Skip to content

Commit

Permalink
Merge pull request #10 from fleetbase/dev-v0.0.11
Browse files Browse the repository at this point in the history
enforce stripe onboard for users to monetize extensions
  • Loading branch information
roncodes authored Jul 31, 2024
2 parents 9bdedfd + 4baf6ab commit 118af76
Show file tree
Hide file tree
Showing 10 changed files with 152 additions and 97 deletions.
106 changes: 63 additions & 43 deletions addon/components/extension-monetize-form.hbs
Original file line number Diff line number Diff line change
@@ -1,55 +1,75 @@
<ContentPanel @title={{t "registry-bridge.developers.extensions.extension-form.extension-payment-details"}} @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-800">
<InputGroup @wrapperClass={{unless @extension.payment_required "mb-0i"}}>
<Toggle
@isToggled={{@extension.payment_required}}
@onToggle={{fn (mut @extension.payment_required)}}
@label={{t "registry-bridge.developers.extensions.extension-form.extension-payment-required"}}
@helpText={{t "registry-bridge.developers.extensions.extension-form.extension-payment-required-help-text"}}
/>
</InputGroup>
{{#if @extension.payment_required}}
{{!-- <InputGroup>
{{#if this.lookupStripeConnectAccount.isRunning}}
<div class="flex items-center justify-center flex-1 p-4">
<Spinner @loadingMessage="Loading monetization settings..." @loadingMessageClass="ml-2 text-black dark:text-white" @wrapperClass="flex flex-row items-center" />
</div>
{{else}}
{{#if this.hasStripeConnectAccount}}
<InputGroup @wrapperClass={{unless @extension.payment_required "mb-0i"}}>
<Toggle
@isToggled={{@extension.payment_required}}
@onToggle={{fn (mut @extension.payment_required)}}
@label={{t "registry-bridge.developers.extensions.extension-form.extension-payment-required"}}
@helpText={{t "registry-bridge.developers.extensions.extension-form.extension-payment-required-help-text"}}
/>
</InputGroup>
{{#if @extension.payment_required}}
{{!-- <InputGroup>
<Toggle
@isToggled={{@extension.subscription_required}}
@onToggle={{fn (mut @extension.subscription_required)}}
@label={{t "registry-bridge.developers.extensions.extension-form.extension-subscription-required"}}
@helpText={{t "registry-bridge.developers.extensions.extension-form.extension-subscription-required-help-text"}}
/>
</InputGroup> --}}
{{#if @extension.subscription_required}}
<InputGroup
@name={{t "registry-bridge.developers.extensions.extension-form.extension-subscription-billing-period"}}
@helpText={{t "registry-bridge.developers.extensions.extension-form.extension-subscription-billing-period-help-text"}}
>
<Select
@value={{@extension.subscription_billing_period}}
@options={{this.billingPeriodOptions}}
@onSelect={{fn (mut @extension.subscription_billing_period)}}
@placeholder={{t "registry-bridge.developers.extensions.extension-form.extension-subscription-billing-period-placeholder"}}
class="w-full"
/>
</InputGroup>
<InputGroup
@name={{t "registry-bridge.developers.extensions.extension-form.extension-subscription-amount"}}
@helpText={{t "registry-bridge.developers.extensions.extension-form.extension-subscription-amount-help-text"}}
@wrapperClass="mb-0i"
>
<MoneyInput @value={{@extension.subscription_amount}} @currency="USD" />
</InputGroup>
{{#if @extension.subscription_required}}
<InputGroup
@name={{t "registry-bridge.developers.extensions.extension-form.extension-subscription-billing-period"}}
@helpText={{t "registry-bridge.developers.extensions.extension-form.extension-subscription-billing-period-help-text"}}
>
<Select
@value={{@extension.subscription_billing_period}}
@options={{this.billingPeriodOptions}}
@onSelect={{fn (mut @extension.subscription_billing_period)}}
@placeholder={{t "registry-bridge.developers.extensions.extension-form.extension-subscription-billing-period-placeholder"}}
class="w-full"
/>
</InputGroup>
<InputGroup
@name={{t "registry-bridge.developers.extensions.extension-form.extension-subscription-amount"}}
@helpText={{t "registry-bridge.developers.extensions.extension-form.extension-subscription-amount-help-text"}}
@wrapperClass="mb-0i"
>
<MoneyInput @value={{@extension.subscription_amount}} @currency="USD" />
</InputGroup>
{{else}}
<div class="grid grid-cols-1 lg:grid-cols-2 gap-2">
<InputGroup
@name={{t "registry-bridge.developers.extensions.extension-form.extension-price"}}
@helpText={{t "registry-bridge.developers.extensions.extension-form.extension-price-help-text"}}
>
<MoneyInput @value={{@extension.price}} @currency="USD" />
</InputGroup>
<InputGroup
@name={{t "registry-bridge.developers.extensions.extension-form.extension-sale-price"}}
@helpText={{t "registry-bridge.developers.extensions.extension-form.extension-sale-price-help-text"}}
>
<MoneyInput @value={{@extension.sale_price}} @currency="USD" />
</InputGroup>
</div>
{{/if}}
{{/if}}
{{else}}
<div class="grid grid-cols-1 lg:grid-cols-2 gap-2">
<InputGroup
@name={{t "registry-bridge.developers.extensions.extension-form.extension-price"}}
@helpText={{t "registry-bridge.developers.extensions.extension-form.extension-price-help-text"}}
>
<MoneyInput @value={{@extension.price}} @currency="USD" />
</InputGroup>
<InputGroup
@name={{t "registry-bridge.developers.extensions.extension-form.extension-sale-price"}}
@helpText={{t "registry-bridge.developers.extensions.extension-form.extension-sale-price-help-text"}}
>
<MoneyInput @value={{@extension.sale_price}} @currency="USD" />
</InputGroup>
<div class="container">
<div class="max-w-3xl mx-auto mt-4">
<div class="content">
<div class="flex flex-col items-center justify-center">
<h1 class="text-lg font-semibold mb-1">Your account is not setup to accept payments yet.</h1>
<p class="text-sm mb-2">To accept payments for extensions, you must complete the onboard process via Stripe.</p>
<Button @type="primary" @size="lg" @text="Start payments onboard" @onClick={{transition-to "developers.payments.onboard"}} />
</div>
</div>
</div>
</div>
{{/if}}
{{/if}}
Expand Down
18 changes: 18 additions & 0 deletions addon/components/extension-monetize-form.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,25 @@
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { inject as service } from '@ember/service';
import { task } from 'ember-concurrency';

export default class ExtensionMonetizeFormComponent extends Component {
@service fetch;
@tracked subscriptionModelOptions = ['flat_rate', 'tiered', 'usage'];
@tracked billingPeriodOptions = ['daily', 'weekly', 'monthly', 'quarterly', 'yearly'];
@tracked hasStripeConnectAccount = false;

constructor() {
super(...arguments);
this.lookupStripeConnectAccount.perform();
}

@task *lookupStripeConnectAccount() {
try {
const { hasStripeConnectAccount } = yield this.fetch.get('payments/has-stripe-connect-account', {}, { namespace: '~registry/v1' });
this.hasStripeConnectAccount = hasStripeConnectAccount;
} catch (error) {
this.hasStripeConnectAccount = false;
}
}
}
6 changes: 1 addition & 5 deletions addon/controllers/developers/extensions/edit/monetize.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
import Controller from '@ember/controller';
import { tracked } from '@glimmer/tracking';

export default class DevelopersExtensionsEditMonetizeController extends Controller {
@tracked subscriptionModelOptions = ['flat_rate', 'tiered', 'usage'];
@tracked billingPeriodOptions = ['daily', 'weekly', 'monthly', 'quarterly', 'yearly'];
}
export default class DevelopersExtensionsEditMonetizeController extends Controller {}
12 changes: 12 additions & 0 deletions addon/controllers/developers/payments/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import Controller from '@ember/controller';
import { tracked } from '@glimmer/tracking';
import { inject as service } from '@ember/service';
import { task } from 'ember-concurrency';

export default class DevelopersPaymentsIndexController extends Controller {
@service fetch;
@tracked hasStripeConnectAccount = true;
@tracked table;
@tracked page = 1;
Expand Down Expand Up @@ -37,4 +40,13 @@ export default class DevelopersPaymentsIndexController extends Controller {
width: '20%',
},
];

@task *lookupStripeConnectAccount() {
try {
const { hasStripeConnectAccount } = yield this.fetch.get('payments/has-stripe-connect-account', {}, { namespace: '~registry/v1' });
this.hasStripeConnectAccount = hasStripeConnectAccount;
} catch (error) {
this.hasStripeConnectAccount = false;
}
}
}
9 changes: 2 additions & 7 deletions addon/routes/developers/payments/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,7 @@ export default class DevelopersPaymentsIndexRoute extends Route {
return this.fetch.get('payments/author-received', {}, { namespace: '~registry/v1' });
}

async setupController(controller) {
try {
const { hasStripeConnectAccount } = await this.fetch.get('payments/has-stripe-connect-account', {}, { namespace: '~registry/v1' });
controller.hasStripeConnectAccount = hasStripeConnectAccount;
} catch (error) {
controller.hasStripeConnectAccount = false;
}
setupController(controller) {
controller.lookupStripeConnectAccount.perform();
}
}
56 changes: 32 additions & 24 deletions addon/templates/developers/payments/index.hbs
Original file line number Diff line number Diff line change
@@ -1,34 +1,42 @@
<Layout::Section::Header @title="Payments">
<div class="flex flex-row space-x-1">
<span class="text-sm text-black dark:text-white font-bold">Total Amount:</span>
<span class="text-sm text-black dark:text-white">{{format-currency @model.total_amount "USD"}}</span>
</div>
{{#if this.hasStripeConnectAccount}}
<div class="flex flex-row space-x-1">
<span class="text-sm text-black dark:text-white font-bold">Total Amount:</span>
<span class="text-sm text-black dark:text-white">{{format-currency @model.total_amount "USD"}}</span>
</div>
{{/if}}
</Layout::Section::Header>

<Layout::Section::Body class="overflow-y-scroll h-full">
{{#if this.hasStripeConnectAccount}}
<Table
@rows={{@model.data}}
@columns={{this.columns}}
@selectable={{false}}
@canSelectAll={{false}}
@onSetup={{fn (mut this.table)}}
@pagination={{true}}
@paginationMeta={{@model.meta}}
@page={{this.page}}
@onPageChange={{fn (mut this.page)}}
/>
{{#if this.lookupStripeConnectAccount.isRunning}}
<div class="flex items-center justify-center flex-1 p-4">
<Spinner @loadingMessage="Loading monetization settings..." @loadingMessageClass="ml-2 text-black dark:text-white" @wrapperClass="flex flex-row items-center" />
</div>
{{else}}
<div class="container">
<div class="max-w-3xl mx-auto mt-4">
<div class="content">
<div class="flex flex-col items-center justify-center">
<h1 class="text-lg font-semibold mb-1">Your account is not setup to accept payments yet.</h1>
<p class="text-sm mb-2">To accept payments for extensions, you must complete the onboard process via Stripe.</p>
<Button @type="primary" @size="lg" @text="Start payments onboard" @onClick={{transition-to "developers.payments.onboard"}} />
{{#if this.hasStripeConnectAccount}}
<Table
@rows={{@model.data}}
@columns={{this.columns}}
@selectable={{false}}
@canSelectAll={{false}}
@onSetup={{fn (mut this.table)}}
@pagination={{true}}
@paginationMeta={{@model.meta}}
@page={{this.page}}
@onPageChange={{fn (mut this.page)}}
/>
{{else}}
<div class="container">
<div class="max-w-3xl mx-auto mt-4">
<div class="content">
<div class="flex flex-col items-center justify-center">
<h1 class="text-lg font-semibold mb-1">Your account is not setup to accept payments yet.</h1>
<p class="text-sm mb-2">To accept payments for extensions, you must complete the onboard process via Stripe.</p>
<Button @type="primary" @size="lg" @text="Start payments onboard" @onClick={{transition-to "developers.payments.onboard"}} />
</div>
</div>
</div>
</div>
</div>
{{/if}}
{{/if}}
</Layout::Section::Body>
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "fleetbase/registry-bridge",
"version": "0.0.10",
"version": "0.0.11",
"description": "Internal Bridge between Fleetbase API and Extensions Registry",
"keywords": [
"fleetbase-extension",
Expand Down
2 changes: 1 addition & 1 deletion extension.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "Registry Bridge",
"version": "0.0.10",
"version": "0.0.11",
"description": "Internal Bridge between Fleetbase API and Extensions Registry",
"repository": "https://github.com/fleetbase/registry-bridge",
"license": "AGPL-3.0-or-later",
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@fleetbase/registry-bridge-engine",
"version": "0.0.10",
"version": "0.0.11",
"description": "Internal Bridge between Fleetbase API and Extensions Registry",
"fleetbase": {
"route": "extensions"
Expand Down
36 changes: 21 additions & 15 deletions server/src/Http/Controllers/Internal/v1/RegistryAuthController.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,21 +40,27 @@ public function composerAuthentication(Request $request)
return response()->error('Invalid registry token provided for authentication.', 401);
}

// Fetch unauthorized extensions
$unauthorizedExtensions = RegistryExtension::where('payment_required', true)
->whereDoesntHave('purchases', function ($query) use ($registryUser) {
$query->where('company_uuid', $registryUser->company_uuid);
})
->whereHas('currentBundle')
->with('currentBundle')
->get();

// Map to unathorized to package names
$unauthorizedExtensionNames = $unauthorizedExtensions->map(function ($registryExtension) {
$composerJson = $registryExtension->currentBundle->meta['composer.json'] ?? [];

return $composerJson['name'] ?? null;
})->filter()->values();
// Init unauthorized extensions
$unauthorizedExtensionNames = collect();

// Unless admin the registry user is only allowed access to their extensions
if ($registryUser->isNotAdmin()) {
// Fetch unauthorized extensions
$unauthorizedExtensions = RegistryExtension::where('payment_required', true)
->whereDoesntHave('purchases', function ($query) use ($registryUser) {
$query->where('company_uuid', $registryUser->company_uuid);
})
->whereHas('currentBundle')
->with('currentBundle')
->get();

// Map to unathorized to package names
$unauthorizedExtensionNames = $unauthorizedExtensions->map(function ($registryExtension) {
$composerJson = $registryExtension->currentBundle->meta['composer.json'] ?? [];

return $composerJson['name'] ?? null;
})->filter()->values();
}

// Done
return response()->json([
Expand Down

0 comments on commit 118af76

Please sign in to comment.