Skip to content

Commit f05a7f4

Browse files
authored
Merge pull request #95 from Dialogue-Bot/DIAL-42-implement-test-your-bot
feat: add integrate stripe
2 parents 6e0aebe + 142d5b2 commit f05a7f4

File tree

93 files changed

+10029
-251
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

93 files changed

+10029
-251
lines changed

client/package-lock.json

+9
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

client/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
"@radix-ui/react-toggle": "^1.0.3",
4646
"@radix-ui/react-toggle-group": "^1.0.4",
4747
"@radix-ui/react-tooltip": "^1.0.7",
48+
"@stripe/stripe-js": "^3.3.0",
4849
"@tanstack/react-query": "^5.22.2",
4950
"@tanstack/react-query-devtools": "^5.24.0",
5051
"@tanstack/react-router": "^1.16.6",

client/src/apis/plan.api.ts

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { ENDPOINTS } from '@/constants'
2+
import http_client from '@/lib/http-client'
3+
import { TPlan } from '@/types/plan'
4+
import { TBaseResponse } from '@/types/share'
5+
6+
export class PlanApi {
7+
getAllPlans(): Promise<TBaseResponse<TPlan[]>> {
8+
return http_client.get(ENDPOINTS.PLANS.INDEX)
9+
}
10+
}
11+
12+
export const planApi = new PlanApi()

client/src/apis/subscription.ts

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { ENDPOINTS } from '@/constants'
2+
import http_client from '@/lib/http-client'
3+
import { TBaseResponse } from '@/types/share'
4+
import {
5+
TCreateBillingPortalSession,
6+
TCreateSubscriptionCheckoutSession,
7+
} from '@/types/subscription'
8+
9+
export class SubscriptionApi {
10+
async createCheckoutSession(
11+
data: TCreateSubscriptionCheckoutSession,
12+
): Promise<
13+
TBaseResponse<{
14+
sessionId: string
15+
type: string
16+
url: string
17+
}>
18+
> {
19+
return http_client.post(
20+
ENDPOINTS.SUBSCRIPTIONS.CREATE_CHECKOUT_SESSION,
21+
data,
22+
)
23+
}
24+
25+
async createBillingPortalSession(
26+
data: TCreateBillingPortalSession,
27+
): Promise<TBaseResponse<string>> {
28+
return http_client.post(
29+
ENDPOINTS.SUBSCRIPTIONS.CREATE_BILLING_PORTAL_SESSION,
30+
data,
31+
)
32+
}
33+
}
34+
35+
export const subscriptionApi = new SubscriptionApi()

client/src/apis/user-subscription.ts

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { ENDPOINTS } from '@/constants'
2+
import http_client from '@/lib/http-client'
3+
import { TBaseResponse } from '@/types/share'
4+
import { TUserSubscription } from '@/types/user-subscription'
5+
6+
export class UserSubscriptionApi {
7+
async getCurrentUserSubscription(): Promise<
8+
TBaseResponse<TUserSubscription>
9+
> {
10+
return http_client.get(ENDPOINTS.USER_SUBSCRIPTIONS.CURRENT)
11+
}
12+
13+
async getUsageSubscription(): Promise<
14+
TBaseResponse<{
15+
numberOfChannels: number
16+
numberOfFlows: number
17+
totalChannels: number
18+
totalFlows: number
19+
}>
20+
> {
21+
return http_client.get(ENDPOINTS.USER_SUBSCRIPTIONS.USAGE)
22+
}
23+
}
24+
25+
export const userSubscriptionApi = new UserSubscriptionApi()

client/src/components/forms/condition.tsx

+2-16
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import {
55
} from '@/lib/schema/compare-value'
66
import { isStringBoolean } from '@/utils'
77
import { zodResolver } from '@hookform/resolvers/zod'
8-
import { useEffect } from 'react'
98
import { useForm } from 'react-hook-form'
109
import { useTranslation } from 'react-i18next'
1110
import {
@@ -56,12 +55,6 @@ const ConditionForm = ({
5655
})
5756
})
5857

