diff --git a/dashboard/public/locales/en.json b/dashboard/public/locales/en.json
@@ -39,6 +39,7 @@
"disable": "Disable",
"close": "Close",
"save": "Save",
+ "day": "Day",
"page": {
"settings": {
"certificate": {
diff --git a/dashboard/public/locales/kur.json b/dashboard/public/locales/kur.json
@@ -32,6 +32,7 @@
"disable": "Naçalakî ke",
"close": "Dayixe",
"save": "Seyv Bike",
+ "day": "Roj",
"page": {
"settings": {
"certificate": {
diff --git a/dashboard/src/features/users/dialogs/mutation/fields/data-limit.tsx b/dashboard/src/features/users/dialogs/mutation/fields/data-limit.tsx
@@ -21,7 +21,7 @@ export const DataLimitField: FC<DataLimitFieldProps> = () => {
name="data_limit"
render={({ field }) => (
<FormItem className="w-full">
- <FormLabel>{t('page.users.data_limit')}</FormLabel>
+ <FormLabel>{t('page.users.data_limit')} (GB)</FormLabel>
<FormControl>
<Input type="number" className="order-1" {...field} />
</FormControl>
diff --git a/dashboard/src/features/users/dialogs/mutation/fields/index.ts b/dashboard/src/features/users/dialogs/mutation/fields/index.ts
@@ -4,3 +4,5 @@ export * from "./note"
export * from "./services"
export * from "./data-limit-reset-strategy"
export * from "./username"
+export * from "./onhold-timeout"
+export * from "./onhold-expire-duration"
diff --git a/dashboard/src/features/users/dialogs/mutation/fields/onhold-expire-duration.tsx b/dashboard/src/features/users/dialogs/mutation/fields/onhold-expire-duration.tsx
@@ -27,7 +27,7 @@ export const OnHoldExpireDurationField: FC<OnHoldExpireDurationFieldProps> = ()
name="on_hold_expire_duration"
render={({ field }) => (
<FormItem>
- <FormLabel>{t('page.users.on_hold_expire_duration')}</FormLabel>
+ <FormLabel>{t('page.users.on_hold_expire_duration')} ({t('day')})</FormLabel>
<FormControl>
<Input
type="number"
diff --git a/dashboard/src/features/users/dialogs/mutation/index.tsx b/dashboard/src/features/users/dialogs/mutation/index.tsx
@@ -1,4 +1,4 @@
-import { FC, useCallback, useEffect, useState } from "react";
+import { FC, useCallback } from "react";
import {
DialogTitle,
DialogContent,
@@ -6,10 +6,6 @@ import {
DialogHeader,
Form,
Button,
- Tabs,
- TabsTrigger,
- TabsContent,
- FormLabel
} from '@marzneshin/components';
import { useTranslation } from 'react-i18next';
import {
@@ -21,16 +17,11 @@ import {
import { UserSchema } from "./schema";
import {
UsernameField,
- DataLimitField,
- ExpireDateField,
- DataLimitResetStrategyField,
NoteField,
ServicesField,
} from "./fields";
import { useMutationDialog } from "@marzneshin/hooks";
-import { TabsList } from "@radix-ui/react-tabs";
-import { OnHoldExpireDurationField } from "./fields/onhold-expire-duration";
-import { OnHoldTimeoutField } from "./fields/onhold-timeout";
+import { DataLimitFields, ExpirationMethodFields } from "./sections";
interface UsersMutationDialogProps {
entity: UserMutationType | null;
@@ -66,56 +57,6 @@ export const UsersMutationDialog: FC<UsersMutationDialogProps> = ({
loadFormtter: (d) => ({ ...d, data_limit: (d.data_limit ? d.data_limit : 0) / DATA_LIMIT_METRIC })
})
- const [
- selectedDataLimitTab,
- setSelectedDataLimitTab
- ] = useState<'limited' | 'unlimited' | string>('limited');
- useEffect(() => {
- if (selectedDataLimitTab === 'limited') {
- form.setValue("data_limit", 1)
- form.setValue("data_limit_reset_strategy", "no_reset");
- } else {
- form.setValue("data_limit", 0)
- form.setValue("data_limit_reset_strategy", "no_reset");
- }
- }, [selectedDataLimitTab, form]);
-
- const getUserExpirationMethod = useCallback((entity: UserMutationType) => {
- if (entity.status === "on_hold")
- return 'onhold'
- else if (entity.expire !== undefined)
- return 'determined'
- else
- return 'unlimited'
- }, [])
-
- const defaultExpirationMethodTab = entity?.username ? getUserExpirationMethod(entity) : 'determined'
- const [
- selectedExpirationMethodTab,
- setSelectedExpirationMethodTab
- ] = useState<'determined' | 'onhold' | 'unlimited' | string>(defaultExpirationMethodTab);
-
- useEffect(() => {
- form.setValue("status", "active")
- if (selectedExpirationMethodTab === 'onhold') {
- form.setValue("status", "on_hold")
- form.setValue("expire", undefined);
- form.clearErrors("expire");
- } else if (selectedExpirationMethodTab === "unlimited") {
- form.setValue("expire", undefined);
- form.setValue("on_hold_expire_duration", undefined);
- form.setValue("on_hold_timeout", undefined);
- form.clearErrors("expire");
- form.clearErrors("on_hold_expire_duration");
- form.clearErrors("on_hold_timeout");
- } else {
- form.setValue("on_hold_expire_duration", 0);
- form.setValue("on_hold_timeout", null);
- form.clearErrors("on_hold_expire_duration");
- form.clearErrors("on_hold_timeout");
- }
- }, [selectedExpirationMethodTab, form]);
-
return (
<Dialog open={open} onOpenChange={onOpenChange} defaultOpen={true}>
<DialogContent className="sm:max-w-full md:max-w-[600px]">
@@ -131,58 +72,8 @@ export const UsersMutationDialog: FC<UsersMutationDialogProps> = ({
<div className="flex-col grid-cols-2 gap-2 sm:flex md:grid">
<div>
<UsernameField />
- <FormLabel>
- {t('page.users.data_limit_method')}
- </FormLabel>
- <div className="flex gap-2 items-center w-full sm:flex-row md:flex-col">
- <Tabs defaultValue="limited" onValueChange={setSelectedDataLimitTab} className="mt-2 w-full">
- <TabsList className="flex flex-row items-center p-1 w-full rounded-md bg-accent">
- <TabsTrigger
- className="w-full"
- value="limited">
- {t('page.users.limited')}
- </TabsTrigger>
- <TabsTrigger
- className="w-full"
- value="unlimited">
- {t('page.users.unlimited')}
- </TabsTrigger>
- </TabsList>
- <TabsContent value="limited">
- <DataLimitField />
- {form.watch().data_limit !== 0 && <DataLimitResetStrategyField />}
- </TabsContent>
- </Tabs>
- </div>
- <FormLabel>
- {t('page.users.expire_method')}
- </FormLabel>
- <Tabs defaultValue={defaultExpirationMethodTab} onValueChange={setSelectedExpirationMethodTab} className="mt-2 w-full">
- <TabsList className="flex flex-row items-center p-1 w-full rounded-md bg-accent">
- <TabsTrigger
- className="w-full"
- value="determined">
- {t('page.users.determined_expire')}
- </TabsTrigger>
- <TabsTrigger
- className="w-full"
- value="onhold">
- {t('page.users.onhold_expire')}
- </TabsTrigger>
- <TabsTrigger
- className="w-full"
- value="unlimited">
- {t('page.users.unlimited')}
- </TabsTrigger>
- </TabsList>
- <TabsContent value="determined">
- <ExpireDateField />
- </TabsContent>
- <TabsContent value="onhold">
- <OnHoldExpireDurationField />
- <OnHoldTimeoutField />
- </TabsContent>
- </Tabs>
+ <DataLimitFields />
+ <ExpirationMethodFields entity={entity} />
<NoteField />
</div>
<div>
diff --git a/dashboard/src/features/users/dialogs/mutation/sections/data-limit.tsx b/dashboard/src/features/users/dialogs/mutation/sections/data-limit.tsx
@@ -0,0 +1,64 @@
+
+import { FC, useEffect, useState } from "react";
+import {
+ Tabs,
+ TabsTrigger,
+ TabsContent,
+ FormLabel
+} from '@marzneshin/components';
+import { useTranslation } from 'react-i18next';
+import {
+ DataLimitField,
+ DataLimitResetStrategyField,
+} from "../fields";
+import { TabsList } from "@radix-ui/react-tabs";
+import { useFormContext } from 'react-hook-form';
+
+export const DataLimitFields: FC = () => {
+ const form = useFormContext()
+
+ const { t } = useTranslation()
+ const [
+ selectedDataLimitTab,
+ setSelectedDataLimitTab
+ ] = useState<'limited' | 'unlimited' | string>('limited');
+ useEffect(() => {
+ if (selectedDataLimitTab === 'limited') {
+ form.setValue("data_limit", 1)
+ form.setValue("data_limit_reset_strategy", "no_reset");
+ } else {
+ form.setValue("data_limit", 0)
+ form.setValue("data_limit_reset_strategy", "no_reset");
+ }
+ // eslint-disable-next-line
+ }, [selectedDataLimitTab]);
+
+ return (
+ <>
+
+ <FormLabel>
+ {t('page.users.data_limit_method')}
+ </FormLabel>
+ <div className="flex gap-2 items-center w-full sm:flex-row md:flex-col">
+ <Tabs defaultValue="limited" onValueChange={setSelectedDataLimitTab} className="mt-2 w-full">
+ <TabsList className="flex flex-row items-center p-1 w-full rounded-md bg-accent">
+ <TabsTrigger
+ className="w-full"
+ value="limited">
+ {t('page.users.limited')}
+ </TabsTrigger>
+ <TabsTrigger
+ className="w-full"
+ value="unlimited">
+ {t('page.users.unlimited')}
+ </TabsTrigger>
+ </TabsList>
+ <TabsContent value="limited">
+ <DataLimitField />
+ {form.watch().data_limit !== 0 && <DataLimitResetStrategyField />}
+ </TabsContent>
+ </Tabs>
+ </div>
+ </>
+ )
+}
diff --git a/dashboard/src/features/users/dialogs/mutation/sections/expiration-method.tsx b/dashboard/src/features/users/dialogs/mutation/sections/expiration-method.tsx
@@ -0,0 +1,62 @@
+import { FC } from "react";
+import {
+ Tabs,
+ TabsTrigger,
+ TabsContent,
+ FormLabel
+} from '@marzneshin/components';
+import {
+ UserMutationType,
+} from "@marzneshin/features/users";
+import {
+ ExpireDateField,
+ OnHoldTimeoutField,
+ OnHoldExpireDurationField,
+} from "../fields";
+import { TabsList } from "@radix-ui/react-tabs";
+import { useTranslation } from "react-i18next";
+import { useExpirationMethodTabs } from "./use-expiration-method-tabs";
+
+interface ExpirationMethodProps {
+ entity: UserMutationType | null
+}
+
+
+export const ExpirationMethodFields: FC<ExpirationMethodProps> = ({ entity }) => {
+ const { t } = useTranslation()
+ const { setSelectedExpirationMethodTab, defaultExpirationMethodTab } = useExpirationMethodTabs({ entity })
+
+ return (
+ <>
+ <FormLabel>
+ {t('page.users.expire_method')}
+ </FormLabel>
+ <Tabs defaultValue={defaultExpirationMethodTab} onValueChange={setSelectedExpirationMethodTab} className="mt-2 w-full">
+ <TabsList className="flex flex-row items-center p-1 w-full rounded-md bg-accent">
+ <TabsTrigger
+ className="w-full"
+ value="determined">
+ {t('page.users.determined_expire')}
+ </TabsTrigger>
+ <TabsTrigger
+ className="w-full"
+ value="onhold">
+ {t('page.users.onhold_expire')}
+ </TabsTrigger>
+ <TabsTrigger
+ className="w-full"
+ value="unlimited">
+ {t('page.users.unlimited')}
+ </TabsTrigger>
+ </TabsList>
+ <TabsContent value="determined">
+ <ExpireDateField />
+ </TabsContent>
+ <TabsContent value="onhold">
+ <OnHoldExpireDurationField />
+ <OnHoldTimeoutField />
+ </TabsContent>
+ </Tabs>
+ </>
+ )
+}
diff --git a/dashboard/src/features/users/dialogs/mutation/sections/index.ts b/dashboard/src/features/users/dialogs/mutation/sections/index.ts
@@ -0,0 +1,2 @@
+export * from './data-limit'
+export * from './expiration-method'
diff --git a/dashboard/src/features/users/dialogs/mutation/sections/use-expiration-method-tabs.ts b/dashboard/src/features/users/dialogs/mutation/sections/use-expiration-method-tabs.ts
@@ -0,0 +1,49 @@
+import { UserMutationType } from "@marzneshin/features/users";
+import { useEffect, useState } from "react";
+import { useFormContext } from "react-hook-form";
+
+type ExpirationMethodStrategy = "onhold" | "determined" | "unlimited";
+
+const getUserExpirationMethod = (entity: UserMutationType): ExpirationMethodStrategy => {
+ if (entity.status === "on_hold")
+ return 'onhold'
+ else if (entity.expire !== undefined)
+ return 'determined'
+ else
+ return 'unlimited'
+}
+
+
+export const useExpirationMethodTabs = ({ entity }: { entity: UserMutationType | null }) => {
+ const form = useFormContext()
+
+ const defaultExpirationMethodTab = entity?.username ? getUserExpirationMethod(entity) : 'determined'
+ const [
+ selectedExpirationMethodTab,
+ setSelectedExpirationMethodTab
+ ] = useState<ExpirationMethodStrategy | string>(defaultExpirationMethodTab);
+
+ useEffect(() => {
+ form.setValue("status", "active")
+ if (selectedExpirationMethodTab === 'onhold') {
+ form.setValue("status", "on_hold")
+ form.setValue("expire", undefined);
+ form.clearErrors("expire");
+ } else if (selectedExpirationMethodTab === "unlimited") {
+ form.setValue("expire", undefined);
+ form.setValue("on_hold_expire_duration", undefined);
+ form.setValue("on_hold_timeout", undefined);
+ form.clearErrors("expire");
+ form.clearErrors("on_hold_expire_duration");
+ form.clearErrors("on_hold_timeout");
+ } else {
+ form.setValue("on_hold_expire_duration", 0);
+ form.setValue("on_hold_timeout", null);
+ form.clearErrors("on_hold_expire_duration");
+ form.clearErrors("on_hold_timeout");
+ }
+ // eslint-disable-next-line
+ }, [selectedExpirationMethodTab]);
+
+ return { selectedExpirationMethodTab, defaultExpirationMethodTab, setSelectedExpirationMethodTab }
+}