diff --git a/.gitignore b/.gitignore
@@ -199,3 +199,4 @@ app/dashboard/build/
dashboard/.vite/deps_temp_f42dd32d/package.json
dashboard/.vite/deps
dashboard/coverage
+note.md
diff --git a/dashboard/src/features/users/components/used-user-traffic.tsx b/dashboard/src/features/users/components/used-user-traffic.tsx
@@ -14,7 +14,7 @@ export const UserUsedTraffic: FC<UserUsedTrafficProps> = (
) => {
const { t } = useTranslation()
const formatedUsedTraffic = format(user.used_traffic)
- const formatedDatalimit = user.data_limit !== null ? format(user.data_limit) : []
+ const formatedDatalimit = (user.data_limit != null) ? format(user.data_limit) : []
return (
<div className="flex gap-x-5 justify-start items-center">
<CircularProgress
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,9 +21,14 @@ export const DataLimitField: FC<DataLimitFieldProps> = () => {
name="data_limit"
render={({ field }) => (
<FormItem className="w-full">
- <FormLabel>{t('page.users.data_limit')} (GB)</FormLabel>
+ <FormLabel>{t('page.users.data_limit')}</FormLabel>
<FormControl>
- <Input type="number" className="order-1" {...field} />
+ <Input
+ type="number"
+ className="order-1"
+ {...field}
+ placeholder="GB"
+ />
</FormControl>
<FormMessage />
</FormItem>
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
@@ -1,4 +1,3 @@
-
import {
FormControl,
FormField,
@@ -11,15 +10,16 @@ import { FC, useEffect, useState } from 'react'
import { useFormContext } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
-interface OnHoldExpireDurationFieldProps { }
+export const OnHoldExpireDurationField: FC = () => {
+ const form = useFormContext();
+ const { t } = useTranslation();
+
+ const defaultDuration = (form.getValues('on_hold_expire_duration') ?? 0) / 86400;
+ const [duration, setDuration] = useState<number>(defaultDuration);
-export const OnHoldExpireDurationField: FC<OnHoldExpireDurationFieldProps> = () => {
- const form = useFormContext()
- const [duration, setDuration] = useState<number>(0)
useEffect(() => {
- form.setValue('on_hold_expire_duration', duration * 86400)
- }, [form, duration])
- const { t } = useTranslation()
+ form.setValue('on_hold_expire_duration', duration * 86400);
+ }, [form, duration]);
return (
<FormField
@@ -30,10 +30,13 @@ export const OnHoldExpireDurationField: FC<OnHoldExpireDurationFieldProps> = ()
<FormLabel>{t('page.users.on_hold_expire_duration')} ({t('days')})</FormLabel>
<FormControl>
<Input
- type="number"
{...field}
+ type="number"
value={duration}
- onChange={(e) => setDuration(Number(e.target.value))}
+ onChange={(e) => {
+ setDuration(Number(e.target.value));
+ field.onChange(e.target.value);
+ }}
/>
</FormControl>
<FormMessage />
diff --git a/dashboard/src/features/users/dialogs/mutation/index.tsx b/dashboard/src/features/users/dialogs/mutation/index.tsx
@@ -38,7 +38,7 @@ export const UsersMutationDialog: FC<UsersMutationDialogProps> = ({
const getDefaultValues = useCallback(
(): UserMutationType => ({
services: [],
- data_limit: 1,
+ data_limit: undefined,
expire: null,
username: "",
data_limit_reset_strategy: "no_reset",
diff --git a/dashboard/src/features/users/dialogs/mutation/sections/data-limit.tsx b/dashboard/src/features/users/dialogs/mutation/sections/data-limit.tsx
@@ -18,29 +18,32 @@ export const DataLimitFields: FC = () => {
const form = useFormContext()
const { t } = useTranslation()
+ const data_limit = form.watch().data_limit;
+
const [
selectedDataLimitTab,
setSelectedDataLimitTab
- ] = useState<'limited' | 'unlimited' | string>('limited');
+ ] = useState((data_limit === 0) ? "unlimited" : "limited");
+
useEffect(() => {
- if (selectedDataLimitTab === 'limited') {
- form.setValue("data_limit", 1)
- form.setValue("data_limit_reset_strategy", "no_reset");
- } else {
- form.setValue("data_limit", 0)
+ setSelectedDataLimitTab((data_limit === 0) ? "unlimited" : "limited")
+ }, [data_limit])
+
+ useEffect(() => {
+ if (selectedDataLimitTab !== 'limited') {
+ form.setValue("data_limit", undefined)
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">
+ <Tabs defaultValue={selectedDataLimitTab} 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"
diff --git a/dashboard/src/features/users/dialogs/mutation/sections/expiration-method.tsx b/dashboard/src/features/users/dialogs/mutation/sections/expiration-method.tsx
@@ -24,14 +24,21 @@ interface ExpirationMethodProps {
export const ExpirationMethodFields: FC<ExpirationMethodProps> = ({ entity }) => {
const { t } = useTranslation()
- const { setSelectedExpirationMethodTab, defaultExpirationMethodTab } = useExpirationMethodTabs({ entity })
+ const {
+ setSelectedExpirationMethodTab,
+ defaultExpirationMethodTab
+ } = useExpirationMethodTabs({ entity })
return (
<>
<FormLabel>
{t('page.users.expire_method')}
</FormLabel>
- <Tabs defaultValue={defaultExpirationMethodTab} onValueChange={setSelectedExpirationMethodTab} className="mt-2 w-full">
+ <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"
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
@@ -7,7 +7,7 @@ type ExpirationMethodStrategy = "onhold" | "determined" | "unlimited";
const getUserExpirationMethod = (entity: UserMutationType): ExpirationMethodStrategy => {
if (entity.status === "on_hold")
return 'onhold'
- else if (entity.expire !== undefined)
+ else if (entity.expire !== undefined && entity.expire !== null)
return 'determined'
else
return 'unlimited'
@@ -17,7 +17,8 @@ const getUserExpirationMethod = (entity: UserMutationType): ExpirationMethodStra
export const useExpirationMethodTabs = ({ entity }: { entity: UserMutationType | null }) => {
const form = useFormContext()
- const defaultExpirationMethodTab = entity?.username ? getUserExpirationMethod(entity) : 'determined'
+ const defaultExpirationMethodTab =
+ (entity !== null) ? getUserExpirationMethod(entity) : 'determined'
const [
selectedExpirationMethodTab,
setSelectedExpirationMethodTab
@@ -30,7 +31,7 @@ export const useExpirationMethodTabs = ({ entity }: { entity: UserMutationType |
form.setValue("expire", undefined);
form.clearErrors("expire");
} else if (selectedExpirationMethodTab === "unlimited") {
- form.setValue("expire", undefined);
+ form.setValue("expire", 0);
form.setValue("on_hold_expire_duration", undefined);
form.setValue("on_hold_timeout", undefined);
form.clearErrors("expire");
diff --git a/dashboard/src/features/users/types/index.ts b/dashboard/src/features/users/types/index.ts
@@ -21,7 +21,7 @@ export interface UserType {
on_hold_timeout: Date | string | undefined;
on_hold_expire_duration: number;
expire: Date | string | null;
- data_limit: number | null;
+ data_limit: number | null | undefined;
data_limit_reset_strategy: DataLimitResetStrategy;
lifetime_used_traffic: number;
enabled: boolean;