Skip to content

Commit 9ac4215

Browse files
committed
Merge branch 'main' into DIAL-35-Setup-socket-for-server
2 parents 0cea6af + 338c1a5 commit 9ac4215

Some content is hidden

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

71 files changed

+17535
-7334
lines changed

client/package-lock.json

Lines changed: 1789 additions & 103 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

client/package.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
"@hookform/resolvers": "^3.3.4",
1515
"@mdx-js/react": "^3.0.1",
1616
"@mdx-js/rollup": "^3.0.1",
17+
"@million/lint": "^0.0.73",
1718
"@paralleldrive/cuid2": "^2.2.2",
1819
"@radix-ui/react-accordion": "^1.1.2",
1920
"@radix-ui/react-alert-dialog": "^1.0.5",
@@ -48,6 +49,13 @@
4849
"@tanstack/react-router": "^1.16.6",
4950
"@tanstack/react-table": "^8.12.0",
5051
"@tanstack/router-devtools": "^1.16.6",
52+
"@tiptap/extension-color": "^2.2.4",
53+
"@tiptap/extension-list-item": "^2.2.4",
54+
"@tiptap/extension-text-align": "^2.2.4",
55+
"@tiptap/extension-text-style": "^2.2.4",
56+
"@tiptap/extension-underline": "^2.2.4",
57+
"@tiptap/react": "^2.2.4",
58+
"@tiptap/starter-kit": "^2.2.4",
5159
"@xyflow/react": "^12.0.0-next.11",
5260
"axios": "^1.6.7",
5361
"class-variance-authority": "^0.7.0",
@@ -64,7 +72,9 @@
6472
"i18next-chained-backend": "^4.6.2",
6573
"i18next-http-backend": "^2.4.3",
6674
"i18next-localstorage-backend": "^4.2.0",
75+
"lodash": "^4.17.21",
6776
"lucide-react": "^0.335.0",
77+
"million": "^3.0.6",
6878
"next-themes": "^0.2.1",
6979
"react": "^18.2.0",
7080
"react-day-picker": "^8.10.0",
@@ -88,6 +98,7 @@
8898
"@tailwindcss/typography": "^0.5.10",
8999
"@tanstack/router-vite-plugin": "^1.16.5",
90100
"@types/crypto-js": "^4.2.2",
101+
"@types/lodash": "^4.17.0",
91102
"@types/mdx": "^2.0.11",
92103
"@types/node": "^20.11.24",
93104
"@types/react": "^18.2.55",

