1import { FC, useCallback, useEffect, useState } from "react";
2import {
3 DialogTitle,
4 DialogContent,
5 Dialog,
6 DialogHeader,
7 Form,
8 Button,
9 Tabs,
10 TabsTrigger,
11 TabsContent,
12 FormLabel
13} from '@marzneshin/components';
14import { useTranslation } from 'react-i18next';
15import {
16 DATA_LIMIT_METRIC,
17 UserMutationType,
18 useUsersCreationMutation,
19 useUsersUpdateMutation
20} from "@marzneshin/features/users";
21import { UserSchema } from "./schema";
22import {
23 UsernameField,
24 DataLimitField,
25 ExpireDateField,
26 DataLimitResetStrategyField,
27 NoteField,
28 ServicesField,
29} from "./fields";
30import { useMutationDialog } from "@marzneshin/hooks";
31import { TabsList } from "@radix-ui/react-tabs";
32import { OnHoldExpireDurationField } from "./fields/onhold-expire-duration";
33import { OnHoldTimeoutField } from "./fields/onhold-timeout";
34
35interface UsersMutationDialogProps {
36 entity: UserMutationType | null;
37 open: boolean;
38 onOpenChange: (state: boolean) => void;
39}
40
41export const UsersMutationDialog: FC<UsersMutationDialogProps> = ({
42 entity,
43 open,
44 onOpenChange,
45}) => {
46 const { t } = useTranslation();
47 const getDefaultValues = useCallback((): UserMutationType => ({
48 services: [],
49 data_limit: 1,
50 expire: null,
51 username: '',
52 data_limit_reset_strategy: 'no_reset',
53 status: 'active',
54 note: '',
55 on_hold_expire_duration: 0,
56 on_hold_timeout: undefined,
57 }), []);
58
59 const { form, handleSubmit } = useMutationDialog({
60 entity,
61 onOpenChange,
62 createMutation: useUsersCreationMutation(),
63 updateMutation: useUsersUpdateMutation(),
64 schema: UserSchema,
65 getDefaultValue: getDefaultValues,
66 loadFormtter: (d) => ({ ...d, data_limit: (d.data_limit ? d.data_limit : 0) / DATA_LIMIT_METRIC })
67 })
68
69 const [
70 selectedDataLimitTab,
71 setSelectedDataLimitTab
72 ] = useState<'limited' | 'unlimited' | string>('limited');
73 useEffect(() => {
74 if (selectedDataLimitTab === 'limited') {
75 form.setValue("data_limit", 1)
76 form.setValue("data_limit_reset_strategy", "no_reset");
77 } else {
78 form.setValue("data_limit", 0)
79 form.setValue("data_limit_reset_strategy", "no_reset");
80 }
81 }, [selectedDataLimitTab, form]);
82
83 const getUserExpirationMethod = useCallback((entity: UserMutationType) => {
84 if (entity.status === "on_hold")
85 return 'onhold'
86 else if (entity.expire !== undefined)
87 return 'determined'
88 else
89 return 'unlimited'
90 }, [])
91
92 const defaultExpirationMethodTab = entity?.username ? getUserExpirationMethod(entity) : 'determined'
93 const [
94 selectedExpirationMethodTab,
95 setSelectedExpirationMethodTab
96 ] = useState<'determined' | 'onhold' | 'unlimited' | string>(defaultExpirationMethodTab);
97
98 useEffect(() => {
99 form.setValue("status", "active")
100 if (selectedExpirationMethodTab === 'onhold') {
101 form.setValue("status", "on_hold")
102 form.setValue("expire", undefined);
103 form.clearErrors("expire");
104 } else if (selectedExpirationMethodTab === "unlimited") {
105 form.setValue("expire", undefined);
106 form.setValue("on_hold_expire_duration", undefined);
107 form.setValue("on_hold_timeout", undefined);
108 form.clearErrors("expire");
109 form.clearErrors("on_hold_expire_duration");
110 form.clearErrors("on_hold_timeout");
111 } else {
112 form.setValue("on_hold_expire_duration", 0);
113 form.setValue("on_hold_timeout", null);
114 form.clearErrors("on_hold_expire_duration");
115 form.clearErrors("on_hold_timeout");
116 }
117 }, [selectedExpirationMethodTab, form]);
118
119 return (
120 <Dialog open={open} onOpenChange={onOpenChange} defaultOpen={true}>
121 <DialogContent className="sm:max-w-full md:max-w-[600px]">
122 <DialogHeader>
123 <DialogTitle className="text-primary">
124 {entity
125 ? t('page.users.dialogs.edition.title')
126 : t('page.users.dialogs.creation.title')}
127 </DialogTitle>
128 </DialogHeader>
129 <Form {...form}>
130 <form onSubmit={handleSubmit}>
131 <div className="flex-col grid-cols-2 gap-2 sm:flex md:grid">
132 <div>
133 <UsernameField />
134 <FormLabel>
135 {t('page.users.data_limit_method')}
136 </FormLabel>
137 <div className="flex gap-2 items-center w-full sm:flex-row md:flex-col">
138 <Tabs defaultValue="limited" onValueChange={setSelectedDataLimitTab} className="mt-2 w-full">
139 <TabsList className="flex flex-row items-center p-1 w-full rounded-md bg-accent">
140 <TabsTrigger
141 className="w-full"
142 value="limited">
143 {t('page.users.limited')}
144 </TabsTrigger>
145 <TabsTrigger
146 className="w-full"
147 value="unlimited">
148 {t('page.users.unlimited')}
149 </TabsTrigger>
150 </TabsList>
151 <TabsContent value="limited">
152 <DataLimitField />
153 {form.watch().data_limit !== 0 && <DataLimitResetStrategyField />}
154 </TabsContent>
155 </Tabs>
156 </div>
157 <FormLabel>
158 {t('page.users.expire_method')}
159 </FormLabel>
160 <Tabs defaultValue={defaultExpirationMethodTab} onValueChange={setSelectedExpirationMethodTab} className="mt-2 w-full">
161 <TabsList className="flex flex-row items-center p-1 w-full rounded-md bg-accent">
162 <TabsTrigger
163 className="w-full"
164 value="determined">
165 {t('page.users.determined_expire')}
166 </TabsTrigger>
167 <TabsTrigger
168 className="w-full"
169 value="onhold">
170 {t('page.users.onhold_expire')}
171 </TabsTrigger>
172 <TabsTrigger
173 className="w-full"
174 value="unlimited">
175 {t('page.users.unlimited')}
176 </TabsTrigger>
177 </TabsList>
178 <TabsContent value="determined">
179 <ExpireDateField />
180 </TabsContent>
181 <TabsContent value="onhold">
182 <OnHoldExpireDurationField />
183 <OnHoldTimeoutField />
184 </TabsContent>
185 </Tabs>
186 <NoteField />
187 </div>
188 <div>
189 <ServicesField />
190 </div>
191 </div>
192 <Button
193 className="mt-3 w-full font-semibold"
194 type="submit"
195 disabled={form.formState.isSubmitting}
196 >
197 {t('submit')}
198 </Button>
199 </form>
200 </Form>
201 </DialogContent>
202 </Dialog>
203 );
204};