Skip to content

Commit

Permalink
usage board
Browse files Browse the repository at this point in the history
  • Loading branch information
djyde committed Jul 13, 2023
1 parent 53cfc6e commit 6db257c
Show file tree
Hide file tree
Showing 6 changed files with 161 additions and 85 deletions.
177 changes: 106 additions & 71 deletions components/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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, Grid, Group, Header, List, Menu, Modal, Navbar, NavLink, Paper, 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, Progress, 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"
Expand All @@ -14,6 +14,7 @@ import { useForm } from "react-hook-form"
import { MainLayoutData } from "../service/viewData.service"
import { Head } from "./Head"
import dayjs from "dayjs"
import { usageLimitation } from "../config.common"

// From https://stackoverflow.com/questions/46155/how-to-validate-an-email-address-in-javascript
function validateEmail(email) {
Expand Down Expand Up @@ -271,6 +272,37 @@ export function MainLayout(props: {
)
}, [])

const usageBoard = React.useMemo(() => {
return (
<>
<Text size="sm" weight={900}>
Usage (per month)
</Text>
<Stack spacing={4}>
<Group spacing={4}>
<Text weight={500} size="sm">Sites:</Text>
<Text size='sm'>
{`${props.usage.projectCount} / ${usageLimitation['create_site']}`}
</Text>
</Group>

<Group spacing={4}>
<Text weight={500} size="sm">Approve comments:</Text>
<Text size='sm'>
{`${props.usage.approveCommentUsage} / ${usageLimitation['approve_comment']}`}
</Text>
</Group>
<Group spacing={4}>
<Text weight={500} size="sm">Quick Approve:</Text>
<Text size='sm'>
{`${props.usage.quickApproveUsage} / ${usageLimitation['quick_approve']}`}
</Text>
</Group>
</Stack>
</>
)
}, [])