client/src/app.tsx

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import { Outlet, createBrowserRouter, redirect } from 'react-router-dom'
2-
import i18n from './i18n'
31
import {
42
Channels,
53
ChatBotDetail,
@@ -11,17 +9,18 @@ import {
119
Register,
1210
SetPassword,
1311
} from '@/pages'
12+
import { Outlet, createBrowserRouter, redirect } from 'react-router-dom'
1413

1514
import {
1615
AppLayout,
1716
AuthLayout,
1817
PublishLayout,
1918
SettingLayout,
2019
} from '@/components/layouts'
21-
import { ROUTES } from './constants'
22-
import Help from './pages/help'
20+
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'
2321
import { Suspense } from 'react'
2422
import PageLoading from './components/page-loading'
23+
import { ROUTES } from './constants'
2524
import {
2625
appLoader,
2726
articleLoader,
@@ -32,8 +31,8 @@ import {
3231
flowsLoader,
3332
settingLoader,
3433
} from './lib/loader'
34+
import Help from './pages/help'
3535
import HelpDetail from './pages/help-detail'
36-
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'
3736

3837
const App = () => {
3938
return (
Lines changed: 239 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
1+
import { TCardInput, useCardInputSchema } from '@/lib/schema/card-input'
2+
import { zodResolver } from '@hookform/resolvers/zod'
3+
import _ from 'lodash'
4+
import { Plus, X } from 'lucide-react'
5+
import { useFieldArray, useForm, useWatch } from 'react-hook-form'
6+
import { useTranslation } from 'react-i18next'
7+
import {
8+
Button,
9+
Form,
10+
FormControl,
11+
FormField,
12+
FormItem,
13+
FormLabel,
14+
FormMessage,
15+
Input,
16+
Select,
17+
SelectContent,
18+
SelectItem,
19+
SelectTrigger,
20+
SelectValue,
21+
} from '../ui'
22+
import InputImage from '../ui/input-image'
23+
24+
type Props = {
25+
id?: string
26+
27+
onSubmit?: (data: TCardInput) => void
28+
defaultValue?: TCardInput
29+
}
30+
31+
export const CardForm = ({
32+
defaultValue,
33+
id = 'card-form',
34+
onSubmit,
35+
}: Props) => {
36+
const schema = useCardInputSchema()
37+
const { t } = useTranslation(['forms', 'flowDetail'])
38+
const form = useForm<TCardInput>({
39+
resolver: zodResolver(schema),
40+
mode: 'onChange',
41+
defaultValues: defaultValue,
42+
})
43+
44+
const { fields, append, remove } = useFieldArray({
45+
name: 'buttons',
46+
control: form.control,
47+
})
48+
49+
const buttonsWatch = useWatch({
50+
control: form.control,
51+
name: 'buttons',
52+
})
53+
54+
const handleAddButton = () => {
55+
form.trigger('buttons')
56+
57+
if (
58+
!_.isEmpty(form.formState.errors.buttons) ||
59+
buttonsWatch?.some((field) => !field.label || !field.value)
60+
)
61+
return
62+
63+
append({
64+
label: '',
65+
value: '',
66+
type: 'url',
67+
})
68+
}
69+
70+
const handleSubmit = (data: TCardInput) => {
71+
onSubmit?.(data)
72+
}
73+
74+
return (
75+
<Form {...form}>
76+
<form
77+
className='space-y-3'
78+
id={id}
79+
onSubmit={form.handleSubmit(handleSubmit)}
80+
>
81+
<FormField
82+
control={form.control}
83+
name='title'
84+
render={({ field }) => {
85+
return (
86+
<FormItem>
87+
<FormLabel required>{t('card_title.label')}</FormLabel>
88+
<FormControl>
89+
<Input {...field} placeholder={t('card_title.placeholder')} />
90+
</FormControl>
91+
<FormMessage />
92+
</FormItem>
93+
)
94+
}}
95+
/>
96+
<FormField
97+
control={form.control}
98+
name='subtitle'
99+
render={({ field }) => {
100+
return (
101+
<FormItem>
102+
<FormLabel required>{t('card_subtitle.label')}</FormLabel>
103+
<FormControl>
104+
<Input
105+
{...field}
106+
placeholder={t('card_subtitle.placeholder')}
107+
/>
108+
</FormControl>
109+
<FormMessage />
110+
</FormItem>
111+
)
112+
}}
113+
/>
114+
<FormField
115+
control={form.control}
116+
name='imageUrl'
117+
render={({ field }) => {
118+
return (
119+
<FormItem>
120+
<FormLabel>{t('card_image_url.label')}</FormLabel>
121+
<FormControl>
122+
<InputImage
123+
defaultValue={field.value}
124+
value={field.value}
125+
onChange={field.onChange}
126+
toServer
127+
size={80}
128+
/>
129+
</FormControl>
130+
<FormMessage />
131+
</FormItem>
132+
)
133+
}}
134+
/>
135+
136+
<div className='space-y-2'>
137+
<div className='flex items-center justify-between'>
138+
<span>Buttons</span>
139+
<Button
140+
variant='outline'
141+
className='p-0 w-6 h-6'
142+
type='button'
143+
onClick={handleAddButton}
144+
disabled={fields.length >= 3}
145+
>
146+
<Plus className='w-4 h-4' />
147+
</Button>
148+
</div>
149+
{fields.length > 0 ? (
150+
fields.map((field, index) => {
151+
return (
152+
<div key={field.id} className='flex gap-3'>
153+
<FormField
154+
name={`buttons.${index}.label`}
155+
control={form.control}
156+
render={({ field }) => {
157+
return (
158+
<FormItem className='w-full'>
159+
<FormControl>
160+
<Input
161+
{...field}
162+
autoComplete='off'
163+
placeholder={t('button_label.placeholder')}
164+
/>
165+
</FormControl>
166+
<FormMessage />
167+
</FormItem>
168+
)
169+
}}
170+
/>
171+
<FormField
172+
name={`buttons.${index}.value`}
173+
control={form.control}
174+
render={({ field }) => {
175+
return (
176+
<FormItem className='w-full'>
177+
<FormControl>
178+
<Input
179+
{...field}
180+
autoComplete='off'
181+
placeholder={t('button_value.placeholder')}
182+
/>
183+
</FormControl>
184+
<FormMessage />
185+
</FormItem>
186+
)
187+
}}
188+
/>
189+
<FormField
190+
name={`buttons.${index}.type`}
191+
control={form.control}
192+
render={({ field }) => {
193+
return (
194+
<FormItem className='w-24 flex-shrink-0'>
195+
<Select
196+
onValueChange={field.onChange}
197+
defaultValue={field.value}
198+
>
199+
<FormControl>
200+
<SelectTrigger>
201+
<SelectValue />
202+
</SelectTrigger>
203+
</FormControl>
204+
<SelectContent>
205+
{['url', 'postback'].map((type) => (
206+
<SelectItem key={type} value={type}>
207+
{type}
208+
</SelectItem>
209+
))}
210+
</SelectContent>
211+
</Select>
212+
<FormMessage />
213+
</FormItem>
214+
)
215+
}}
216+
/>
217+
<Button
218+
size='icon'
219+
onClick={() => {
220+
remove(index)
221+
}}
222+
variant='destructive'
223+
className='flex-shrink-0'
224+
>
225+
<X />
226+
</Button>
227+
</div>
228+
)
229+
})
230+
) : (
231+
<p className='flex items-center justify-center text-center text-sm text-muted-foreground'>
232+
{t('flowDetail:empty_buttons')}
233+
</p>
234+
)}
235+
</div>
236+
</form>
237+
</Form>
238+
)
239+
}

client/src/components/forms/channel.tsx

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,14 @@
1+
import { useDidUpdate } from '@/hooks/use-did-update'
2+
import { useErrorsLngChange } from '@/hooks/use-errors-lng-change'
3+
import { queryChannelTypesOption } from '@/lib/query-options/channel'
4+
import { queryFlowsForSelectOption } from '@/lib/query-options/flow'
5+
import { TChannelInput, useChannelSchema } from '@/lib/schema/channel'
6+
import { ChannelType } from '@/types/channel'
7+
import { zodResolver } from '@hookform/resolvers/zod'
8+
import { useQuery } from '@tanstack/react-query'
9+
import { useMemo } from 'react'
110
import { useForm } from 'react-hook-form'
11+
import { useTranslation } from 'react-i18next'
212
import {
313
Form,
414
FormControl,
@@ -15,16 +25,6 @@ import {
1525
SelectValue,
1626
Switch,
1727
} from '../ui'
18-
import { TChannelInput, useChannelSchema } from '@/lib/schema/channel'
19-
import { useErrorsLngChange } from '@/hooks/use-errors-lng-change'
20-
import { useTranslation } from 'react-i18next'
21-
import { useQuery } from '@tanstack/react-query'
22-
import { queryChannelTypesOption } from '@/lib/query-options/channel'
23-
import { zodResolver } from '@hookform/resolvers/zod'
24-
import { ChannelType } from '@/types/channel'
25-
import { useMemo } from 'react'
26-
import { useDidUpdate } from '@/hooks/use-did-update'
27-
import { queryFlowsForSelectOption } from '@/lib/query-options/flow'
2828

2929
type Props = {
3030
id?: string
@@ -138,13 +138,12 @@ const ChannelForm = ({
138138
render={({ field }) => (
139139
<FormItem>
140140
<FormLabel>
141-
<Label>{t('active.label')}</Label>
141+
<Label>{t('flow.label')}</Label>
142142
</FormLabel>
143-
144143
<Select onValueChange={field.onChange} defaultValue={field.value}>
145144
<FormControl>
146145
<SelectTrigger>
147-
<SelectValue placeholder='Select a verified email to display' />
146+
<SelectValue placeholder={t('flow.placeholder')} />
148147
</SelectTrigger>
149148
</FormControl>
150149
<SelectContent>

0 commit comments

Comments
 (0)