gitscope
← marzneshin / v0.3.1 / dashboard/src/features/subscription-settings/form/form.tsx
https://dev.kronoz.win/r/marzneshin.git
dashboard/src/features/subscription-settings/form/form.tsx · TypeScript
Blame Raw
  1import { zodResolver } from "@hookform/resolvers/zod";
  2import { useFieldArray, useForm } from "react-hook-form";
  3import { useTranslation } from "react-i18next";
  4import { schema } from "./schema";
  5import { RuleItem } from "./rule-item";
  6import {
  7    HStack,
  8    Button,
  9    Form,
 10    Sortable,
 11    ScrollArea,
 12    FormLabel,
 13    Separator,
 14    Awaiting,
 15} from "@marzneshin/components";
 16import { Schema } from "./schema"
 17import { Overlay } from "./overlay"
 18import {
 19    TemplateOnAcceptanceField,
 20    ProfileTitleField,
 21    SupportLinkField,
 22    UpdateIntervalField,
 23    PlaceholderRemarkField,
 24    PlaceholderIfDisabledField,
 25    ShuffleConfigsField
 26} from "./fields";
 27import { NoRulesAlert } from "./no-rules-alert";
 28import {
 29    useSubscriptionSettingsQuery,
 30    useSubscriptionSettingsMutation,
 31} from "@marzneshin/features/subscription-settings";
 32import { useEffect, useCallback } from "react";
 33
 34export function SubscriptionRulesForm() {
 35    const { t } = useTranslation()
 36    const { data, isFetching } = useSubscriptionSettingsQuery()
 37    const subscriptionSettings = useSubscriptionSettingsMutation()
 38    const form = useForm<Schema>({
 39        resolver: zodResolver(schema),
 40        defaultValues: data,
 41    })
 42
 43    const handleResetLocalChanges = useCallback(
 44        () => {
 45            form.reset(data)
 46        },
 47        [form, data],
 48    )
 49
 50    const handleSubscriptionRulesDataUpdate = useCallback(
 51        () => {
 52            form.reset(data, {
 53                keepDirtyValues: true
 54            })
 55        },
 56        [form, data],
 57    )
 58
 59    useEffect(() => {
 60        if (data) {
 61            handleSubscriptionRulesDataUpdate()
 62        }
 63    }, [data, handleSubscriptionRulesDataUpdate])
 64
 65    const onSubmit = (data: Schema) => {
 66        subscriptionSettings.mutate(data)
 67    }
 68
 69    const { fields, append, move, remove } = useFieldArray({
 70        control: form.control,
 71        name: "rules"
 72    })
 73
 74    return (
 75        <Form {...form}>
 76            <form
 77                onSubmit={form.handleSubmit(onSubmit)}
 78                className="flex w-full max-w-4xl flex-col gap-2"
 79            >
 80                <ProfileTitleField />
 81                <div className="md:grid grid-cols-2 gap-2 flex flex-col">
 82                    <UpdateIntervalField />
 83                    <SupportLinkField />
 84                </div>
 85                <TemplateOnAcceptanceField />
 86                <PlaceholderRemarkField />
 87                <PlaceholderIfDisabledField />
 88                <ShuffleConfigsField />
 89                <Separator className="my-3" />
 90                <h4 className="text-lg mt-2">
 91                    {t("page.settings.subscription-settings.subscription-title")}
 92                </h4>
 93                <p className="text-sm text-muted-foreground">
 94                    {t("page.settings.subscription-settings.subscription-desc")}
 95                </p>
 96                <Awaiting
 97                    isFetching={isFetching}
 98                    Skeleton={
 99                        <>
100                            <Overlay />
101                            <Overlay />
102                            <Overlay />
103                            <Overlay />
104                        </>
105                    }
106                    isNotFound={fields.length === 0}
107                    NotFound={<NoRulesAlert />}
108                    Component={
109                        <div className="space-y-1">
110                            <Sortable
111                                value={fields}
112                                onMove={({ activeIndex, overIndex }) =>
113                                    move(activeIndex, overIndex)
114                                }
115                            >
116                                <div className="grid grid-cols-[2fr,1.3fr,0.25fr,0.25fr] items-center justify-start gap-2 my-2">
117                                    <FormLabel>
118                                        {t("pattern")}
119                                    </FormLabel>
120                                    <FormLabel>
121                                        {t("result")}
122                                    </FormLabel>
123                                </div>
124                                <ScrollArea className="flex flex-col w-full max-h-[400px] gap-2" type="always">
125                                    {fields.map((field, index) => (
126                                        <RuleItem
127                                            field={field}
128                                            index={index}
129                                            onRemove={remove} />
130                                    ))}
131                                </ScrollArea>
132                            </Sortable>
133                        </div>
134                    }
135                />
136                <HStack className="w-full flex-end">
137                    <Button
138                        type="button"
139                        variant="destructive"
140                        className="w-fit"
141                        onMouseDown={handleResetLocalChanges}
142                    >
143                        {t("page.settings.subscription-settings.reset-local-changes")}
144                    </Button>
145                    <Button
146                        type="button"
147                        variant="outline"
148                        className="w-fit"
149                        onClick={() =>
150                            append({
151                                pattern: "",
152                                result: "block",
153                            })
154                        }
155                    >
156                        {t("page.settings.subscription-settings.add-rule")}
157                    </Button>
158                    <Button type="submit" className="w-fit">
159                        {t("submit")}
160                    </Button>
161                </HStack>
162            </form>
163        </Form>
164    )
165}