From cc469a50ee596863051a952e5926fea151a3e0b9 Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Wed, 8 Feb 2023 00:38:57 +0000 Subject: [PATCH 01/10] initiate stripe integration --- package-lock.json | 6 ++++ package.json | 1 + .../settings/+page.svelte | 30 +++++++++++++++++++ 3 files changed, 37 insertions(+) diff --git a/package-lock.json b/package-lock.json index 071882cfc9..19dd58fdb0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,7 @@ "@popperjs/core": "^2.11.6", "@sentry/svelte": "^7.36.0", "@sentry/tracing": "^7.36.0", + "@stripe/stripe-js": "^1.46.0", "analytics": "^0.8.1", "echarts": "^5.4.1", "pretty-bytes": "^6.1.0", @@ -1927,6 +1928,11 @@ "@sinonjs/commons": "^2.0.0" } }, + "node_modules/@stripe/stripe-js": { + "version": "1.46.0", + "resolved": "https://registry.npmjs.org/@stripe/stripe-js/-/stripe-js-1.46.0.tgz", + "integrity": "sha512-dkm0zCEoRLu5rTnsIgwDf/QG2DKcalOT2dk1IVgMySOHWTChLyOvQwMYhEduGgLvyYWTwNhAUV4WOLPQvjwLwA==" + }, "node_modules/@sveltejs/adapter-static": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/@sveltejs/adapter-static/-/adapter-static-1.0.6.tgz", diff --git a/package.json b/package.json index 02996ed909..24a5109034 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "@popperjs/core": "^2.11.6", "@sentry/svelte": "^7.36.0", "@sentry/tracing": "^7.36.0", + "@stripe/stripe-js": "^1.46.0", "analytics": "^0.8.1", "echarts": "^5.4.1", "pretty-bytes": "^6.1.0", diff --git a/src/routes/console/organization-[organization]/settings/+page.svelte b/src/routes/console/organization-[organization]/settings/+page.svelte index 13aa5d1c5f..bdadf6f2a8 100644 --- a/src/routes/console/organization-[organization]/settings/+page.svelte +++ b/src/routes/console/organization-[organization]/settings/+page.svelte @@ -10,13 +10,33 @@ import { onMount } from 'svelte'; import Delete from '../deleteOrganization.svelte'; import { trackEvent } from '$lib/actions/analytics'; + import { loadStripe } from '@stripe/stripe-js'; let name: string; let showDelete = false; + let stripe: any; + const options = { + clientSecret: '{{CLIENT_SECRET}}', + // Fully customizable with appearance API. + appearance: {/*...*/}, + }; + + onMount(() => { name = $organization.name; + initStripe(); }); + + async function initStripe() { + stripe = await loadStripe(import.meta.env.VITE_STRIPE_PUBLISHABLE_KEY?.toString()); + // Set up Stripe.js and Elements to use in checkout form, passing the client secret obtained in step 3 + const elements = stripe.elements(options); + + // Create and mount the Payment Element + const paymentElement = elements.create('payment'); + paymentElement.mount('#payment-element'); + } async function updateName() { try { @@ -61,6 +81,16 @@ +
+
+ +
+ +
+ +
+
+
Delete Organization From a85b105505874dcdc632ef48db3206c5456b8017 Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Wed, 8 Feb 2023 01:57:15 +0000 Subject: [PATCH 02/10] cloud SDK with billing --- src/lib/stores/billing.ts | 16 ++++++++++++++++ src/lib/stores/sdk.ts | 7 ++++++- 2 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 src/lib/stores/billing.ts diff --git a/src/lib/stores/billing.ts b/src/lib/stores/billing.ts new file mode 100644 index 0000000000..5aaf0fbbc7 --- /dev/null +++ b/src/lib/stores/billing.ts @@ -0,0 +1,16 @@ +import type { Client } from "@aw-labs/appwrite-console"; + +export class Billing { + client: Client; + + constructor(client: Client) { + this.client = client; + } + + async createPaymentMethod(teamId: string) { + const path = `/teams/${teamId}/payment-methods`; + const params = {}; + const uri = new URL(this.client.config.endpoint + path); + this.client.call('POST', uri, {}, params); + } +} \ No newline at end of file diff --git a/src/lib/stores/sdk.ts b/src/lib/stores/sdk.ts index cffc23deca..3625958a4f 100644 --- a/src/lib/stores/sdk.ts +++ b/src/lib/stores/sdk.ts @@ -48,4 +48,9 @@ const sdkForProject = { users: new Users(clientProject) }; -export { sdkForConsole, sdkForProject, setProject }; +const cloudSdk = { + ...sdkForConsole, + billing: new Billing(clientConsole), +} + +export { sdkForConsole, sdkForProject, cloudSdk, setProject }; From 0b8f2fde2ee574d7d4c64021f64bc2718697ea25 Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Wed, 8 Feb 2023 14:14:44 +0545 Subject: [PATCH 03/10] update to get client secret and create form --- src/lib/stores/billing.ts | 13 +++-- src/lib/stores/sdk.ts | 6 ++- .../settings/+page.svelte | 53 +++++++++++++------ 3 files changed, 50 insertions(+), 22 deletions(-) diff --git a/src/lib/stores/billing.ts b/src/lib/stores/billing.ts index 5aaf0fbbc7..0ecfcff2ab 100644 --- a/src/lib/stores/billing.ts +++ b/src/lib/stores/billing.ts @@ -1,4 +1,4 @@ -import type { Client } from "@aw-labs/appwrite-console"; +import type { Client } from '@aw-labs/appwrite-console'; export class Billing { client: Client; @@ -11,6 +11,13 @@ export class Billing { const path = `/teams/${teamId}/payment-methods`; const params = {}; const uri = new URL(this.client.config.endpoint + path); - this.client.call('POST', uri, {}, params); + return await this.client.call( + 'POST', + uri, + { + 'Content-Type': 'application/json' + }, + params + ); } -} \ No newline at end of file +} diff --git a/src/lib/stores/sdk.ts b/src/lib/stores/sdk.ts index 3625958a4f..870cade528 100644 --- a/src/lib/stores/sdk.ts +++ b/src/lib/stores/sdk.ts @@ -12,6 +12,8 @@ import { Users } from '@aw-labs/appwrite-console'; +import { Billing } from './billing'; + const endpoint = import.meta.env.VITE_APPWRITE_ENDPOINT?.toString() ?? `${window?.location?.origin}/v1`; const clientConsole = new Client(); @@ -50,7 +52,7 @@ const sdkForProject = { const cloudSdk = { ...sdkForConsole, - billing: new Billing(clientConsole), -} + billing: new Billing(clientConsole) +}; export { sdkForConsole, sdkForProject, cloudSdk, setProject }; diff --git a/src/routes/console/organization-[organization]/settings/+page.svelte b/src/routes/console/organization-[organization]/settings/+page.svelte index bdadf6f2a8..22f927f7b7 100644 --- a/src/routes/console/organization-[organization]/settings/+page.svelte +++ b/src/routes/console/organization-[organization]/settings/+page.svelte @@ -3,7 +3,7 @@ import { InputText, Form, Button } from '$lib/elements/forms'; import { Container } from '$lib/layout'; import { addNotification } from '$lib/stores/notifications'; - import { sdkForConsole } from '$lib/stores/sdk'; + import { cloudSdk, sdkForConsole } from '$lib/stores/sdk'; import { members, organization } from '$lib/stores/organization'; import { invalidate } from '$app/navigation'; import { Dependencies } from '$lib/constants'; @@ -16,26 +16,39 @@ let showDelete = false; let stripe: any; - const options = { - clientSecret: '{{CLIENT_SECRET}}', - // Fully customizable with appearance API. - appearance: {/*...*/}, - }; - - onMount(() => { name = $organization.name; initStripe(); }); - + async function initStripe() { stripe = await loadStripe(import.meta.env.VITE_STRIPE_PUBLISHABLE_KEY?.toString()); - // Set up Stripe.js and Elements to use in checkout form, passing the client secret obtained in step 3 - const elements = stripe.elements(options); - - // Create and mount the Payment Element - const paymentElement = elements.create('payment'); - paymentElement.mount('#payment-element'); + } + + async function createPaymentMethod(event) { + event.preventDefault(); + + try { + const paymentMethod = await cloudSdk.billing.createPaymentMethod($organization.$id); + const options = { + clientSecret: paymentMethod.clientSecret, + // Fully customizable with appearance API. + appearance: { + /*...*/ + } + }; + // Set up Stripe.js and Elements to use in checkout form, passing the client secret obtained in step 3 + const elements = stripe.elements(options); + + // Create and mount the Payment Element + const paymentElement = elements.create('payment'); + paymentElement.mount('#payment-element'); + } catch (error) { + addNotification({ + message: error.toString(), + type: 'error' + }); + } } async function updateName() { @@ -82,12 +95,18 @@
+ + Create Payment Method + + + +
- +
- +
From e571886021ff50658a41ba1d240db4624138b421 Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Wed, 8 Feb 2023 14:40:51 +0545 Subject: [PATCH 04/10] save payment details --- .../settings/+page.svelte | 40 ++++++++++++++----- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/src/routes/console/organization-[organization]/settings/+page.svelte b/src/routes/console/organization-[organization]/settings/+page.svelte index 22f927f7b7..dc7e255194 100644 --- a/src/routes/console/organization-[organization]/settings/+page.svelte +++ b/src/routes/console/organization-[organization]/settings/+page.svelte @@ -15,6 +15,7 @@ let name: string; let showDelete = false; let stripe: any; + let elements: any; onMount(() => { name = $organization.name; @@ -38,7 +39,7 @@ } }; // Set up Stripe.js and Elements to use in checkout form, passing the client secret obtained in step 3 - const elements = stripe.elements(options); + elements = stripe.elements(options); // Create and mount the Payment Element const paymentElement = elements.create('payment'); @@ -51,6 +52,29 @@ } } + async function savePaymentDetails(event) { + event.preventDefault(); + + const { error } = await stripe.confirmSetup({ + //`Elements` instance that was used to create the Payment Element + elements, + confirmParams: { + return_url: 'https://localhost:3000' + } + }); + + if (error) { + addNotification({ + message: error.message, + type: 'error' + }); + } else { + // Your customer will be redirected to your `return_url`. For some payment + // methods like iDEAL, your customer will be redirected to an intermediate + // site first to authorize the payment, then redirected to the `return_url`. + } + } + async function updateName() { try { await sdkForConsole.teams.update($organization.$id, name); @@ -94,20 +118,18 @@ -
+ Create Payment Method +
+ +
+ +
-
- -
- -
- -
From 63ba5e31c9db79df7dc2201baee37740bbc2c7b7 Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Thu, 9 Feb 2023 06:37:35 +0545 Subject: [PATCH 05/10] update project plan --- src/lib/stores/billing.ts | 20 ++++++++- .../settings/+page.svelte | 4 +- .../project-[project]/settings/+page.svelte | 45 ++++++++++++++++++- 3 files changed, 64 insertions(+), 5 deletions(-) diff --git a/src/lib/stores/billing.ts b/src/lib/stores/billing.ts index 0ecfcff2ab..bd96d49817 100644 --- a/src/lib/stores/billing.ts +++ b/src/lib/stores/billing.ts @@ -1,4 +1,4 @@ -import type { Client } from '@aw-labs/appwrite-console'; +import type { Client, Payload } from '@aw-labs/appwrite-console'; export class Billing { client: Client; @@ -15,7 +15,23 @@ export class Billing { 'POST', uri, { - 'Content-Type': 'application/json' + 'content-type': 'application/json' + }, + params + ); + } + + async updateProjectPlan(projectId: string, billingPlan: string) { + const path = `/project/${projectId}/plan`; + const params: Payload = { + billingPlan + }; + const uri = new URL(this.client.config.endpoint + path); + return await this.client.call( + 'patch', + uri, + { + 'content-type': 'application/json' }, params ); diff --git a/src/routes/console/organization-[organization]/settings/+page.svelte b/src/routes/console/organization-[organization]/settings/+page.svelte index dc7e255194..f8ae121c69 100644 --- a/src/routes/console/organization-[organization]/settings/+page.svelte +++ b/src/routes/console/organization-[organization]/settings/+page.svelte @@ -118,7 +118,7 @@ -
+ Create Payment Method
@@ -130,7 +130,7 @@ - +
diff --git a/src/routes/console/project-[project]/settings/+page.svelte b/src/routes/console/project-[project]/settings/+page.svelte index 76277fbf24..c8cfc0d863 100644 --- a/src/routes/console/project-[project]/settings/+page.svelte +++ b/src/routes/console/project-[project]/settings/+page.svelte @@ -1,5 +1,5 @@