From c82cd09e5b30f7d7989b874ef4c142a2a0f9daa8 Mon Sep 17 00:00:00 2001 From: Randy Date: Thu, 13 Jul 2023 14:26:08 +0800 Subject: [PATCH 1/6] subscription db --- components/Layout.tsx | 112 ++++++++++++++++-- components/Navbar.tsx | 40 +++++++ pages/api/subscription.ts | 88 ++++++++++++++ .../20230713042856_subscription/migration.sql | 17 +++ .../20230713055831_subscription/migration.sql | 2 + prisma/sqlite/schema.prisma | 35 ++++-- service/subscription.service.ts | 68 +++++++++++ service/viewData.service.ts | 4 + utils.server.ts | 6 + 9 files changed, 353 insertions(+), 19 deletions(-) create mode 100644 components/Navbar.tsx create mode 100644 pages/api/subscription.ts create mode 100644 prisma/sqlite/migrations/20230713042856_subscription/migration.sql create mode 100644 prisma/sqlite/migrations/20230713055831_subscription/migration.sql create mode 100644 service/subscription.service.ts diff --git a/components/Layout.tsx b/components/Layout.tsx index eb314c78..67e81e0c 100644 --- a/components/Layout.tsx +++ b/components/Layout.tsx @@ -3,7 +3,7 @@ import { useMutation, useQuery } from "react-query" import { useRouter } from "next/router" import { AiOutlineLogout, AiOutlineSetting, AiOutlineFileText, AiOutlineAlert, AiOutlinePlus, AiOutlineComment, AiOutlineCode, AiOutlineRight, AiOutlineDown, AiOutlineFile, AiOutlineQuestion, AiOutlineQuestionCircle } from 'react-icons/ai' import { signout, signOut } from "next-auth/client" -import { Anchor, AppShell, Avatar, Badge, Box, Button, Code, Group, Header, Menu, Modal, Navbar, NavLink, ScrollArea, Select, Space, Stack, Switch, Text, TextInput, Title } from "@mantine/core" +import { Anchor, AppShell, Avatar, Badge, Box, Button, Code, Grid, Group, Header, List, Menu, Modal, Navbar, NavLink, Paper, ScrollArea, Select, Space, Stack, Switch, Text, TextInput, Title } from "@mantine/core" import Link from "next/link" import type { ProjectServerSideProps } from "../pages/dashboard/project/[projectId]/settings" import { modals } from "@mantine/modals" @@ -13,6 +13,7 @@ import { apiClient } from "../utils.client" import { useForm } from "react-hook-form" import { MainLayoutData } from "../service/viewData.service" import { Head } from "./Head" +import dayjs from "dayjs" // From https://stackoverflow.com/questions/46155/how-to-validate-an-email-address-in-javascript function validateEmail(email) { @@ -55,6 +56,25 @@ export function MainLayout(props: { }, }) + const downgradePlanMutation = useMutation(async () => { + await apiClient.delete('/subscription') + }, { + onSuccess() { + notifications.show({ + title: 'Success', + message: 'Downgrade success', + color: 'green' + }) + }, + onError() { + notifications.show({ + title: 'Error', + message: 'Something went wrong, please contact hi@cusdis.com', + color: 'red' + }) + } + }) + const updateNewCommentNotification = useMutation(updateUserSettings, { onSuccess() { notifications.show({ @@ -209,11 +229,14 @@ export function MainLayout(props: { }, []) const badge = React.useMemo(() => { - if (!props.config.isHosted) { - return OSS + if (props.subscription.isActived) { + return PRO } - return PRO + if (props.config.isHosted) { + return OSS + } + return FREE }, []) const header = React.useMemo(() => { @@ -242,7 +265,7 @@ export function MainLayout(props: { + }} size="xs" rightIcon={} variant='subtle'>{props.session.user.name} {badge} ) @@ -273,7 +296,7 @@ export function MainLayout(props: { } }} > - @@ -298,11 +321,78 @@ export function MainLayout(props: { Display name - {/* - Subscription - Current plan: {badge} - Manage subscription - */} + {props.config.checkout.enabled && ( + + Subscription + + + ({ + border: '1px solid #eaeaea', + padding: theme.spacing.md + })}> + + + Free + + + + Up to 1 site + + + 10 Quick Approve / month + + + 100 approved comments / month + + + {!props.subscription.isActived || props.subscription.status === 'cancelled' ? ( + + ) : ( + + )} + + + + + ({ + border: '1px solid #eaeaea', + padding: theme.spacing.md + })}> + + + Pro + + + + Unlimited sites + + + Unlimited Quick Approve + + + Unlimited approved comments + + + {props.subscription.isActived ? ( + <> + + {props.subscription.status === 'cancelled' && (Expire on {dayjs(props.subscription.endAt).format('YYYY/MM/DD')})} + + ) : ( + + )} + + + + + + )} - ) : ( - - )} - - - - - ({ - border: '1px solid #eaeaea', - padding: theme.spacing.md - })}> - - - Pro - - - - Unlimited sites - - - Unlimited Quick Approve - - - Unlimited approved comments - - - {props.subscription.isActived ? ( - <> - - {props.subscription.status === 'cancelled' && (Expire on {dayjs(props.subscription.endAt).format('YYYY/MM/DD')})} - - ) : ( - - )} - - - - - + <> + {usageBoard} + + Subscription + + + ({ + border: '1px solid #eaeaea', + padding: theme.spacing.md + })}> + + + Free + + + + Up to 1 site + + + 10 Quick Approve / month + + + 100 approved comments / month + + + {!props.subscription.isActived || props.subscription.status === 'cancelled' ? ( + + ) : ( + + )} + + + + + ({ + border: '1px solid #eaeaea', + padding: theme.spacing.md + })}> + + + Pro + + + + Unlimited sites + + + Unlimited Quick Approve + + + Unlimited approved comments + + + {props.subscription.isActived ? ( + <> + + {props.subscription.status === 'cancelled' && (Expire on {dayjs(props.subscription.endAt).format('YYYY/MM/DD')})} + + ) : ( + + )} + + + + + + )} + Pricing + {/* Pricing */} @@ -152,7 +154,7 @@ function IndexPage({ session, contributers }: Props) { Email Notification - You will receive Email notification when a new comment comes in, and approve the new comment without login. + You will receive Email notification when a new comment comes in, and do a Quick Approve. @@ -163,7 +165,7 @@ function IndexPage({ session, contributers }: Props) { - Approve/Reply without login + Quick Approve In the notification email and webhook, you will get a short-time link to approve/reply the new comment without login to dashboard. All the things get done in your mobile. @@ -182,7 +184,7 @@ function IndexPage({ session, contributers }: Props) { You can set a Webhook URL that will be triggered when your websites have new comment. Integrate Cusdis with your favorite tools such as Telegram. - How to use Webhook @@ -215,13 +217,72 @@ function IndexPage({ session, contributers }: Props) { ) })} + -
- {StartButton} -
+ + Pricing + + + Self Host + + FREE + + + All features. But host on your own server and database. + + + + + + Cloud + + FREE + + + {usageLimitation['create_site']} site + {usageLimitation['approve_comment']} approved comments / month + {usageLimitation['quick_approve']} Quick Approve / month + + + -