gitscope
← marzneshin / Diff · 6955aba → 6955aba
Changes 6955aba..6955aba
Patch commit
diff --git a/dashboard/public/locales/en.json b/dashboard/public/locales/en.json
index 21360a7..1aa66a9 100644
--- a/dashboard/public/locales/en.json
+++ b/dashboard/public/locales/en.json
@@ -109,6 +109,8 @@
"determined_expire": "Determined",
"expire_method": "Expiration method",
"onhold_expire": "On Hold",
+ "reset_usage": "Reset Usage",
+ "revoke_subscription": "Revoke Subscription",
"on_hold_expire_duration": "On Hold",
"on_hold_timeout": "On Hold Timeout",
"settings": {
@@ -181,6 +183,20 @@
"title": "{{name}} is successfuly updated",
"desc": ""
}
+ },
+ "user_revoke": {
+ "error": "Failed to revoke {{name}} subscription",
+ "success": {
+ "title": "{{name}} is successfuly created",
+ "desc": ""
+ }
+ },
+ "user_reset": {
+ "error": "Failed to reset {{name}} data usage",
+ "success": {
+ "title": "{{name}} data usage is successfuly reseted",
+ "desc": ""
+ }
}
},
"delete-confirmation": {
diff --git a/dashboard/src/features/users/dialogs/settings/index.tsx b/dashboard/src/features/users/dialogs/settings/index.tsx
index ce7ac2c..9603bda 100644
--- a/dashboard/src/features/users/dialogs/settings/index.tsx
+++ b/dashboard/src/features/users/dialogs/settings/index.tsx
@@ -21,7 +21,6 @@ interface UsersSettingsDialogProps {
}
export const UsersSettingsDialog: FC<UsersSettingsDialogProps> = ({ onOpenChange, open, entity }) => {
-
const { t } = useTranslation();
if (entity) {
diff --git a/dashboard/src/features/users/dialogs/settings/user-info/qrcode.tsx b/dashboard/src/features/users/dialogs/settings/user-info/qrcode.tsx
index 058f814..f4e4e07 100644
--- a/dashboard/src/features/users/dialogs/settings/user-info/qrcode.tsx
+++ b/dashboard/src/features/users/dialogs/settings/user-info/qrcode.tsx
@@ -1,9 +1,18 @@
-import { UserType } from '@marzneshin/features/users';
+import {
+ useUserSubscriptionRevokeCmd,
+ UserType
+} from '@marzneshin/features/users';
import QRCode from "react-qr-code";
import { QrCodeIcon } from "lucide-react";
import { FC } from 'react'
-import { Card, CardContent, CardHeader, CardTitle } from '@marzneshin/components';
+import {
+ Button,
+ Card,
+ CardContent,
+ CardHeader,
+ CardTitle
+} from '@marzneshin/components';
import { useTranslation } from 'react-i18next';
import { SubscriptionLinkButton } from './subcription-link-button';
import { getSubscriptionLink } from '@marzneshin/utils';
@@ -16,14 +25,18 @@ export const QRCodeSection: FC<QRCodeProps> = (
{ entity }
) => {
const subscribeQrLink = getSubscriptionLink(entity.subscription_url);
+ const { mutate: revokeSubscription } = useUserSubscriptionRevokeCmd()
const { t } = useTranslation()
return (
<Card>
- <CardHeader>
+ <CardHeader className="flex flex-row justify-between items-center w-full">
<CardTitle className="flex flex-row gap-4 justify-start">
<QrCodeIcon />
{t('subscription')}
</CardTitle>
+ <Button className="w-[9rem]" onClick={() => revokeSubscription(entity)}>
+ {t('page.users.revoke_subscription')}
+ </Button>
</CardHeader>
<CardContent className='flex flex-col justify-center items-center py-10 w-full h-full'>
<div className="flex flex-col gap-3 justify-center items-center w-1/2 h-1/2">
diff --git a/dashboard/src/features/users/dialogs/settings/user-info/table.tsx b/dashboard/src/features/users/dialogs/settings/user-info/table.tsx
index c425b24..a11efe7 100644
--- a/dashboard/src/features/users/dialogs/settings/user-info/table.tsx
+++ b/dashboard/src/features/users/dialogs/settings/user-info/table.tsx
@@ -1,6 +1,11 @@
-import { Card, CardContent, CardHeader, CardTitle, Table, TableBody, TableCell, TableRow } from "@marzneshin/components";
+import { Button, Card, CardContent, CardHeader, CardTitle, Table, TableBody, TableCell, TableRow } from "@marzneshin/components";
import { FC } from 'react';
-import { UserType, UsersStatus, UsersStatusBadge } from '@marzneshin/features/users';
+import {
+ useUserUsageResetCmd,
+ UserType,
+ UsersStatus,
+ UsersStatusBadge
+} from '@marzneshin/features/users';
import { CircularProgress } from "@nextui-org/progress";
import { useTranslation } from "react-i18next";
import { format, isDate, isValid } from "date-fns";
@@ -35,12 +40,15 @@ const CircularProgressBarRow: FC<{ label: string; value: number; limit: number }
export const UserInfoTable: FC<UserInfoTableProps> = ({ entity }) => {
const { t } = useTranslation();
-
+ const { mutate: resetUsage } = useUserUsageResetCmd()
const expireDate = entity.expire ? (isDate(entity.expire) ? entity.expire : new Date(entity.expire)) : null;
return (
<Card>
- <CardHeader>
+ <CardHeader className="flex flex-row justify-between items-center w-full">
<CardTitle>{t('user_info')}</CardTitle>
+ <Button className="w-[7rem]" onClick={() => resetUsage(entity)}>
+ {t('page.users.reset_usage')}
+ </Button>
</CardHeader>
<CardContent>
<Table>
diff --git a/dashboard/src/features/users/services/index.ts b/dashboard/src/features/users/services/index.ts
index 9098541..7f180cc 100644
--- a/dashboard/src/features/users/services/index.ts
+++ b/dashboard/src/features/users/services/index.ts
@@ -2,3 +2,5 @@ export * from './users.query'
export * from './update-user.mutate'
export * from './create-user.mutate'
export * from './delete-user.mutate'
+export * from './user-usage-reset.command'
+export * from './user-subscription-revoke.command'
diff --git a/dashboard/src/features/users/services/user-subscription-revoke.command.ts b/dashboard/src/features/users/services/user-subscription-revoke.command.ts
new file mode 100644
index 0000000..265bb8d
--- /dev/null
+++ b/dashboard/src/features/users/services/user-subscription-revoke.command.ts
@@ -0,0 +1,42 @@
+import { useMutation } from "@tanstack/react-query";
+import { fetch, queryClient } from "@marzneshin/utils";
+import { toast } from "sonner";
+import i18n from "@marzneshin/features/i18n";
+import {
+ UserMutationType
+} from "@marzneshin/features/users";
+
+export async function userSubscriptionRvoke(user: UserMutationType): Promise<UserMutationType> {
+ return fetch(`/users/${user.username}/revoke_sub`, { method: 'post', body: user }).then((user) => {
+ return user;
+ });
+}
+
+const handleError = (error: Error, value: UserMutationType) => {
+ toast.error(
+ i18n.t('events.user_revoke.error', { name: value.username }),
+ {
+ description: error.message
+ })
+}
+
+const handleSuccess = (value: UserMutationType) => {
+ toast.success(
+ i18n.t('events.user_revoke.success.title', { name: value.username }),
+ {
+ description: i18n.t('events.user_revoke.success.desc')
+ })
+ queryClient.invalidateQueries({ queryKey: [UsersSubscriptionFetchKey] })
+}
+
+
+const UsersSubscriptionFetchKey = "users";
+
+export const useUserSubscriptionRevokeCmd = () => {
+ return useMutation({
+ mutationKey: [UsersSubscriptionFetchKey, "revoke_sub"],
+ mutationFn: userSubscriptionRvoke,
+ onError: handleError,
+ onSuccess: handleSuccess,
+ })
+}
diff --git a/dashboard/src/features/users/services/user-usage-reset.command.ts b/dashboard/src/features/users/services/user-usage-reset.command.ts
new file mode 100644
index 0000000..f6c4baa
--- /dev/null
+++ b/dashboard/src/features/users/services/user-usage-reset.command.ts
@@ -0,0 +1,43 @@
+import { useMutation } from "@tanstack/react-query";
+import { fetch, queryClient } from "@marzneshin/utils";
+import { toast } from "sonner";
+import i18n from "@marzneshin/features/i18n";
+import {
+ UsersQueryFetchKey,
+ UserMutationType
+} from "@marzneshin/features/users";
+
+export async function userUsageReset(user: UserMutationType): Promise<UserMutationType> {
+ return fetch(`/users/${user.username}/reset`, { method: 'post', body: user }).then((user) => {
+ return user;
+ });
+}
+
+const handleError = (error: Error, value: UserMutationType) => {
+ toast.error(
+ i18n.t('events.user_reset.error', { name: value.username }),
+ {
+ description: error.message
+ })
+}
+
+const handleSuccess = (value: UserMutationType) => {
+ toast.success(
+ i18n.t('events.user_reset.success.title', { name: value.username }),
+ {
+ description: i18n.t('events.user_reset.success.desc')
+ })
+ queryClient.invalidateQueries({ queryKey: [UsersQueryFetchKey] })
+}
+
+
+const UsersUpdateFetchKey = "users";
+
+export const useUserUsageResetCmd = () => {
+ return useMutation({
+ mutationKey: [UsersUpdateFetchKey, "reset"],
+ mutationFn: userUsageReset,
+ onError: handleError,
+ onSuccess: handleSuccess,
+ })
+}