59-
useEffect(() => {
60-
if (watchOperator === 'exist' && !form.getValues('value')) {
61-
form.reset({ value: 'true' })
62-
}
63-
}, [watchOperator, form])
64-
6558
return (
6659
<Form {...form}>
6760
<form className='space-y-3' onSubmit={handleSubmit} id={id}>
@@ -72,11 +65,7 @@ const ConditionForm = ({
7265
render={({ field }) => (
7366
<FormItem className='w-full'>
7467
<FormLabel>{t('operator.label')}</FormLabel>
75-
<Select
76-
onValueChange={field.onChange}
77-
defaultValue={field.value}
78-
value={field.value}
79-
>
68+
<Select onValueChange={field.onChange} value={field.value}>
8069
<FormControl>
8170
<SelectTrigger>
8271
<SelectValue placeholder={t('operator.placeholder')} />
@@ -108,10 +97,7 @@ const ConditionForm = ({
10897
render={({ field }) => (
10998
<FormItem className='w-full'>
11099
<FormLabel>{t('value.label')}</FormLabel>
111-
<Select
112-
onValueChange={field.onChange}
113-
defaultValue={field.value}
114-
>
100+
<Select onValueChange={field.onChange} value={field.value}>
115101
<FormControl>
116102
<SelectTrigger className='capitalize'>
117103
<SelectValue placeholder={t('value.placeholder')} />

client/src/components/forms/general-setting.tsx

+3-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,9 @@ export const GeneralSettingForm = ({
3737
}: Props) => {
3838
const { id: flowId } = useParams()
3939
const { data } = useSuspenseQuery(
40-
queryChannelsForSelectOption(flowId as string),
40+
queryChannelsForSelectOption({
41+
flowId,
42+
}),
4143
)
4244
const { t } = useTranslation('forms')
4345
const schema = useFlowInputSchema()

client/src/components/layouts/app/sidebar.tsx

+79-54
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import PageLoading from '@/components/page-loading'
12
import {
23
Avatar,
34
AvatarFallback,
@@ -9,6 +10,7 @@ import {
910
} from '@/components/ui'
1011
import { ROUTES } from '@/constants'
1112
import { useLogout } from '@/hooks/auth'
13+
import { useCreateBillingPortalSession } from '@/hooks/subscription'
1214
import { useUserStore } from '@/store/use-user'
1315
import {
1416
Bot,
@@ -17,6 +19,7 @@ import {
1719
LogOut,
1820
MessageCircle,
1921
MessageSquareCode,
22+
Rss,
2023
} from 'lucide-react'
2124
import { useTranslation } from 'react-i18next'
2225
import { Link } from 'react-router-dom'
@@ -62,68 +65,90 @@ const Sidebar = () => {
6265

6366
const logoutMutation = useLogout()
6467

68+
const createBillingPortalSessionMutation = useCreateBillingPortalSession()
69+
6570
return (
66-
<aside className='w-sidebar bg-stone-800 min-h-svh flex flex-col fixed left-0 top-0 bottom-0 z-50'>
67-
<Link
68-
className='bg-primary w-sidebar h-sidebar flex items-center justify-center'
69-
to={ROUTES.PRIVATE.DASHBOARD}
70-
>
71-
<Bot size={32} className='text-white' />
72-
</Link>
73-
<nav className='flex flex-col flex-1'>
74-
<ul className='flex flex-col'>
75-
{SIDEBAR_ITEMS.map((item, index) => (
76-
<TooltipProvider key={item.i18n + index}>
71+
<>
72+
{createBillingPortalSessionMutation.isPending && (
73+
<PageLoading className='fixed inset-0 z-[1000] backdrop-blur-sm bg-transparent' />
74+
)}
75+
<aside className='w-sidebar bg-stone-800 min-h-svh flex flex-col fixed left-0 top-0 bottom-0 z-50'>
76+
<Link
77+
className='bg-primary w-sidebar h-sidebar flex items-center justify-center'
78+
to={ROUTES.PRIVATE.DASHBOARD}
79+
>
80+
<Bot size={32} className='text-white' />
81+
</Link>
82+
<nav className='flex flex-col flex-1'>
83+
<ul className='flex flex-col'>
84+
{SIDEBAR_ITEMS.map((item, index) => (
85+
<TooltipProvider key={item.i18n + index}>
86+
<Tooltip>
87+
<TooltipTrigger>
88+
<li className='h-12 w-full flex items-center justify-center group'>
89+
<Link
90+
to={item.to}
91+
className='w-full h-full flex items-center justify-center'
92+
>
93+
{item.Icon}
94+
</Link>
95+
</li>
96+
</TooltipTrigger>
97+
<TooltipContent side='right'>
98+
<p>{t(item.i18n as any)}</p>
99+
</TooltipContent>
100+
</Tooltip>
101+
</TooltipProvider>
102+
))}
103+
</ul>
104+
<div className='mt-auto'>
105+
<TooltipProvider>
106+
<Tooltip>
107+
<TooltipTrigger className='h-12 w-full flex items-center justify-center group'>
108+
<Link
109+
className='w-full h-full flex items-center justify-center'
110+
to={ROUTES.PRIVATE.USER_SUBSCRIPTION.INDEX}
111+
>
112+
<Rss className='w-5 h-5 text-white' />
113+
</Link>
114+
</TooltipTrigger>
115+
<TooltipContent side='right'>
116+
<p>{t('subscription')}</p>
117+
</TooltipContent>
118+
</Tooltip>
119+
</TooltipProvider>
120+
<div className='flex items-center justify-center cursor-pointer w-sidebar h-sidebar'>
121+
<Link
122+
to={ROUTES.PRIVATE.SETTING.PROFILES}
123+
className='flex items-center justify-center'
124+
>
125+
<Avatar className='w-9 h-9 '>
126+
<AvatarImage src={user?.avatar as string} alt={user?.name} />
127+
<AvatarFallback>
128+
<span>{user?.name?.[0]}</span>
129+
</AvatarFallback>
130+
</Avatar>
131+
</Link>
132+
</div>
133+
<TooltipProvider>
77134
<Tooltip>
78-
<TooltipTrigger>
79-
<li className='h-12 w-full flex items-center justify-center group'>
80-
<Link
81-
to={item.to}
82-
className='w-full h-full flex items-center justify-center'
83-
>
84-
{item.Icon}
85-
</Link>
86-
</li>
135+
<TooltipTrigger className='h-12 w-full flex items-center justify-center group'>
136+
<div
137+
className='w-full h-full flex items-center justify-center'
138+
onClick={() => logoutMutation.mutate()}
139+
>
140+
<LogOut className='w-5 h-5 text-white group-hover:opacity-85 transition-all' />
141+
</div>
87142
</TooltipTrigger>
88143
<TooltipContent side='right'>
89-
<p>{t(item.i18n as any)}</p>
144+
<p>{t('logout')}</p>
90145
</TooltipContent>
91146
</Tooltip>
92147
</TooltipProvider>
93-
))}
94-
</ul>
95-
<div className='mt-auto'>
96-
<div className='flex items-center justify-center cursor-pointer w-sidebar h-sidebar'>
97-
<Link
98-
to={ROUTES.PRIVATE.SETTING.PROFILES}
99-
className='flex items-center justify-center'
100-
>
101-
<Avatar className='w-9 h-9 '>
102-
<AvatarImage src={user?.avatar as string} alt={user?.name} />
103-
<AvatarFallback>
104-
<span>{user?.name?.[0]}</span>
105-
</AvatarFallback>
106-
</Avatar>
107-
</Link>
108148
</div>
109-
<TooltipProvider>
110-
<Tooltip>
111-
<TooltipTrigger className='h-12 w-full flex items-center justify-center group'>
112-
<div
113-
className='w-full h-full flex items-center justify-center'
114-
onClick={() => logoutMutation.mutate()}
115-
>
116-
<LogOut className='w-5 h-5 text-white group-hover:opacity-85 transition-all' />
117-
</div>
118-
</TooltipTrigger>
119-
<TooltipContent side='right'>
120-
<p>{t('logout')}</p>
121-
</TooltipContent>
122-
</Tooltip>
123-
</TooltipProvider>
124-
</div>
125-
</nav>
126-
</aside>
149+
</nav>
150+
</aside>
151+
</>
127152
)
128153
}
129154

client/src/components/page-loading.tsx

+13-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,18 @@
1+
import { cn } from '@/lib/utils'
12
import { Bot, Loader2 } from 'lucide-react'
2-
const PageLoading = () => {
3+
4+
type PageLoadingProps = {
5+
className?: string
6+
}
7+
8+
const PageLoading = ({ className }: PageLoadingProps) => {
39
return (
4-
<div className='flex items-center justify-center h-svh bg-white'>
10+
<div
11+
className={cn(
12+
'flex items-center justify-center h-svh bg-white',
13+
className,
14+
)}
15+
>
516
<div className='flex flex-col gap-2 items-center'>
617
<Bot size={56} className='text-primary' />
718
<Loader2 className='text-primary animate-spin' size={24} />

client/src/components/pages/flow-detail/node-dialog/http-request.tsx

-6
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ export const HttpRequestDialogContent = () => {
4242
method: selectedNode?.data?.httpRequest?.method || 'GET',
4343
params: selectedNode?.data?.httpRequest?.params || [],
4444
headers: selectedNode?.data?.httpRequest?.headers || [],
45-
query: selectedNode?.data?.httpRequest?.query || [],
4645
body: selectedNode?.data?.httpRequest?.body || [],
4746
assignUserResponse: selectedNode?.data?.assignUserResponse || NOT_CHOOSE,
4847
},
@@ -58,11 +57,6 @@ export const HttpRequestDialogContent = () => {
5857
control: form.control,
5958
})
6059

61-
const queryFieldArray = useFieldArray({
62-
name: 'query',
63-
control: form.control,
64-
})
65-
6660
const bodyFieldArray = useFieldArray({
6761
name: 'body',
6862
control: form.control,

0 commit comments

Comments
 (0)