This commit is contained in:
Joey Kimsey
2024-12-21 16:26:05 -05:00
parent 0c2fa757dd
commit f8e75e847d
59 changed files with 861 additions and 387 deletions

View File

@ -19,6 +19,8 @@ use TheTempusProject\Classes\AdminController;
use TheTempusProject\Plugins\Members as MemberModel;
use TheTempusProject\Houdini\Classes\Issues;
use TheTempusProject\Bedrock\Functions\Input;
use TheTempusProject\Hermes\Functions\Route as Routes;
use TheTempusProject\Hermes\Functions\Redirect;
class Members extends AdminController {
public function __construct() {
@ -28,13 +30,46 @@ class Members extends AdminController {
}
public function index( $data = null ) {
self::$title = 'Admin - Membership Scripts';
Views::view( 'members.admin.scripts' );
}
public function orphans( $data = null, $id = null ) {
self::$title = 'Admin - Orphaned PRoducts';
if ( $data = 'abandon' && ! empty( $id ) ) {
MemberModel::orphanAbandon( $id );
Redirect::to('admin/members/orphans');
}
$orphans = MemberModel::findOrphans();
Views::view( 'members.admin.orphans', $orphans );
}
public function webhooks( $data = null, $id = null ) {
self::$title = 'Admin - Membership Webhooks';
if ( $data = 'delete' && ! empty( $id ) ) {
MemberModel::webhookRemove( $id );
Redirect::to('admin/members/webhooks');
}
$data = [];
$webhooks = MemberModel::webhookList();
foreach ($webhooks->data as $key => $webhook) {
$hook = new \stdClass;
$hook->id = $webhook->id;
$hook->enabled_events = implode( ', <br>', $webhook->enabled_events );
$hook->status = $webhook->status;
$hook->url = $webhook->url;
$data[] = $hook;
}
Components::set( 'urltouse', Routes::getAddress() );
if ( !Input::exists( 'submit' ) ) {
return Views::view( 'members.admin.webhooks' );
return Views::view( 'members.admin.webhooks', $data );
}
MemberModel::webhookSetup();
Issues::add( 'success', 'Webhooks Generated' );
Issues::add( 'error', 'Now, LEAVE!' );
Redirect::to('admin/members/webhooks');
}
}

View File

@ -70,7 +70,7 @@ class Member extends Controller {
}
try {
$session = self::$stripe->billingPortal->sessions->create([
'customer' => $customer,
'customer' => $customer->stripe_customer,
'return_url' => Routes::getAddress() . 'member/manage',
]);
} catch (\Stripe\Exception\InvalidRequestException $e) {
@ -174,7 +174,7 @@ class Member extends Controller {
Session::flash( 'success', 'We aren\'t currently accepting new members, please check back soon!' );
return Redirect::home();
}
Views::view( 'members.landing1', $product );
Views::view( 'members.landing', $product );
}
public function checkout( $plan = 'monthly' ) {
@ -187,6 +187,19 @@ class Member extends Controller {
Issues::add( 'error', 'no customer' );
return $this->index();
}
$plan = strtolower( $plan );
if ( ! in_array( $plan, ['monthly','yearly','upgrade'] ) ) {
Session::flash( 'error', 'Unknown plan' );
return Redirect::to( 'home/index' );
}
if ( $plan === 'upgrade' ) {
$plan = 'yearly';
$successUrl = Routes::getAddress() . 'member/payment/upgrade?session_id={CHECKOUT_SESSION_ID}';
} else {
$successUrl = Routes::getAddress() . 'member/payment/complete?session_id={CHECKOUT_SESSION_ID}';
}
$stripePrice = $this->findPrice( $plan );
$session = self::$stripe->checkout->sessions->create([
@ -197,7 +210,7 @@ class Member extends Controller {
'quantity' => 1,
]],
'mode' => 'subscription',
'success_url' => Routes::getAddress() . 'member/payment/complete?session_id={CHECKOUT_SESSION_ID}',
'success_url' => $successUrl,
'cancel_url' => Routes::getAddress() . 'member/payment/cancel',
]);
header('Location: ' . $session->url);
@ -206,7 +219,7 @@ class Member extends Controller {
public function payment( $type = '' ) {
$type = strtolower( $type );
if ( ! in_array( $type, ['cancel','complete'] ) ) {
if ( ! in_array( $type, ['cancel','complete','upgrade'] ) ) {
Session::flash( 'error', 'Unknown Payment' );
return Redirect::to( 'home/index' );
}
@ -216,6 +229,11 @@ class Member extends Controller {
return Views::view( 'members.paymentcanceled' );
}
if ( $type == 'upgrade' ) {
self::$title = 'Better Members Area';
return Views::view( 'members.upgradeCompleted' );
}
self::$title = '(almost) Members Area';
Views::view( 'members.paymentcomplete' );
}

View File

@ -27,8 +27,8 @@ class MembershipProducts extends DatabaseModel {
public $databaseMatrix = [
[ 'name', 'varchar', '128' ],
[ 'description', 'text', '' ],
[ 'monthly_price', 'int', '10' ], // must be int value greater than 99 IE $1.00 === 100, $4399.22 === 439922
[ 'yearly_price', 'int', '10' ], // must be int value greater than 99 IE $1.00 === 100, $4399.22 === 439922
[ 'monthly_price', 'int', '10' ], // must be int value greater than 99 IE $1.00 === 100, $4,399.22 === 439922
[ 'yearly_price', 'int', '10' ], // must be int value greater than 99 IE $1.00 === 100, $4,399.22 === 439922
[ 'stripe_product', 'varchar', '64' ], // not-required to create - generated by stripe after
[ 'stripe_price_monthly', 'varchar', '64' ], // not-required to create - generated by stripe after
[ 'stripe_price_yearly', 'varchar', '64' ], // not-required to create - generated by stripe after
@ -166,7 +166,7 @@ class MembershipProducts extends DatabaseModel {
public function updateStripeYearlyPrice( $product, $yearly_price ) {
$stripe->prices->update(
$yearly->id,
$yearly_price,
['lookup_key' => ""]
);
return $this->createStripeYearlyPrice( $product, $yearly_price );
@ -174,7 +174,7 @@ class MembershipProducts extends DatabaseModel {
public function updateStripeMonthlyPrice( $product, $monthly_price ) {
$stripe->prices->update(
$monthly->id,
$monthly_price,
['lookup_key' => ""]
);
return $this->createStripeMonthlyPrice( $product, $monthly_price );
@ -208,7 +208,7 @@ class MembershipProducts extends DatabaseModel {
if ( ! $data->count() ) {
return false;
}
return $data->first();
return $this->filter( $data->first() );
}
public function mainProduct() {

View File

@ -19,6 +19,7 @@ use TheTempusProject\Bedrock\Classes\Config;
use TheTempusProject\Hermes\Functions\Route as Routes;
use TheTempusProject\Models\Memberships;
use TheTempusProject\Models\MembershipProducts as Products;
use TheTempusProject\Canary\Bin\Canary as Debug;
class Members extends Plugin {
public static $stripe;
@ -46,17 +47,17 @@ class Members extends Plugin {
'text' => '<i class="fa fa-fw fa-arrow-down"></i> Memberships',
'url' => [
[
'text' => '<i class="fa fa-fw fa-database"></i> Products',
'text' => '<i class="fa fa-fw fa-barcode"></i> Products',
'url' => '{ROOT_URL}admin/products',
],
[
'text' => '<i class="fa fa-fw fa-database"></i> Subscriptions',
'text' => '<i class="fa fa-fw fa-bag-shopping"></i> Subscriptions',
'url' => '{ROOT_URL}admin/records',
],
// [
// 'text' => '<i class="fa fa-fw fa-database"></i> Invoices',
// 'url' => '{ROOT_URL}admin/invoices',
// ],
[
'text' => '<i class="fa fa-fw fa-code"></i> Scripts',
'url' => '{ROOT_URL}admin/members',
],
],
],
];
@ -116,41 +117,52 @@ class Members extends Plugin {
];
public function __construct( $load = false ) {
if ( ! self::$loaded ) {
App::$userCPlinks[] = (object) self::$userLinks;
self::$loaded = true;
if ( ! self::$loaded && $load ) {
if ( App::$isLoggedIn ) {
App::$isMember = $this->groupHasMemberAccess( App::$activeGroup );
if ( empty( App::$isMember ) ) {
App::$isMember = $this->userHasActiveMembership( App::$activeUser->ID );
}
}
$this->filters[] = [
'name' => 'member',
'find' => '#{MEMBER}(.*?){/MEMBER}#is',
'replace' => ( App::$isMember ? '$1' : '' ),
'enabled' => true,
];
$this->filters[] = [
'name' => 'nonmember',
'find' => '#{NONMEMBER}(.*?){/NONMEMBER}#is',
'replace' => ( App::$isLoggedIn && App::$isMember == false ? '$1' : '' ),
'enabled' => true,
];
$this->filters[] = [
'name' => 'upgrade',
'find' => '#{UPGRADE}(.*?){/UPGRADE}#is',
'replace' => ( App::$isLoggedIn && ( App::$isMember === 'monthly' ) ? '$1' : '' ),
'enabled' => true,
];
}
if ( App::$isLoggedIn ) {
App::$isMember = $this->groupHasMemberAccess( App::$activeGroup );
if ( empty( App::$isMember ) ) {
App::$isMember = $this->userHasActiveMembership( App::$activeUser->ID );
parent::__construct( $load );
if ( $this->checkEnabled() && App::$isLoggedIn ) {
if ( ! self::$loaded && $load ) {
App::$userCPlinks[] = (object) self::$userLinks;
App::$topNavRightDropdown .= '<li><a href="{ROOT_URL}member/manage" class="dropdown-item"><i class="fa fa-fw fa-credit-card"></i> Subscriptions</a></li>';
}
}
$this->filters[] = [
'name' => 'member',
'find' => '#{MEMBER}(.*?){/MEMBER}#is',
'replace' => ( App::$isMember ? '$1' : '' ),
'enabled' => true,
];
$this->filters[] = [
'name' => 'nonmember',
'find' => '#{NONMEMBER}(.*?){/NONMEMBER}#is',
'replace' => ( App::$isLoggedIn && App::$isMember == false ? '$1' : '' ),
'enabled' => true,
];
$this->filters[] = [
'name' => 'upgrade',
'find' => '#{UPGRADE}(.*?){/UPGRADE}#is',
'replace' => ( App::$isLoggedIn && ( App::$isMember === 'monthly' ) ? '$1' : '' ),
'enabled' => true,
];
if ( ! self::$loaded && $load ) {
self::$loaded = true;
}
$api_key = Config::getValue( 'memberships/stripeSecret' );
if ( $api_key == 'sk_xxxxxxxxxxxxxxx' || empty($api_key) ) {
self::$stripe = false;
} else {
self::$stripe = new StripeClient( $api_key );
}
parent::__construct( $load );
}
public function groupHasMemberAccess( $activeGroup ) {
@ -169,6 +181,10 @@ class Members extends Plugin {
$products = new Products;
$product = $products->findByPriceID( $membership->subscription_price_id );
if ( empty( $product ) ) {
Debug::error('Active membership on non-existent product');
return false;
}
if ( $product->stripe_price_monthly == $membership->subscription_price_id ) {
return 'monthly';
}
@ -177,7 +193,6 @@ class Members extends Plugin {
public static function webhookSetup() {
$root = Routes::getAddress();
// $root = "https://stripe.joeykimsey.com/";
$response = self::$stripe->webhookEndpoints->create([
'enabled_events' => self::$webhookEvents,
'url' => $root . 'api/stripe/webhook',
@ -185,13 +200,66 @@ class Members extends Plugin {
return $response;
}
// public static function webhookSetup() {
// $root = Routes::getAddress();
// $root = "https://stripe.joeykimsey.com/";
// $response = self::$stripe->webhookEndpoints->create([
// 'enabled_events' => self::$webhookEvents,
// 'url' => $root . 'api/stripe/webhook',
// ]);
// return $response;
// }
public static function webhookList() {
$response = self::$stripe->webhookEndpoints->all(['limit' => 25]);
return $response;
}
public static function webhookRemove( $id ) {
$response = self::$stripe->webhookEndpoints->delete( $id, []);
return $response;
}
public static function orphanAbandon( $id ) {
$response = self::$stripe->prices->update(
$id,
['lookup_key' => ""]
);
return $response;
}
public static function findOrphans() {
$orphans = [];
// any prices with keys not represented in our local db will show as an orphan
$result = self::$stripe->prices->search([
'query' => 'lookup_key:"membership-monthly"',
]);
$products = new Products;
if ( ! empty( $result->data ) ) {
$product = $products->findByPriceID( $result->data[0]->id );
if ( empty( $product ) ) {
$data = $result->data[0];
$child = new \stdClass;
$child->price_id = $data->id;
$child->product = $data->product;
$child->lookup_key = $data->lookup_key;
$child->amount = $data->unit_amount;
$orphans[] = $child;
}
}
$result = self::$stripe->prices->search([
'query' => 'lookup_key:"membership-yearly"',
]);
if ( ! empty( $result->data ) ) {
$product = $products->findByPriceID( $result->data[0]->id );
if ( empty( $product ) ) {
$data = $result->data[0];
$child = new \stdClass;
$child->price_id = $data->id;
$child->product = $data->product;
$child->lookup_key = $data->lookup_key;
$child->amount = $data->unit_amount;
$orphans[] = $child;
}
}
return $orphans;
}
}

View File

@ -0,0 +1,35 @@
<div class="context-main-bg context-main p-3">
<legend class="text-center">Stripe Webhook Generation</legend>
<hr>
{ADMIN_BREADCRUMBS}
<p>Orphans are stripe prices that have unique lookup_keys used by the membership system, but have no products currently saved.</p>
<table class="table table-striped">
<thead>
<tr>
<th style="width: 10%">price id</th>
<th style="width: 10%">amount</th>
<th style="width: 50%">lookup key</th>
<th style="width: 10%">url</th>
<th style="width: 10%"></th>
</tr>
</thead>
<tbody>
{LOOP}
<tr>
<td>{price_id}</td>
<td>{amount}</td>
<td>{lookup_key}</td>
<td><a href="{ROOT_URL}admin/members/orphans/adopt/{price_id}" class="btn btn-sm btn-success"><i class="fa fa-fw fa-download"></i></a></td>
<td><a href="{ROOT_URL}admin/members/orphans/abandon/{price_id}" class="btn btn-sm btn-danger"><i class="fa fa-fw fa-trash"></i></a></td>
</tr>
{/LOOP}
{ALT}
<tr>
<td class="text-center" colspan="5">
No results to show.
</td>
</tr>
{/ALT}
</tbody>
</table>
</div>

View File

@ -45,7 +45,7 @@
<!-- Submit Button -->
<div class="text-center">
<button type="submit" name="submit" value="submit" class="btn btn-primary btn-lg center-block">Send</button>
<button type="submit" name="submit" value="submit" class="btn btn-primary btn-lg center-block">Save</button>
</div>
</form>
</div>

View File

@ -0,0 +1,13 @@
<div class="context-main-bg context-main p-3">
<legend class="text-center">Membership Scripts</legend>
<hr>
{ADMIN_BREADCRUMBS}
<ul class="list-unstyled">
<li>
<a href="{ROOT_URL}admin/members/webhooks">Webhook Generation</a>
</li>
<li>
<a href="{ROOT_URL}admin/members/orphans">Orphan Products</a>
</li>
</ul>
</div>

View File

@ -1,10 +1,43 @@
<legend>WARNING: Regenerating existing webhooks makes joey sad, don't do iit!</legend>
<form action="" method="post" class="form-horizontal">
<div class="form-group">
<label for="submit" class="col-lg-3 control-label"></label>
<div class="col-lg-3">
<button name="submit" value="submit" type="submit" class="btn btn-lg btn-primary center-block ">Submit</button>
</div>
<div class="context-main-bg context-main p-3">
<legend class="text-center">Stripe Webhook Generation</legend>
<hr>
{ADMIN_BREADCRUMBS}
<table class="table table-striped">
<thead>
<tr>
<th style="width: 10%">id</th>
<th style="width: 10%">status</th>
<th style="width: 50%">enabled_events</th>
<th style="width: 10%">url</th>
<th style="width: 10%"></th>
</tr>
</thead>
<tbody>
{LOOP}
<tr>
<td>{id}</td>
<td>{status}</td>
<td>{enabled_events}</td>
<td>{url}</td>
<td><a href="{ROOT_URL}admin/members/webhooks/delete/{ID}" class="btn btn-sm btn-danger"><i class="fa fa-fw fa-trash"></i></a></td>
</tr>
{/LOOP}
{ALT}
<tr>
<td class="text-center" colspan="5">
No results to show.
</td>
</tr>
{/ALT}
</tbody>
</table>
<div class="text-center">
<h5>WARNING: Regenerating existing webhooks makes joey sad, don't do iit!</h5>
<p>The new webhooks will be generated using the base url: <strong>{urltouse}</strong></p>
<form action="" method="post" class="form-horizontal">
<div class="form-group">
<button name="submit" value="submit" type="submit" class="btn btn-lg btn-danger">re-generate</button>
</div>
</form>
</div>
</form>
</div>

View File

@ -1,21 +1,20 @@
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2 text-center">
<h2>Are You Sure You Want to Cancel?</h2>
<div class="container py-4 context-main-bg my-4">
<h2 class="text-center">Are You Sure You Want to Cancel?</h2>
<hr>
<div class="text-center">
<p class="lead">
Cancelling your subscription means you'll miss out on exclusive features, updates, and benefits.
Cancelling your subscription means you'll miss out on exclusive features, updates, and benefits.
</p>
<p>
Consider staying to continue enjoying the full experience of our service.
Consider staying to continue enjoying the full experience of our service.
</p>
<div class="row">
<div class="col-md-6">
<a href="{ROOT_URL}member/cancelconfirm/{cancelid}" class="btn btn-lg btn-danger btn-block">Cancel Subscription</a>
</div>
<div class="col-md-6">
<a href="{ROOT_URL}member/manage" class="btn btn-lg btn-primary btn-block">Go Back</a>
</div>
<div class="col-md-3 offset-3">
<a href="{ROOT_URL}member/cancelconfirm/{cancelid}" class="btn btn-lg btn-outline-danger btn-block">Cancel Subscription</a>
</div>
<div class="col-md-3">
<a href="{ROOT_URL}member/manage" class="btn btn-lg btn-primary btn-block atb-green-bg">Go Back</a>
</div>
</div>
</div>
</div>
</div>
</div>

View File

@ -1,4 +1,3 @@
<!-- Compare plans -->
<div class="table-responsive pricing-container container pb-4" id="compare">
<h1 class="display-6 text-center my-4">Compare plans</h1>
@ -31,7 +30,7 @@
<td><i class="fa fa-fw fa-check atb-green"></i></td>
</tr>
<tr>
<th scope="row" class="text-start">Share bookmarks abd folders</th>
<th scope="row" class="text-start">Share bookmarks and folders</th>
<td><i class="fa fa-fw fa-check"></i></td>
<td><i class="fa fa-fw fa-check atb-green"></i></td>
<td><i class="fa fa-fw fa-check atb-green"></i></td>
@ -88,9 +87,6 @@
<li>Access from any device</li>
<li>Share access with anyone</li>
</ul>
<a href="/register" class="mt-auto w-100 btn btn-lg atb-green-outline">
Sign-Up for Free
</a>
</div>
</div>
</div>
@ -100,7 +96,7 @@
<h4 class="my-0 fw-normal">Monthly</h4>
</div>
<div class="card-body d-flex flex-column">
<h1 class="card-title pricing-card-title">&#36;4.99<small class="text-muted fw-light">/month</small></h1>
<h1 class="card-title pricing-card-title">{prettyPriceMonthly}<small class="text-muted fw-light">/month</small></h1>
<ul class="list-unstyled mt-3 mb-4">
<li>Import/Export Features</li>
<li>Integration with TempusTools App (WIP)</li>
@ -108,7 +104,7 @@
<li>Direct control of Feature Development</li>
<li>Early Access to new features</li>
</ul>
<a href="/member/signup/monthly" class="mt-auto w-100 btn btn-lg atb-green-bg">
<a href="/member/checkout/monthly" class="mt-auto w-100 btn btn-lg atb-green-bg">
Get started
</a>
</div>
@ -120,11 +116,11 @@
<h4 class="my-0 fw-normal">Yearly</h4>
</div>
<div class="card-body d-flex flex-column">
<h1 class="card-title pricing-card-title">&#36;19.99<small class="text-muted fw-light">/year</small></h1>
<h1 class="card-title pricing-card-title">{prettyPriceYearly}<small class="text-muted fw-light">/year</small></h1>
<ul class="list-unstyled mt-3 mb-4">
<li>Its cheaper if you like the product</li>
</ul>
<a href="/member/signup/yearly" class="mt-auto w-100 btn btn-lg atb-green-bg">
<a href="/member/checkout/yearly" class="mt-auto w-100 btn btn-lg atb-green-bg">
Get started
</a>
</div>

View File

@ -1,7 +1,8 @@
<div class="container py-4">
<div class="container py-4 context-main-bg my-4">
<h3 class="mb-4 text-center">Manage Memberships</h3>
<hr>
<div class="row justify-content-center">
<div class="col-md-8">
<legend>Memberships</legend>
<table class="table text-center context-main">
<thead>
<tr>
@ -23,13 +24,13 @@
<td>{DTC=date}{current_period_start}{/DTC}</td>
<td>{DTC=date}{current_period_end}{/DTC}</td>
<td>
<a href="{ROOT_URL}member/pause/{ID}" class="btn btn-sm btn-primary">
<a href="{ROOT_URL}member/pause/{ID}" class="btn btn-sm btn-outline-warning">
<i class="fa fa-fw fa-pause"></i>
</a>
</td>
<td>
<a href="{ROOT_URL}member/cancel/{ID}" class="btn btn-sm btn-danger">
<i class="fa fa-fw fa-trash"></i>
<a href="{ROOT_URL}member/cancel/{ID}" class="btn btn-sm btn-outline-danger">
<i class="fa fa-fw fa-ban"></i>
</a>
</td>
</tr>
@ -43,7 +44,7 @@
{/ALT}
</tbody>
</table>
<a href="{ROOT_URL}member/managepayment" class="btn btn-sm btn-primary">
<a href="{ROOT_URL}member/managepayment" class="btn btn-sm btn-primary atb-green-bg">
Manage Payment Method
</a>
</div>

View File

@ -11,7 +11,8 @@
Right now, this entire system was built and managed by myself. I have used my own version of this for years, but translating it to a publicly available product is not a 1-to-1 job. There may be bugs or issues encountered while you use the product. I can't guarantee a fix for every need in every case immediately, but I do actively keep track of bugs and work hard to ensure everyone has a great experience using the app.
</p>
<div class="text-center mt-4 pb-4">
{loggedin}<a href="/bugreport" class="btn btn-primary btn-lg px-5 atb-green-bg">Report a Bug</a>{/loggedin}
{loggedin}<a href="/bugreport" class="btn btn-outline-secondary btn-lg px-5 ms-3 atb-green-outline">Report a Bug</a>{/loggedin}
<a href="/member/manage" class="btn btn-outline-secondary btn-lg px-5 ms-3 atb-green-bg">Manage Membership</a>
<a href="/contact" class="btn btn-outline-secondary btn-lg px-5 ms-3 atb-green-outline">Contact Us</a>
</div>
</div>

View File

@ -1,21 +1,20 @@
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2 text-center">
<h2>Are You Sure You Want to Pause?</h2>
<div class="container py-4 context-main-bg my-4">
<h2 class="text-center">Are You Sure You Want to Pause?</h2>
<hr>
<div class="text-center">
<p class="lead">
Pausing your subscription means you'll miss out on exclusive features, updates, and benefits.
Pausing your subscription means you'll miss out on exclusive features, updates, and benefits.
</p>
<p>
Consider staying to continue enjoying the full experience of our service.
Consider staying to continue enjoying the full experience of our service.
</p>
<div class="row">
<div class="col-md-6">
<a href="{ROOT_URL}member/pauseconfirm/{pauseid}" class="btn btn-lg btn-danger btn-block">Pause Subscription</a>
</div>
<div class="col-md-6">
<a href="{ROOT_URL}member/manage" class="btn btn-lg btn-primary btn-block">Go Back</a>
</div>
<div class="col-md-3 offset-3">
<a href="{ROOT_URL}member/pauseconfirm/{pauseid}" class="btn btn-lg btn-outline-danger btn-block">Pause Subscription</a>
</div>
<div class="col-md-3">
<a href="{ROOT_URL}member/manage" class="btn btn-lg btn-primary btn-block atb-green-bg">Go Back</a>
</div>
</div>
</div>
</div>
</div>
</div>

View File

@ -1,4 +1,14 @@
<div class="jumbotron text-center">
<h1>Take your time, its not a sprint, its a marathon.</h1>
<p>Its ok, no-one wants to checkout too fast, its embarrassing.</p>
<div class="col-8 mx-auto p-4 rounded shadow-sm context-main-bg my-4">
<h2 class="text-center atb-green mb-4">Almost there!</h2>
<p class="lead">
Take your time, its not a sprint, its a marathon.
Nno-one wants to checkout too fast, its embarrassing.
</p>
<p class="text-muted">
If you think this is a tool that you could really use and can't afford it, use the contact form below and tell me why you need it.
</p>
<div class="text-center mt-4 pb-4">
{loggedin}<a href="/bugreport" class="btn btn-primary btn-lg px-5 atb-green-bg">Report a Bug</a>{/loggedin}
<a href="/contact" class="btn btn-outline-secondary btn-lg px-5 ms-3 atb-green-outline">Contact Us</a>
</div>
</div>

View File

@ -1,5 +1,14 @@
<div class="jumbotron text-center">
<h1>Thanks for joining!</h1>
<p>Its people like you who keep the pixels on around here.
Its people like me who tell you life is unfair and it could take up to an hour for your membership to activate.</p>
<div class="col-8 mx-auto p-4 rounded shadow-sm context-main-bg my-4">
<h2 class="text-center atb-green mb-4">Thanks for joining!</h2>
<p class="lead">
Its people like you who keep the pixels on around here.
Its people like me who tell people like you that unfortunately, it could take up to an hour for your membership to activate.
</p>
<p class="text-muted">
With that said, its usually instant, and if its taking too long, just reach out to us via the contact form.
</p>
<div class="text-center mt-4 pb-4">
{loggedin}<a href="/bugreport" class="btn btn-primary btn-lg px-5 atb-green-bg">Report a Bug</a>{/loggedin}
<a href="/contact" class="btn btn-outline-secondary btn-lg px-5 ms-3 atb-green-outline">Contact Us</a>
</div>
</div>

View File

@ -1,6 +1,6 @@
<div class="col-8 mx-auto p-4 rounded shadow-sm mb-5 context-main-bg mt-4 text-center">
<div class="row">
<h2 class="text-primary mb-4">Upgrade to a Yearly Plan</h2>
<h2 class="mb-4 atb-green">Upgrade to a Yearly Plan</h2>
<p class="lead">
Save more and enjoy uninterrupted access to all features with our yearly plan!
</p>
@ -10,12 +10,12 @@
</p>
<div class="row">
<div class="col-md-6">
<a href="/member/checkout/yearly" class="btn btn-lg btn-success btn-block">
<a href="/member/checkout/upgrade" class="btn btn-lg btn-block atb-green-bg">
Upgrade to Yearly
</a>
</div>
<div class="col-md-6">
<a href="/member/upgrade" class="btn btn-lg btn-primary btn-block">
<a href="/member" class="btn btn-lg btn-block atb-green-outline">
Stay on Monthly
</a>
</div>

View File

@ -0,0 +1,13 @@
<div class="col-8 mx-auto p-4 rounded shadow-sm context-main-bg my-4">
<h2 class="text-center atb-green mb-4">Thanks for the vote of confidence!</h2>
<p class="lead">
While you were more profitable as a monthly user, I do appreciate the vote of confidence it takes to commit to 4x the cost at once.
</p>
<p class="text-muted">
There really is no more benefit than you saving money, so enjoy the features you have already come to know and enjoy.
</p>
<div class="text-center mt-4 pb-4">
{loggedin}<a href="/bugreport" class="btn btn-primary btn-lg px-5 atb-green-bg">Report a Bug</a>{/loggedin}
<a href="/contact" class="btn btn-outline-secondary btn-lg px-5 ms-3 atb-green-outline">Contact Us</a>
</div>
</div>