return (
<>
<Head title={`${props.project.title} - Cusdis`} />
Expand Down Expand Up @@ -322,76 +354,79 @@ export function MainLayout(props: {
<TextInput placeholder={props.userInfo.name} {...userSettingsForm.register("displayName")} size="sm" />
</Stack>
{props.config.checkout.enabled && (
<Stack spacing={8}>
<Text weight={500} size="sm">Subscription </Text>
<Grid>
<Grid.Col span={6}>
<Paper sx={theme => ({
border: '1px solid #eaeaea',
padding: theme.spacing.md
})}>
<Stack>
<Title order={4}>
Free
</Title>
<List size='sm' sx={{
}}>
<List.Item>
Up to 1 site
</List.Item>
<List.Item>
10 Quick Approve / month
</List.Item>
<List.Item>
100 approved comments / month
</List.Item>
</List>
{!props.subscription.isActived || props.subscription.status === 'cancelled' ? (
<Button disabled size="xs">Current plan</Button>
) : (
<Button size="xs" variant={'outline'} loading={downgradePlanMutation.isLoading} onClick={_ => {
if (window.confirm('Are you sure to downgrade?')) {
downgradePlanMutation.mutate()
}
}}>Downgrade</Button>
)}
</Stack>
</Paper>
</Grid.Col>
<Grid.Col span={6}>
<Paper sx={theme => ({
border: '1px solid #eaeaea',
padding: theme.spacing.md
})}>
<Stack>
<Title order={4}>
Pro
</Title>
<List size='sm' sx={{
}}>
<List.Item>
Unlimited sites
</List.Item>
<List.Item>
Unlimited Quick Approve
</List.Item>
<List.Item>
Unlimited approved comments
</List.Item>
</List>
{props.subscription.isActived ? (
<>
<Button size="xs" component="a" href={props.subscription.updatePaymentMethodUrl}>Manage payment method</Button>
{props.subscription.status === 'cancelled' && (<Text size='xs' align='center'>Expire on {dayjs(props.subscription.endAt).format('YYYY/MM/DD')}</Text>)}
</>
) : (
<Button size='xs' component="a" href={`${props.config.checkout.url}?checkout=[custom][user_id]=${props.session.uid}`}>Upgrade $5/month</Button>
)}
</Stack>
</Paper>
</Grid.Col>
</Grid>
</Stack>
<>
{usageBoard}
<Stack spacing={8}>
<Text weight={900} size="sm">Subscription </Text>
<Grid>
<Grid.Col span={6}>
<Paper sx={theme => ({
border: '1px solid #eaeaea',
padding: theme.spacing.md
})}>
<Stack>
<Title order={4}>
Free
</Title>
<List size='sm' sx={{
}}>
<List.Item>
Up to 1 site
</List.Item>
<List.Item>
10 Quick Approve / month
</List.Item>
<List.Item>
100 approved comments / month
</List.Item>
</List>
{!props.subscription.isActived || props.subscription.status === 'cancelled' ? (
<Button disabled size="xs">Current plan</Button>
) : (
<Button size="xs" variant={'outline'} loading={downgradePlanMutation.isLoading} onClick={_ => {
if (window.confirm('Are you sure to downgrade?')) {
downgradePlanMutation.mutate()
}
}}>Downgrade</Button>
)}
</Stack>
</Paper>
</Grid.Col>
<Grid.Col span={6}>
<Paper sx={theme => ({
border: '1px solid #eaeaea',
padding: theme.spacing.md
})}>
<Stack>
<Title order={4}>
Pro
</Title>
<List size='sm' sx={{
}}>
<List.Item>
Unlimited sites
</List.Item>
<List.Item>
Unlimited Quick Approve
</List.Item>
<List.Item>
Unlimited approved comments
</List.Item>
</List>
{props.subscription.isActived ? (
<>
<Button size="xs" component="a" href={props.subscription.updatePaymentMethodUrl}>Manage payment method</Button>
{props.subscription.status === 'cancelled' && (<Text size='xs' align='center'>Expire on {dayjs(props.subscription.endAt).format('YYYY/MM/DD')}</Text>)}
</>
) : (
<Button size='xs' component="a" href={`${props.config.checkout.url}?checkout=[custom][user_id]=${props.session.uid}`}>Upgrade $5/month</Button>
)}
</Stack>
</Paper>
</Grid.Col>
</Grid>
</Stack>
</>
)}
<Button loading={updateUserSettingsMutation.isLoading} onClick={onClickSaveUserSettings}>Save</Button>
<Button onClick={_ => signOut()} variant={'outline'} color='red'>
Expand Down
11 changes: 11 additions & 0 deletions config.common.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export enum UsageLabel {
ApproveComment = 'approve_comment',
QuickApprove = 'quick_approve',
CreateSite = 'create_site'
}

export const usageLimitation = {
[UsageLabel.ApproveComment]: 100,
[UsageLabel.QuickApprove]: 10,
[UsageLabel.CreateSite]: 1
}
5 changes: 3 additions & 2 deletions pages/api/open/approve.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ import { resolvedConfig } from '../../../utils.server'
import jwt from 'jsonwebtoken'
import { CommentService } from '../../../service/comment.service'
import { SecretKey, TokenBody, TokenService } from '../../../service/token.service'
import { UsageLabel, UsageService } from '../../../service/usage.service'
import { SubscriptionService, usageLimitation } from '../../../service/subscription.service'
import { UsageService } from '../../../service/usage.service'
import { SubscriptionService } from '../../../service/subscription.service'
import { UsageLabel, usageLimitation } from '../../../config.common'

export default async function handler(
req: NextApiRequest,
Expand Down
7 changes: 1 addition & 6 deletions service/subscription.service.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
import { UsageLabel, usageLimitation } from "../config.common"
import { prisma, resolvedConfig } from "../utils.server"
import { UsageLabel } from "./usage.service"

export const usageLimitation = {
[UsageLabel.ApproveComment]: 100,
[UsageLabel.QuickApprove]: 10,
}

export class SubscriptionService {
async update(body) {
Expand Down
7 changes: 1 addition & 6 deletions service/usage.service.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
import { RequestScopeService } from ".";
import { UsageLabel } from "../config.common";
import { prisma } from "../utils.server";


export enum UsageLabel {
ApproveComment = 'approve_comment',
QuickApprove = 'quick_approve',
}

export class UsageService extends RequestScopeService {
async incr(label: UsageLabel) {
const session = await this.getSession()
Expand Down
39 changes: 39 additions & 0 deletions service/viewData.service.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// A service for rendering page

import { RequestScopeService, UserSession } from ".";
import { UsageLabel } from "../config.common";
import { prisma, resolvedConfig } from "../utils.server";
import { ProjectService } from "./project.service";
import { SubscriptionService } from './subscription.service'
Expand All @@ -25,10 +26,48 @@ export class ViewDataService extends RequestScopeService {
}
})

const [projectCount, approveCommentUsage, quickApproveUsage] = await prisma.$transaction([
prisma.project.count({
where: {
ownerId: session.uid,
deletedAt: {
equals: null
}
}
}),
prisma.usage.findUnique({
where: {
userId_label: {
userId: session.uid,
label: UsageLabel.ApproveComment
}
},
select: {
count: true
}
}),
prisma.usage.findUnique({
where: {
userId_label: {
userId: session.uid,
label: UsageLabel.QuickApprove
}
},
select: {
count: true
}
})
])

return {
session,
projects: await this.projectService.list(),
subscription: await this.subscriptionService.getStatus(session.uid),
usage: {
projectCount,
approveCommentUsage: approveCommentUsage?.count ?? 0,
quickApproveUsage: quickApproveUsage?.count ?? 0
},
config: {
isHosted: resolvedConfig.isHosted,
checkout: resolvedConfig.checkout,
Expand Down

0 comments on commit 6db257c

Please sign in to comment.