From 08918282a77c9e2e980fb161912ee5d8da516c83 Mon Sep 17 00:00:00 2001 From: Faruk AYDIN Date: Sat, 18 Mar 2023 21:21:06 +0300 Subject: [PATCH 1/8] feat: redesign billing page --- .../PaymentInformation/index.ee.tsx | 28 --- .../UsageDataInformation/index.ee.tsx | 159 ++++++++++++++---- .../BillingAndUsageSettings/index.ee.tsx | 17 +- 3 files changed, 129 insertions(+), 75 deletions(-) delete mode 100644 packages/web/src/components/PaymentInformation/index.ee.tsx diff --git a/packages/web/src/components/PaymentInformation/index.ee.tsx b/packages/web/src/components/PaymentInformation/index.ee.tsx deleted file mode 100644 index e0f8e22e..00000000 --- a/packages/web/src/components/PaymentInformation/index.ee.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import * as React from 'react'; -import Typography from '@mui/material/Typography'; - -import PageTitle from 'components/PageTitle'; -import { generateExternalLink } from 'helpers/translation-values'; -import usePaymentPortalUrl from 'hooks/usePaymentPortalUrl.ee'; -import useFormatMessage from 'hooks/useFormatMessage'; - -export default function PaymentInformation() { - const paymentPortal = usePaymentPortalUrl(); - const formatMessage = useFormatMessage(); - - return ( - - - {formatMessage('billingAndUsageSettings.paymentInformation')} - - - - {formatMessage( - 'billingAndUsageSettings.paymentPortalInformation', - { link: generateExternalLink(paymentPortal.url) })} - - - ); -} diff --git a/packages/web/src/components/UsageDataInformation/index.ee.tsx b/packages/web/src/components/UsageDataInformation/index.ee.tsx index f655a692..96814ee4 100644 --- a/packages/web/src/components/UsageDataInformation/index.ee.tsx +++ b/packages/web/src/components/UsageDataInformation/index.ee.tsx @@ -1,12 +1,21 @@ import * as React from 'react'; import { DateTime } from 'luxon'; +import Box from '@mui/material/Box'; +import Button from '@mui/material/Button'; +import Card from '@mui/material/Card'; +import CardActions from '@mui/material/CardActions'; +import CardContent from '@mui/material/CardContent'; +import Chip from '@mui/material/Chip'; +import Divider from '@mui/material/Divider'; +import Grid from '@mui/material/Grid'; import Paper from '@mui/material/Paper'; import Table from '@mui/material/Table'; import TableBody from '@mui/material/TableBody'; import TableCell from '@mui/material/TableCell'; import TableContainer from '@mui/material/TableContainer'; import TableRow from '@mui/material/TableRow'; +import Typography from '@mui/material/Typography'; import useUsageData from 'hooks/useUsageData.ee'; @@ -15,43 +24,119 @@ export default function UsageDataInformation() { return ( - - - - - - Current plan - - - {usageData.name} - - - - - Total allowed task count - - - {usageData.allowedTaskCount} - - - - - Consumed task count - - - {usageData.consumedTaskCount} - - - - - Next billing date - - - {usageData.nextResetAt?.toLocaleString(DateTime.DATE_FULL)} - - -
-
+ + + + + Subscription plan + + {/* */} + + + + + + + + Monthly quota + + + Free trial + + + + + + + + + + + + Next bill amount + + + --- + + + + {/* */} + + + + + + + + Next bill date + + + --- + + + + {/* */} + + + + + + + Your usage + + + + Last 30 days total usage + + + + + + Tasks + + + 12300 + + + + + + +
); } diff --git a/packages/web/src/pages/BillingAndUsageSettings/index.ee.tsx b/packages/web/src/pages/BillingAndUsageSettings/index.ee.tsx index af12fbdf..62a7de4f 100644 --- a/packages/web/src/pages/BillingAndUsageSettings/index.ee.tsx +++ b/packages/web/src/pages/BillingAndUsageSettings/index.ee.tsx @@ -2,8 +2,7 @@ import * as React from 'react'; import { Navigate } from 'react-router-dom'; import Grid from '@mui/material/Grid'; -import * as URLS from 'config/urls' -import PaymentInformation from 'components/PaymentInformation/index.ee'; +import * as URLS from 'config/urls'; import UsageDataInformation from 'components/UsageDataInformation/index.ee'; import PageTitle from 'components/PageTitle'; import Container from 'components/Container'; @@ -16,27 +15,25 @@ function BillingAndUsageSettings() { // redirect to the initial settings page if (isCloud === false) { - return () + return ; } // render nothing until we know if it's cloud or not // here, `isCloud` is not `false`, but `undefined` - if (!isCloud) return + if (!isCloud) return ; return ( - + - {formatMessage('billingAndUsageSettings.title')} + + {formatMessage('billingAndUsageSettings.title')} + - - - - ); From b1138dbf05e88889e061f64b8c59811d02cc3265 Mon Sep 17 00:00:00 2001 From: Ali BARIN Date: Sat, 18 Mar 2023 20:43:08 +0000 Subject: [PATCH 2/8] feat: make billings page responsive --- .../UsageDataInformation/index.ee.tsx | 47 ++++++++++++------- 1 file changed, 29 insertions(+), 18 deletions(-) diff --git a/packages/web/src/components/UsageDataInformation/index.ee.tsx b/packages/web/src/components/UsageDataInformation/index.ee.tsx index 96814ee4..623ada51 100644 --- a/packages/web/src/components/UsageDataInformation/index.ee.tsx +++ b/packages/web/src/components/UsageDataInformation/index.ee.tsx @@ -6,15 +6,8 @@ import Button from '@mui/material/Button'; import Card from '@mui/material/Card'; import CardActions from '@mui/material/CardActions'; import CardContent from '@mui/material/CardContent'; -import Chip from '@mui/material/Chip'; import Divider from '@mui/material/Divider'; import Grid from '@mui/material/Grid'; -import Paper from '@mui/material/Paper'; -import Table from '@mui/material/Table'; -import TableBody from '@mui/material/TableBody'; -import TableCell from '@mui/material/TableCell'; -import TableContainer from '@mui/material/TableContainer'; -import TableRow from '@mui/material/TableRow'; import Typography from '@mui/material/Typography'; import useUsageData from 'hooks/useUsageData.ee'; @@ -24,7 +17,7 @@ export default function UsageDataInformation() { return ( - + @@ -33,12 +26,19 @@ export default function UsageDataInformation() { {/* */} - - + + theme.palette.background.default, }} > @@ -54,31 +54,35 @@ export default function UsageDataInformation() { - + + theme.palette.background.default, }} > Next bill amount + --- + {/* */} - + + theme.palette.background.default, }} > @@ -89,6 +93,7 @@ export default function UsageDataInformation() { --- + {/* From 722c39590ff92697773fea973689d6264e6af230 Mon Sep 17 00:00:00 2001 From: Faruk AYDIN Date: Sun, 19 Mar 2023 01:24:41 +0300 Subject: [PATCH 3/8] feat: Start trial period on cloud --- packages/backend/package.json | 1 + ...318220822_add_trial_expiry_date_to_users.ts | 18 ++++++++++++++++++ packages/backend/src/models/user.ts | 11 +++++++++++ yarn.lock | 5 +++++ 4 files changed, 35 insertions(+) create mode 100644 packages/backend/src/db/migrations/20230318220822_add_trial_expiry_date_to_users.ts diff --git a/packages/backend/package.json b/packages/backend/package.json index a3e2a4db..2c0ed6e8 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -54,6 +54,7 @@ "lodash.get": "^4.4.2", "luxon": "2.5.2", "memory-cache": "^0.2.0", + "moment": "^2.29.4", "morgan": "^1.10.0", "multer": "1.4.5-lts.1", "nodemailer": "6.7.0", diff --git a/packages/backend/src/db/migrations/20230318220822_add_trial_expiry_date_to_users.ts b/packages/backend/src/db/migrations/20230318220822_add_trial_expiry_date_to_users.ts new file mode 100644 index 00000000..e3fa8799 --- /dev/null +++ b/packages/backend/src/db/migrations/20230318220822_add_trial_expiry_date_to_users.ts @@ -0,0 +1,18 @@ +import { Knex } from 'knex'; +import appConfig from '../../config/app'; + +export async function up(knex: Knex): Promise { + if (!appConfig.isCloud) return; + + return knex.schema.table('users', (table) => { + table.date('trial_expiry_date'); + }); +} + +export async function down(knex: Knex): Promise { + if (!appConfig.isCloud) return; + + return knex.schema.table('users', (table) => { + table.dropColumn('trial_expiry_date'); + }); +} diff --git a/packages/backend/src/models/user.ts b/packages/backend/src/models/user.ts index 57b07e89..fc880ab5 100644 --- a/packages/backend/src/models/user.ts +++ b/packages/backend/src/models/user.ts @@ -1,4 +1,6 @@ import { QueryContext, ModelOptions } from 'objection'; +import moment from 'moment'; +import appConfig from '../config/app'; import Base from './base'; import Connection from './connection'; import Flow from './flow'; @@ -17,6 +19,7 @@ class User extends Base { role: string; resetPasswordToken: string; resetPasswordTokenSentAt: string; + trialExpiryDate: string; connections?: Connection[]; flows?: Flow[]; steps?: Step[]; @@ -133,9 +136,17 @@ class User extends Base { this.password = await bcrypt.hash(this.password, 10); } + async startTrialPeriod() { + this.trialExpiryDate = moment().add(30, 'days').calendar(); + } + async $beforeInsert(queryContext: QueryContext) { await super.$beforeInsert(queryContext); await this.generateHash(); + + if (appConfig.isCloud) { + await this.startTrialPeriod(); + } } async $beforeUpdate(opt: ModelOptions, queryContext: QueryContext) { diff --git a/yarn.lock b/yarn.lock index 2a0b5d32..c5bc147b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12251,6 +12251,11 @@ modify-values@^1.0.0: resolved "https://registry.yarnpkg.com/modify-values/-/modify-values-1.0.1.tgz#b3939fa605546474e3e3e3c63d64bd43b4ee6022" integrity sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw== +moment@^2.29.4: + version "2.29.4" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.4.tgz#3dbe052889fe7c1b2ed966fcb3a77328964ef108" + integrity sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w== + morgan@^1.10.0: version "1.10.0" resolved "https://registry.yarnpkg.com/morgan/-/morgan-1.10.0.tgz#091778abc1fc47cd3509824653dae1faab6b17d7" From 280d16f3d9230024126c8f504e3cbf8d3b9e41e2 Mon Sep 17 00:00:00 2001 From: Faruk AYDIN Date: Sun, 19 Mar 2023 13:39:06 +0300 Subject: [PATCH 4/8] chore: Use luxon instead moment as date utility --- packages/backend/package.json | 1 - packages/backend/src/models/user.ts | 4 ++-- yarn.lock | 5 ----- 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/packages/backend/package.json b/packages/backend/package.json index 2c0ed6e8..a3e2a4db 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -54,7 +54,6 @@ "lodash.get": "^4.4.2", "luxon": "2.5.2", "memory-cache": "^0.2.0", - "moment": "^2.29.4", "morgan": "^1.10.0", "multer": "1.4.5-lts.1", "nodemailer": "6.7.0", diff --git a/packages/backend/src/models/user.ts b/packages/backend/src/models/user.ts index fc880ab5..bac17b40 100644 --- a/packages/backend/src/models/user.ts +++ b/packages/backend/src/models/user.ts @@ -1,5 +1,5 @@ import { QueryContext, ModelOptions } from 'objection'; -import moment from 'moment'; +import { DateTime } from 'luxon'; import appConfig from '../config/app'; import Base from './base'; import Connection from './connection'; @@ -137,7 +137,7 @@ class User extends Base { } async startTrialPeriod() { - this.trialExpiryDate = moment().add(30, 'days').calendar(); + this.trialExpiryDate = DateTime.now().plus({ days: 30 }).toFormat('D'); } async $beforeInsert(queryContext: QueryContext) { diff --git a/yarn.lock b/yarn.lock index c5bc147b..2a0b5d32 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12251,11 +12251,6 @@ modify-values@^1.0.0: resolved "https://registry.yarnpkg.com/modify-values/-/modify-values-1.0.1.tgz#b3939fa605546474e3e3e3c63d64bd43b4ee6022" integrity sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw== -moment@^2.29.4: - version "2.29.4" - resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.4.tgz#3dbe052889fe7c1b2ed966fcb3a77328964ef108" - integrity sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w== - morgan@^1.10.0: version "1.10.0" resolved "https://registry.yarnpkg.com/morgan/-/morgan-1.10.0.tgz#091778abc1fc47cd3509824653dae1faab6b17d7" From 189432c228aa449e6dc15dc580cf029f575a91fc Mon Sep 17 00:00:00 2001 From: Faruk AYDIN Date: Sun, 19 Mar 2023 15:53:34 +0300 Subject: [PATCH 5/8] feat: Implement draft version of UpgradeFreeTrial component --- .../components/UpgradeFreeTrial/index.ee.tsx | 146 ++++++++++++++++++ .../BillingAndUsageSettings/index.ee.tsx | 5 + 2 files changed, 151 insertions(+) create mode 100644 packages/web/src/components/UpgradeFreeTrial/index.ee.tsx diff --git a/packages/web/src/components/UpgradeFreeTrial/index.ee.tsx b/packages/web/src/components/UpgradeFreeTrial/index.ee.tsx new file mode 100644 index 00000000..ef68864d --- /dev/null +++ b/packages/web/src/components/UpgradeFreeTrial/index.ee.tsx @@ -0,0 +1,146 @@ +import * as React from 'react'; + +import Box from '@mui/material/Box'; +import Button from '@mui/material/Button'; +import Card from '@mui/material/Card'; +import CardContent from '@mui/material/CardContent'; +import Divider from '@mui/material/Divider'; +import Grid from '@mui/material/Grid'; +import Typography from '@mui/material/Typography'; +import Table from '@mui/material/Table'; +import TableBody from '@mui/material/TableBody'; +import TableCell from '@mui/material/TableCell'; +import TableContainer from '@mui/material/TableContainer'; +import TableHead from '@mui/material/TableHead'; +import TableRow from '@mui/material/TableRow'; +import Paper from '@mui/material/Paper'; +import LockIcon from '@mui/icons-material/Lock'; + +const rows = [ + { tasks: '10,000', price: '€20 / month', selected: true }, + { tasks: '30,000', price: '€50 / month', selected: false }, +]; + +export default function UpgradeFreeTrial() { + return ( + + + + + + Upgrade your free trial + + {/* */} + + + + + + + theme.palette.background.default, + }} + > + + + + Monthly Tasks + + + + + Price + + + + + + {rows.map((row) => ( + + + + {row.tasks} + + + + + {row.price} + + + + ))} + +
+
+
+ + + + + Due today:  + + + €20 + + + + + + VAT if applicable + + + +
+
+
+ ); +} diff --git a/packages/web/src/pages/BillingAndUsageSettings/index.ee.tsx b/packages/web/src/pages/BillingAndUsageSettings/index.ee.tsx index 62a7de4f..b6aa962c 100644 --- a/packages/web/src/pages/BillingAndUsageSettings/index.ee.tsx +++ b/packages/web/src/pages/BillingAndUsageSettings/index.ee.tsx @@ -4,6 +4,7 @@ import Grid from '@mui/material/Grid'; import * as URLS from 'config/urls'; import UsageDataInformation from 'components/UsageDataInformation/index.ee'; +import UpgradeFreeTrial from 'components/UpgradeFreeTrial/index.ee'; import PageTitle from 'components/PageTitle'; import Container from 'components/Container'; import useFormatMessage from 'hooks/useFormatMessage'; @@ -34,6 +35,10 @@ function BillingAndUsageSettings() { + + + +
); From 40862fcd019ea585f51929fca0da989802033516 Mon Sep 17 00:00:00 2001 From: Ali BARIN Date: Sun, 19 Mar 2023 22:22:11 +0000 Subject: [PATCH 6/8] feat: move plan upgrade to its page --- .../components/UpgradeFreeTrial/index.ee.tsx | 29 ++++++++----- .../UsageDataInformation/index.ee.tsx | 12 ++++-- packages/web/src/config/urls.ts | 2 + packages/web/src/locales/en.json | 3 +- .../BillingAndUsageSettings/index.ee.tsx | 4 -- .../web/src/pages/PlanUpgrade/index.ee.tsx | 42 +++++++++++++++++++ packages/web/src/settingsRoutes.tsx | 10 +++++ 7 files changed, 83 insertions(+), 19 deletions(-) create mode 100644 packages/web/src/pages/PlanUpgrade/index.ee.tsx diff --git a/packages/web/src/components/UpgradeFreeTrial/index.ee.tsx b/packages/web/src/components/UpgradeFreeTrial/index.ee.tsx index ef68864d..9608e637 100644 --- a/packages/web/src/components/UpgradeFreeTrial/index.ee.tsx +++ b/packages/web/src/components/UpgradeFreeTrial/index.ee.tsx @@ -16,12 +16,17 @@ import TableRow from '@mui/material/TableRow'; import Paper from '@mui/material/Paper'; import LockIcon from '@mui/icons-material/Lock'; -const rows = [ - { tasks: '10,000', price: '€20 / month', selected: true }, - { tasks: '30,000', price: '€50 / month', selected: false }, +const plans = [ + { tasks: '10,000', price: '€20' }, + { tasks: '30,000', price: '€50' }, ]; export default function UpgradeFreeTrial() { + const [selectedIndex, setSelectedIndex] = React.useState(0); + const selectedPlan = plans[selectedIndex]; + + const updateSelection = (index: number) => setSelectedIndex(index); + return ( @@ -42,7 +47,7 @@ export default function UpgradeFreeTrial() { alignItems="stretch" > - +
@@ -69,19 +74,21 @@ export default function UpgradeFreeTrial() { - {rows.map((row) => ( + {plans.map((row, index) => ( updateSelection(index)} sx={{ - backgroundColor: row.selected ? '#f1f3fa' : 'white', - border: row.selected ? '2px solid #0059f7' : 'none', + '&:hover': { cursor: 'pointer' }, + backgroundColor: selectedIndex === index ? '#f1f3fa' : 'white', + border: selectedIndex === index ? '2px solid #0059f7' : 'none', }} > {row.tasks} @@ -91,10 +98,10 @@ export default function UpgradeFreeTrial() { - {row.price} + {row.price} / month @@ -127,7 +134,7 @@ export default function UpgradeFreeTrial() { fontWeight: 'bold', }} > - €20 + {selectedPlan.price} diff --git a/packages/web/src/components/UsageDataInformation/index.ee.tsx b/packages/web/src/components/UsageDataInformation/index.ee.tsx index 623ada51..296ef5b6 100644 --- a/packages/web/src/components/UsageDataInformation/index.ee.tsx +++ b/packages/web/src/components/UsageDataInformation/index.ee.tsx @@ -1,6 +1,5 @@ import * as React from 'react'; -import { DateTime } from 'luxon'; - +import { Link } from 'react-router-dom'; import Box from '@mui/material/Box'; import Button from '@mui/material/Button'; import Card from '@mui/material/Card'; @@ -10,6 +9,7 @@ import Divider from '@mui/material/Divider'; import Grid from '@mui/material/Grid'; import Typography from '@mui/material/Typography'; +import * as URLS from 'config/urls'; import useUsageData from 'hooks/useUsageData.ee'; export default function UsageDataInformation() { @@ -143,7 +143,13 @@ export default function UsageDataInformation() { - diff --git a/packages/web/src/config/urls.ts b/packages/web/src/config/urls.ts index 07f3c448..174bbc9a 100644 --- a/packages/web/src/config/urls.ts +++ b/packages/web/src/config/urls.ts @@ -65,9 +65,11 @@ export const SETTINGS = '/settings'; export const SETTINGS_DASHBOARD = SETTINGS; export const PROFILE = 'profile'; export const BILLING_AND_USAGE = 'billing'; +export const PLAN_UPGRADE = 'upgrade'; export const UPDATES = '/updates'; export const SETTINGS_PROFILE = `${SETTINGS}/${PROFILE}`; export const SETTINGS_BILLING_AND_USAGE = `${SETTINGS}/${BILLING_AND_USAGE}`; +export const SETTINGS_PLAN_UPGRADE = `${SETTINGS_BILLING_AND_USAGE}/${PLAN_UPGRADE}`; export const DASHBOARD = FLOWS; diff --git a/packages/web/src/locales/en.json b/packages/web/src/locales/en.json index bb127ad5..c860fb3e 100644 --- a/packages/web/src/locales/en.json +++ b/packages/web/src/locales/en.json @@ -139,5 +139,6 @@ "resetPasswordForm.passwordUpdated": "The password has been updated. Now, you can login.", "usageAlert.informationText": "Tasks: {consumedTaskCount}/{allowedTaskCount} (Resets {relativeResetDate})", "usageAlert.viewPlans": "View plans", - "jsonViewer.noDataFound": "We couldn't find anything matching your search" + "jsonViewer.noDataFound": "We couldn't find anything matching your search", + "planUpgrade.title": "Upgrade your plan" } diff --git a/packages/web/src/pages/BillingAndUsageSettings/index.ee.tsx b/packages/web/src/pages/BillingAndUsageSettings/index.ee.tsx index b6aa962c..3b5383e4 100644 --- a/packages/web/src/pages/BillingAndUsageSettings/index.ee.tsx +++ b/packages/web/src/pages/BillingAndUsageSettings/index.ee.tsx @@ -35,10 +35,6 @@ function BillingAndUsageSettings() { - - - - ); diff --git a/packages/web/src/pages/PlanUpgrade/index.ee.tsx b/packages/web/src/pages/PlanUpgrade/index.ee.tsx new file mode 100644 index 00000000..e7796e64 --- /dev/null +++ b/packages/web/src/pages/PlanUpgrade/index.ee.tsx @@ -0,0 +1,42 @@ +import * as React from 'react'; +import { Navigate } from 'react-router-dom'; +import Grid from '@mui/material/Grid'; + +import * as URLS from 'config/urls'; +import UpgradeFreeTrial from 'components/UpgradeFreeTrial/index.ee'; +import PageTitle from 'components/PageTitle'; +import Container from 'components/Container'; +import useFormatMessage from 'hooks/useFormatMessage'; +import useCloud from 'hooks/useCloud'; + +function PlanUpgrade() { + const isCloud = useCloud(); + const formatMessage = useFormatMessage(); + + // redirect to the initial settings page + if (isCloud === false) { + return ; + } + + // render nothing until we know if it's cloud or not + // here, `isCloud` is not `false`, but `undefined` + if (!isCloud) return ; + + return ( + + + + + {formatMessage('planUpgrade.title')} + + + + + + + + + ); +} + +export default PlanUpgrade; diff --git a/packages/web/src/settingsRoutes.tsx b/packages/web/src/settingsRoutes.tsx index 60147939..454bcb74 100644 --- a/packages/web/src/settingsRoutes.tsx +++ b/packages/web/src/settingsRoutes.tsx @@ -2,6 +2,7 @@ import { Route, Navigate } from 'react-router-dom'; import SettingsLayout from 'components/SettingsLayout'; import ProfileSettings from 'pages/ProfileSettings'; import BillingAndUsageSettings from 'pages/BillingAndUsageSettings/index.ee'; +import PlanUpgrade from 'pages/PlanUpgrade/index.ee'; import * as URLS from 'config/urls'; @@ -25,6 +26,15 @@ export default ( } /> + + + + } + /> + } From f1358c7ad1691974d11de7003dd9af9424c516fe Mon Sep 17 00:00:00 2001 From: Faruk AYDIN Date: Mon, 20 Mar 2023 19:12:21 +0300 Subject: [PATCH 7/8] feat: add GetPaymentPlans graphQL query --- packages/backend/src/config/app.ts | 4 ++++ .../src/graphql/queries/get-payment-plans.ee.ts | 10 ++++++++++ packages/backend/src/graphql/query-resolvers.ts | 2 ++ packages/backend/src/graphql/schema.graphql | 8 ++++++++ packages/backend/src/helpers/billing/index.ee.ts | 2 ++ packages/backend/src/helpers/billing/plans.ee.ts | 16 ++++++++++++++++ 6 files changed, 42 insertions(+) create mode 100644 packages/backend/src/graphql/queries/get-payment-plans.ee.ts create mode 100644 packages/backend/src/helpers/billing/plans.ee.ts diff --git a/packages/backend/src/config/app.ts b/packages/backend/src/config/app.ts index fc8ad0b4..3364b834 100644 --- a/packages/backend/src/config/app.ts +++ b/packages/backend/src/config/app.ts @@ -39,6 +39,8 @@ type AppConfig = { smtpPassword: string; fromEmail: string; isCloud: boolean; + paddleVendorId: string; + paddleVendorAuthCode: string; stripeSecretKey: string; stripeSigningSecret: string; stripeStarterPriceKey: string; @@ -111,6 +113,8 @@ const appConfig: AppConfig = { smtpPassword: process.env.SMTP_PASSWORD, fromEmail: process.env.FROM_EMAIL, isCloud: process.env.AUTOMATISCH_CLOUD === 'true', + paddleVendorId: process.env.PADDLE_VENDOR_ID, + paddleVendorAuthCode: process.env.PADDLE_VENDOR_AUTH_CODE, stripeSecretKey: process.env.STRIPE_SECRET_KEY, stripeSigningSecret: process.env.STRIPE_SIGNING_SECRET, stripeStarterPriceKey: process.env.STRIPE_STARTER_PRICE_KEY, diff --git a/packages/backend/src/graphql/queries/get-payment-plans.ee.ts b/packages/backend/src/graphql/queries/get-payment-plans.ee.ts new file mode 100644 index 00000000..47fa7d91 --- /dev/null +++ b/packages/backend/src/graphql/queries/get-payment-plans.ee.ts @@ -0,0 +1,10 @@ +import appConfig from '../../config/app'; +import Billing from '../../helpers/billing/index.ee'; + +const getPaymentPlans = async () => { + if (!appConfig.isCloud) return; + + return Billing.paddlePlans; +}; + +export default getPaymentPlans; diff --git a/packages/backend/src/graphql/query-resolvers.ts b/packages/backend/src/graphql/query-resolvers.ts index 659839aa..267b3356 100644 --- a/packages/backend/src/graphql/query-resolvers.ts +++ b/packages/backend/src/graphql/query-resolvers.ts @@ -12,6 +12,7 @@ import getDynamicData from './queries/get-dynamic-data'; import getDynamicFields from './queries/get-dynamic-fields'; import getCurrentUser from './queries/get-current-user'; import getUsageData from './queries/get-usage-data.ee'; +import getPaymentPlans from './queries/get-payment-plans.ee'; import getPaymentPortalUrl from './queries/get-payment-portal-url.ee'; import getAutomatischInfo from './queries/get-automatisch-info'; import healthcheck from './queries/healthcheck'; @@ -31,6 +32,7 @@ const queryResolvers = { getDynamicFields, getCurrentUser, getUsageData, + getPaymentPlans, getPaymentPortalUrl, getAutomatischInfo, healthcheck, diff --git a/packages/backend/src/graphql/schema.graphql b/packages/backend/src/graphql/schema.graphql index c15ccd36..63817641 100644 --- a/packages/backend/src/graphql/schema.graphql +++ b/packages/backend/src/graphql/schema.graphql @@ -36,6 +36,7 @@ type Query { getCurrentUser: User getUsageData: GetUsageData getPaymentPortalUrl: GetPaymentPortalUrl + getPaymentPlans: [PaymentPlan] getAutomatischInfo: GetAutomatischInfo healthcheck: AppHealth } @@ -481,6 +482,13 @@ type GetPaymentPortalUrl { url: String } +type PaymentPlan { + name: String + limit: String + price: String + productId: String +} + schema { query: Query mutation: Mutation diff --git a/packages/backend/src/helpers/billing/index.ee.ts b/packages/backend/src/helpers/billing/index.ee.ts index 3d11f58b..863e68e7 100644 --- a/packages/backend/src/helpers/billing/index.ee.ts +++ b/packages/backend/src/helpers/billing/index.ee.ts @@ -4,6 +4,7 @@ import PaymentPlan from '../../models/payment-plan.ee'; import UsageData from '../../models/usage-data.ee'; import appConfig from '../../config/app'; import handleWebhooks from './webhooks.ee'; +import paddlePlans from './plans.ee'; const plans = [ { @@ -95,6 +96,7 @@ const billing = { handleWebhooks, stripe, plans, + paddlePlans, }; export default billing; diff --git a/packages/backend/src/helpers/billing/plans.ee.ts b/packages/backend/src/helpers/billing/plans.ee.ts new file mode 100644 index 00000000..98bdcac9 --- /dev/null +++ b/packages/backend/src/helpers/billing/plans.ee.ts @@ -0,0 +1,16 @@ +const plans = [ + { + name: '10k - monthly', + limit: '10,000', + price: '€20', + productId: '47384', + }, + { + name: '30k - monthly', + limit: '30,000', + price: '€50', + productId: '47419', + }, +]; + +export default plans; From 3598d439386198e9c79288f3479b99b5a3d2c6d4 Mon Sep 17 00:00:00 2001 From: Ali BARIN Date: Mon, 20 Mar 2023 21:46:20 +0000 Subject: [PATCH 8/8] feat: make payment plans dynamic --- packages/types/index.d.ts | 8 +++++++- .../components/UpgradeFreeTrial/index.ee.tsx | 19 +++++++++---------- .../graphql/queries/get-payment-plans.ee.ts | 12 ++++++++++++ packages/web/src/hooks/usePaymentPlans.ee.ts | 18 ++++++++++++++++++ 4 files changed, 46 insertions(+), 11 deletions(-) create mode 100644 packages/web/src/graphql/queries/get-payment-plans.ee.ts create mode 100644 packages/web/src/hooks/usePaymentPlans.ee.ts diff --git a/packages/types/index.d.ts b/packages/types/index.d.ts index 40ecea8e..6cd0dae2 100644 --- a/packages/types/index.d.ts +++ b/packages/types/index.d.ts @@ -321,6 +321,13 @@ export type IGlobalVariable = { setActionItem?: (actionItem: IActionItem) => void; }; +export type TPaymentPlan = { + price: string; + name: string; + limit: string; + productId: string; +} + declare module 'axios' { interface AxiosResponse { httpError?: IJSONObject; @@ -335,4 +342,3 @@ export interface IRequest extends Request { rawBody?: Buffer; currentUser?: IUser; } - diff --git a/packages/web/src/components/UpgradeFreeTrial/index.ee.tsx b/packages/web/src/components/UpgradeFreeTrial/index.ee.tsx index 9608e637..4fca59a0 100644 --- a/packages/web/src/components/UpgradeFreeTrial/index.ee.tsx +++ b/packages/web/src/components/UpgradeFreeTrial/index.ee.tsx @@ -1,5 +1,4 @@ import * as React from 'react'; - import Box from '@mui/material/Box'; import Button from '@mui/material/Button'; import Card from '@mui/material/Card'; @@ -16,17 +15,17 @@ import TableRow from '@mui/material/TableRow'; import Paper from '@mui/material/Paper'; import LockIcon from '@mui/icons-material/Lock'; -const plans = [ - { tasks: '10,000', price: '€20' }, - { tasks: '30,000', price: '€50' }, -]; +import usePaymentPlans from 'hooks/usePaymentPlans.ee'; export default function UpgradeFreeTrial() { + const { plans, loading } = usePaymentPlans(); const [selectedIndex, setSelectedIndex] = React.useState(0); - const selectedPlan = plans[selectedIndex]; + const selectedPlan = plans?.[selectedIndex]; const updateSelection = (index: number) => setSelectedIndex(index); + if (loading || !plans.length) return null; + return ( @@ -74,9 +73,9 @@ export default function UpgradeFreeTrial() { - {plans.map((row, index) => ( + {plans.map((plan, index) => ( updateSelection(index)} sx={{ '&:hover': { cursor: 'pointer' }, @@ -91,7 +90,7 @@ export default function UpgradeFreeTrial() { fontWeight: selectedIndex === index ? 'bold' : 'normal', }} > - {row.tasks} + {plan.limit} @@ -101,7 +100,7 @@ export default function UpgradeFreeTrial() { fontWeight: selectedIndex === index ? 'bold' : 'normal', }} > - {row.price} / month + {plan.price} / month diff --git a/packages/web/src/graphql/queries/get-payment-plans.ee.ts b/packages/web/src/graphql/queries/get-payment-plans.ee.ts new file mode 100644 index 00000000..1714b108 --- /dev/null +++ b/packages/web/src/graphql/queries/get-payment-plans.ee.ts @@ -0,0 +1,12 @@ +import { gql } from '@apollo/client'; + +export const GET_PAYMENT_PLANS = gql` + query GetPaymentPlans { + getPaymentPlans { + name + limit + price + productId + } + } +`; diff --git a/packages/web/src/hooks/usePaymentPlans.ee.ts b/packages/web/src/hooks/usePaymentPlans.ee.ts new file mode 100644 index 00000000..2a66cc39 --- /dev/null +++ b/packages/web/src/hooks/usePaymentPlans.ee.ts @@ -0,0 +1,18 @@ +import { useQuery } from '@apollo/client'; + +import { TPaymentPlan } from '@automatisch/types'; +import { GET_PAYMENT_PLANS } from 'graphql/queries/get-payment-plans.ee'; + +type UsePaymentPlansReturn = { + plans: TPaymentPlan[]; + loading: boolean; +}; + +export default function usePaymentPlans(): UsePaymentPlansReturn { + const { data, loading } = useQuery(GET_PAYMENT_PLANS); + + return { + plans: data?.getPaymentPlans || [], + loading + }; +}