Skip to content

Commit e88fe33

Browse files
committed
feat: settings general api
1 parent 407dc43 commit e88fe33

18 files changed

+507
-582
lines changed

apps/mochi-web/components/settings/general/DefaultMessage.tsx

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,34 +7,25 @@ import {
77
} from '@mochi-ui/core'
88
import { EditLine, TrashBinLine } from '@mochi-ui/icons'
99
import React from 'react'
10-
import {
11-
Control,
12-
Controller,
13-
UseFormWatch,
14-
useFieldArray,
15-
} from 'react-hook-form'
10+
import { Controller, useFieldArray, useFormContext } from 'react-hook-form'
1611
import { actionList } from '~constants/settings'
17-
import { GeneralFormValue } from './types'
12+
import { ResponseGeneralSettingData } from '~types/mochi-schema'
1813
import { MessageModal } from './MessageModal'
1914

20-
interface Props {
21-
control: Control<GeneralFormValue>
22-
watch: UseFormWatch<GeneralFormValue>
23-
}
24-
25-
export const DefaultMessage = ({ control, watch }: Props) => {
15+
export const DefaultMessage = () => {
16+
const { control, watch } = useFormContext<ResponseGeneralSettingData>()
2617
const { fields, append, remove, update } = useFieldArray({
2718
control,
28-
name: 'defaultMessage',
19+
name: 'payment.default_message_settings',
2920
})
30-
const enableDefaultMessage = watch('enableDefaultMessage')
21+
const enableDefaultMessage = watch('payment.default_message_enable')
3122

3223
return (
3324
<div className="flex flex-col w-full max-w-md space-y-2">
3425
<div className="flex items-center justify-between">
3526
<FormLabel>Default message</FormLabel>
3627
<Controller
37-
name="enableDefaultMessage"
28+
name="payment.default_message_enable"
3829
control={control}
3930
render={({ field: { value, onChange, ...rest } }) => (
4031
<Switch
@@ -48,7 +39,7 @@ export const DefaultMessage = ({ control, watch }: Props) => {
4839
{(enableDefaultMessage ? fields : []).map((each, index) => (
4940
<Controller
5041
key={each.id}
51-
name={`defaultMessage.${index}`}
42+
name={`payment.default_message_settings.${index}`}
5243
control={control}
5344
render={({ field }) => (
5445
<div className="flex items-center border rounded-md border-divider shadow-input">
Lines changed: 135 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,32 @@
1-
import { apiLogout } from '~constants/api'
1+
import { API, GET_PATHS, apiLogout } from '~constants/api'
22
import { api } from '~constants/mochi'
3-
import { Button, Separator, Typography, useLoginWidget } from '@mochi-ui/core'
3+
import {
4+
ActionBar,
5+
ActionBarActionGroup,
6+
ActionBarBody,
7+
ActionBarCancelButton,
8+
ActionBarConfirmButton,
9+
ActionBarContent,
10+
ActionBarDescription,
11+
ActionBarIcon,
12+
Button,
13+
Separator,
14+
Typography,
15+
toast,
16+
useLoginWidget,
17+
} from '@mochi-ui/core'
418
import { useRouter } from 'next/router'
5-
import React from 'react'
19+
import React, { useEffect } from 'react'
620
import { FormProvider, useForm } from 'react-hook-form'
721
import { ROUTES } from '~constants/routes'
8-
import { platformGroupList, targetGroupList } from '~constants/settings'
9-
import { GeneralFormValue } from './types'
22+
import { useFetchGeneralSettings } from '~hooks/settings/useFetchGeneralSettings'
23+
import {
24+
RequestDefaultMessageSetting,
25+
RequestTxLimitSetting,
26+
RequestUpdateGeneralSettingsPayloadRequest,
27+
ResponseGeneralSettingData,
28+
ResponseUserGeneralSettingResponse,
29+
} from '~types/mochi-schema'
1030
import { MoneySource } from './MoneySource'
1131
import { ReceiverPlatform } from './ReceiverPlatform'
1232
import { TokenPriority } from './TokenPriority'
@@ -16,65 +36,94 @@ import { TransactionPrivacy } from './TransactionPrivacy'
1636
import { SocialAccountsPrivacy } from './SocialAccountsPrivacy'
1737
import { WalletsPrivacy } from './WalletsPrivacy'
1838

39+
const SETTINGS_GENERAL_FORM_ID = 'settings-general-form'
40+
1941
export const GeneralPage = () => {
20-
const form = useForm<GeneralFormValue>({
42+
const form = useForm<ResponseGeneralSettingData>({
2143
mode: 'all',
22-
defaultValues: {
23-
defaultMoneySource: 'mochi',
24-
defaultReceiverPlatform: 'discord',
25-
defaultTokenPriority: [{ id: '941f0fb1-00da-49dc-a538-5e81fc874cb4' }],
26-
transactionPrivacy: {
27-
general_target_group: targetGroupList[0].key,
28-
general_platform_group: platformGroupList[0].key,
29-
custom_settings: [],
30-
},
31-
socialAccountsPrivacy: {
32-
general_target_group: targetGroupList[0].key,
33-
general_platform_group: platformGroupList[0].key,
34-
custom_settings: [],
35-
},
36-
walletsPrivacy: {
37-
general_target_group: targetGroupList[0].key,
38-
general_platform_group: platformGroupList[0].key,
39-
custom_settings: [],
40-
},
41-
},
4244
})
43-
const { handleSubmit, control, watch } = form
45+
const {
46+
handleSubmit,
47+
reset,
48+
formState: { isSubmitting, isDirty },
49+
} = form
4450

45-
const { logout } = useLoginWidget()
51+
const { profile, logout } = useLoginWidget()
4652
const { replace } = useRouter()
53+
const { data: settings } = useFetchGeneralSettings(profile?.id)
4754

48-
const onSubmit = (data: any) => {
49-
alert(JSON.stringify(data))
55+
const onUpdateSettings = (data: ResponseGeneralSettingData) => {
56+
if (!profile?.id) return
57+
const payload: RequestUpdateGeneralSettingsPayloadRequest = {
58+
payment: {
59+
default_token: data.payment?.default_token_id || '',
60+
default_money_source: {
61+
platform: data.payment?.default_money_source?.platform || '',
62+
platform_identifier:
63+
data.payment?.default_money_source?.platform_identifier || '',
64+
},
65+
default_receiver_platform:
66+
data.payment?.default_receiver_platform || '',
67+
token_priorities:
68+
data.payment?.prioritized_token?.flatMap((each) => each.id || []) ||
69+
[],
70+
default_message_enable: data.payment?.default_message_enable || true,
71+
default_message_settings: data.payment
72+
?.default_message_settings as RequestDefaultMessageSetting[],
73+
tx_limit_enable: data.payment?.tx_limit_enable || true,
74+
tx_limit_settings: data.payment
75+
?.tx_limit_settings as RequestTxLimitSetting[],
76+
},
77+
privacy: {
78+
...data.privacy,
79+
},
80+
}
81+
return API.MOCHI.put(payload, GET_PATHS.UPDATE_GENERAL_SETTINGS(profile.id))
82+
.json((r: ResponseUserGeneralSettingResponse) => {
83+
reset(r.data)
84+
})
85+
.catch((e) => {
86+
const err = JSON.parse(e.message)
87+
toast({
88+
description: err.msg,
89+
scheme: 'danger',
90+
})
91+
})
5092
}
5193

52-
return (
53-
<>
54-
<FormProvider {...form}>
55-
<form onSubmit={handleSubmit(onSubmit)} />
56-
<div className="space-y-4">
57-
<Typography level="h6">Payment setting</Typography>
94+
useEffect(() => {
95+
if (settings) {
96+
console.log({ settings })
97+
reset(settings)
98+
}
99+
}, [reset, settings])
58100

59-
<div className="flex gap-4">
60-
<MoneySource control={control} />
61-
<ReceiverPlatform control={control} />
62-
</div>
101+
return (
102+
<FormProvider {...form}>
103+
<form
104+
id={SETTINGS_GENERAL_FORM_ID}
105+
onSubmit={handleSubmit(onUpdateSettings)}
106+
/>
107+
<div className="space-y-4">
108+
<Typography level="h6">Payment setting</Typography>
63109

64-
<TokenPriority {...{ control, watch }} />
65-
<DefaultMessage {...{ control, watch }} />
66-
<TransactionLimit {...{ control, watch }} />
110+
<div className="flex gap-4">
111+
<MoneySource />
112+
<ReceiverPlatform />
113+
</div>
67114

68-
<Separator className="w-full max-w-md" />
115+
<TokenPriority />
116+
<DefaultMessage />
117+
<TransactionLimit />
69118

70-
<Typography level="h6">Privacy</Typography>
119+
<Separator className="w-full max-w-md" />
71120

72-
<TransactionPrivacy {...{ control, watch }} />
73-
<SocialAccountsPrivacy {...{ control, watch }} />
74-
<WalletsPrivacy {...{ control, watch }} />
75-
</div>
76-
</FormProvider>
121+
<Typography level="h6">Privacy</Typography>
77122

123+
<TransactionPrivacy />
124+
<SocialAccountsPrivacy />
125+
<WalletsPrivacy />
126+
</div>
78127
<div className="mt-8">
79128
<Button
80129
variant="outline"
@@ -91,6 +140,41 @@ export const GeneralPage = () => {
91140
Log out
92141
</Button>
93142
</div>
94-
</>
143+
<div className="sticky bottom-0">
144+
<ActionBar open={isDirty}>
145+
<ActionBarContent
146+
scheme="success"
147+
outline
148+
shadow
149+
onOpenAutoFocus={(e) => e.preventDefault()}
150+
anchorClassName="left-0 right-0 -mb-8"
151+
>
152+
<ActionBarIcon />
153+
<ActionBarBody>
154+
<ActionBarDescription>
155+
Do you want to save these changes?
156+
</ActionBarDescription>
157+
</ActionBarBody>
158+
<ActionBarActionGroup>
159+
<ActionBarCancelButton
160+
disabled={isSubmitting}
161+
variant="link"
162+
onClick={() => reset()}
163+
>
164+
Reset
165+
</ActionBarCancelButton>
166+
<ActionBarConfirmButton
167+
loading={isSubmitting}
168+
type="submit"
169+
form={SETTINGS_GENERAL_FORM_ID}
170+
className="min-w-[130px]"
171+
>
172+
Save changes
173+
</ActionBarConfirmButton>
174+
</ActionBarActionGroup>
175+
</ActionBarContent>
176+
</ActionBar>
177+
</div>
178+
</FormProvider>
95179
)
96180
}

apps/mochi-web/components/settings/general/MessageModal.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,16 @@ import { Controller, useForm } from 'react-hook-form'
2222
import { zodResolver } from '@hookform/resolvers/zod'
2323
import { z } from 'zod'
2424
import { actionList } from '~constants/settings'
25-
import { Message } from './types'
25+
import { ModelDefaultMessageSetting } from '~types/mochi-schema'
2626

2727
const schema = z.object({
2828
action: z.string().min(1, 'This field is required'),
2929
message: z.string().min(1, 'This field is required'),
3030
})
3131

3232
interface Props {
33-
defaultValues?: Message
34-
onConfirm: (data: Message) => void
33+
defaultValues?: ModelDefaultMessageSetting
34+
onConfirm: (data: ModelDefaultMessageSetting) => void
3535
trigger: React.ReactNode
3636
}
3737

@@ -41,12 +41,12 @@ export const MessageModal = ({
4141
trigger,
4242
}: Props) => {
4343
const [open, setOpen] = useState(false)
44-
const { control, handleSubmit, reset } = useForm<Message>({
44+
const { control, handleSubmit, reset } = useForm<ModelDefaultMessageSetting>({
4545
defaultValues,
4646
resolver: zodResolver(schema),
4747
})
4848

49-
const onSubmit = (data: Message) => {
49+
const onSubmit = (data: ModelDefaultMessageSetting) => {
5050
setOpen(false)
5151
onConfirm(data)
5252
}

apps/mochi-web/components/settings/general/MoneySource.tsx

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { truncate } from '@dwarvesf/react-utils'
12
import {
23
Button,
34
FormControl,
@@ -9,31 +10,39 @@ import {
910
SelectSeparator,
1011
SelectTrigger,
1112
SelectValue,
13+
useLoginWidget,
1214
} from '@mochi-ui/core'
1315
import { PlusLine } from '@mochi-ui/icons'
14-
import { Control, Controller } from 'react-hook-form'
15-
import { GeneralFormValue } from './types'
16+
import { Controller, useFormContext } from 'react-hook-form'
17+
import { ResponseGeneralSettingData } from '~types/mochi-schema'
18+
import { getPlatform } from '~utils/platform'
1619

17-
interface Props {
18-
control: Control<GeneralFormValue>
19-
}
20+
export const MoneySource = () => {
21+
const { profile } = useLoginWidget()
22+
const { control } = useFormContext<ResponseGeneralSettingData>()
2023

21-
export const MoneySource = ({ control }: Props) => {
2224
return (
2325
<Controller
24-
name="defaultMoneySource"
26+
name="payment.default_money_source.platform_identifier"
2527
control={control}
2628
render={({ field, fieldState }) => (
2729
<FormControl error={!!fieldState.error} className="min-w-[160px]">
2830
<FormLabel>Default money source</FormLabel>
2931
<Select {...field}>
3032
<SelectTrigger className="justify-between h-10 border border-divider">
31-
<SelectValue placeholder="Mochi wallet" />
33+
<SelectValue />
3234
</SelectTrigger>
3335
<SelectContent>
3436
<SelectItem value="mochi">Mochi wallet</SelectItem>
35-
<SelectItem value="evm">EVM | 0xfsf...few</SelectItem>
36-
<SelectItem value="sol">SOL | 0xfsf...few</SelectItem>
37+
{profile?.associated_accounts?.map((each) => (
38+
<SelectItem
39+
key={each.platform_identifier}
40+
value={each.platform_identifier}
41+
>
42+
{getPlatform(each.platform).name} |{' '}
43+
{truncate(each.platform_identifier, 10, true)}
44+
</SelectItem>
45+
))}
3746
<SelectSeparator />
3847
<Button variant="ghost" className="w-full pl-2 pr-2 h-9">
3948
<PlusLine className="w-4 h-4" />

0 commit comments

Comments
 (0)