mirror of
https://github.com/shuaiplus/nodewarden.git
synced 2026-08-05 06:50:10 +00:00
feat: add functionality to delete invalid invites and update related components
This commit is contained in:
@@ -2036,6 +2036,7 @@ export default function App() {
|
||||
onRemoveAllDevices: accountSecurityActions.openRemoveAllDevices,
|
||||
onRefreshAdmin: adminActions.refreshAdmin,
|
||||
onCreateInvite: adminActions.createInvite,
|
||||
onDeleteInvalidInvites: adminActions.deleteInvalidInvites,
|
||||
onDeleteAllInvites: adminActions.deleteAllInvites,
|
||||
onToggleUserStatus: adminActions.toggleUserStatus,
|
||||
onDeleteUser: adminActions.deleteUser,
|
||||
|
||||
@@ -13,6 +13,7 @@ interface AdminPageProps {
|
||||
error: string;
|
||||
onRefresh: () => void;
|
||||
onCreateInvite: (hours: number) => Promise<void>;
|
||||
onDeleteInvalidInvites: () => Promise<void>;
|
||||
onDeleteAllInvites: () => Promise<void>;
|
||||
onToggleUserStatus: (userId: string, currentStatus: 'active' | 'banned') => Promise<void>;
|
||||
onDeleteUser: (userId: string) => Promise<void>;
|
||||
@@ -134,7 +135,10 @@ export default function AdminPage(props: AdminPageProps) {
|
||||
<h3>{t('txt_invites')}</h3>
|
||||
<div className="actions admin-invites-head-actions">
|
||||
<button type="button" className="btn btn-secondary small" disabled={props.loading} onClick={props.onRefresh}>
|
||||
<RefreshCw size={14} className="btn-icon" /> {t('txt_sync')}
|
||||
<RefreshCw size={14} className="btn-icon" /> {t('txt_refresh')}
|
||||
</button>
|
||||
<button type="button" className="btn btn-danger small" onClick={() => void props.onDeleteInvalidInvites()}>
|
||||
<Trash2 size={14} className="btn-icon" /> {t('txt_delete_invalid')}
|
||||
</button>
|
||||
<button type="button" className="btn btn-danger small" onClick={() => void props.onDeleteAllInvites()}>
|
||||
<Trash2 size={14} className="btn-icon" /> {t('txt_delete_all')}
|
||||
|
||||
@@ -137,6 +137,7 @@ export interface AppMainRoutesProps {
|
||||
onRemoveAllDevices: () => void;
|
||||
onCreateInvite: (hours: number) => Promise<void>;
|
||||
onRefreshAdmin: () => void;
|
||||
onDeleteInvalidInvites: () => Promise<void>;
|
||||
onDeleteAllInvites: () => Promise<void>;
|
||||
onToggleUserStatus: (userId: string, status: 'active' | 'banned') => Promise<void>;
|
||||
onDeleteUser: (userId: string) => Promise<void>;
|
||||
@@ -413,6 +414,7 @@ export default function AppMainRoutes(props: AppMainRoutesProps) {
|
||||
error={props.adminError}
|
||||
onRefresh={props.onRefreshAdmin}
|
||||
onCreateInvite={props.onCreateInvite}
|
||||
onDeleteInvalidInvites={props.onDeleteInvalidInvites}
|
||||
onDeleteAllInvites={props.onDeleteAllInvites}
|
||||
onToggleUserStatus={props.onToggleUserStatus}
|
||||
onDeleteUser={props.onDeleteUser}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useMemo } from 'preact/hooks';
|
||||
import { createInvite, deleteAllInvites, deleteInvite, deleteUser, setUserStatus } from '@/lib/api/admin';
|
||||
import { createInvite, deleteAllInvites, deleteInvalidInvites, deleteInvite, deleteUser, setUserStatus } from '@/lib/api/admin';
|
||||
import { t } from '@/lib/i18n';
|
||||
import type { AppConfirmState } from '@/components/AppGlobalOverlays';
|
||||
import type { AuthedFetch } from '@/lib/api/shared';
|
||||
@@ -65,6 +65,26 @@ export default function useAdminActions(options: UseAdminActionsOptions) {
|
||||
});
|
||||
},
|
||||
|
||||
async deleteInvalidInvites() {
|
||||
onSetConfirm({
|
||||
title: t('txt_delete_invalid_invites'),
|
||||
message: t('txt_delete_invalid_invites_confirm_message'),
|
||||
danger: true,
|
||||
onConfirm: () => {
|
||||
onSetConfirm(null);
|
||||
void (async () => {
|
||||
try {
|
||||
await deleteInvalidInvites(authedFetch);
|
||||
await refetchInvites();
|
||||
onNotify('success', t('txt_invalid_invites_deleted'));
|
||||
} catch (error) {
|
||||
onNotify('error', error instanceof Error ? error.message : t('txt_delete_invalid_invites_failed'));
|
||||
}
|
||||
})();
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
async deleteAllInvites() {
|
||||
onSetConfirm({
|
||||
title: t('txt_delete_all_invites'),
|
||||
|
||||
@@ -29,6 +29,11 @@ export async function deleteInvite(authedFetch: AuthedFetch, code: string): Prom
|
||||
if (!resp.ok) throw new Error('Delete invite failed');
|
||||
}
|
||||
|
||||
export async function deleteInvalidInvites(authedFetch: AuthedFetch): Promise<void> {
|
||||
const resp = await authedFetch('/api/admin/invites?scope=invalid', { method: 'DELETE' });
|
||||
if (!resp.ok) throw new Error('Delete invalid invites failed');
|
||||
}
|
||||
|
||||
export async function deleteAllInvites(authedFetch: AuthedFetch): Promise<void> {
|
||||
const resp = await authedFetch('/api/admin/invites', { method: 'DELETE' });
|
||||
if (!resp.ok) throw new Error('Delete all invites failed');
|
||||
|
||||
@@ -1127,6 +1127,13 @@ export function createDemoMainRoutesProps(base: AppMainRoutesProps, notify: Noti
|
||||
onRefreshAdmin: () => {
|
||||
notify('success', t('txt_demo_admin_refreshed'));
|
||||
},
|
||||
onDeleteInvalidInvites: async () => {
|
||||
const now = Date.now();
|
||||
state.setInvites((prev) => prev.filter((invite) => (
|
||||
invite.status === 'active' && (!invite.expiresAt || new Date(invite.expiresAt).getTime() > now)
|
||||
)));
|
||||
notify('success', t('txt_invalid_invites_deleted'));
|
||||
},
|
||||
onDeleteAllInvites: async () => {
|
||||
state.setInvites([]);
|
||||
notify('success', t('txt_all_invites_deleted'));
|
||||
|
||||
@@ -582,12 +582,17 @@ const en: Record<string, string> = {
|
||||
"txt_identity_details": "Identity Details",
|
||||
"txt_ie_browser": "IE Browser",
|
||||
"txt_create_invite_failed": "Failed to create invite",
|
||||
"txt_delete_invalid": "Delete Invalid",
|
||||
"txt_delete_invalid_invites": "Delete invalid invites",
|
||||
"txt_delete_invalid_invites_confirm_message": "Delete all invalid invite codes? Active, unexpired invite codes will be kept.",
|
||||
"txt_delete_invalid_invites_failed": "Failed to delete invalid invites",
|
||||
"txt_delete_invite": "Delete invite",
|
||||
"txt_delete_invite_confirm_message": "Delete this invite code? This cannot be undone.",
|
||||
"txt_delete_invite_failed": "Failed to delete invite",
|
||||
"txt_invite_code_required": "Invite Code (Required)",
|
||||
"txt_invite_created": "Invite created",
|
||||
"txt_invite_deleted": "Invite deleted",
|
||||
"txt_invalid_invites_deleted": "Invalid invites deleted",
|
||||
"txt_invite_revoked": "Invite revoked",
|
||||
"txt_revoke_invite_failed": "Failed to revoke invite",
|
||||
"txt_invite_validity_hours": "Invite validity (hours)",
|
||||
@@ -1162,6 +1167,7 @@ const en: Record<string, string> = {
|
||||
"txt_log_action_admin_invite_create": "Create invite",
|
||||
"txt_log_action_admin_invite_delete": "Delete invite",
|
||||
"txt_log_action_admin_invite_delete_all": "Clear invites",
|
||||
"txt_log_action_admin_invite_delete_invalid": "Delete invalid invites",
|
||||
"txt_log_action_admin_invite_revoke": "Revoke invite",
|
||||
"txt_log_action_admin_user_delete": "Delete user",
|
||||
"txt_log_action_admin_user_status": "Change user status",
|
||||
|
||||
@@ -582,12 +582,17 @@ const es: Record<string, string> = {
|
||||
"txt_identity_details": "Detalles de identidad",
|
||||
"txt_ie_browser": "Navegador Internet Explorer",
|
||||
"txt_create_invite_failed": "Error al crear invitación",
|
||||
"txt_delete_invalid": "Eliminar inválidas",
|
||||
"txt_delete_invalid_invites": "Eliminar invitaciones inválidas",
|
||||
"txt_delete_invalid_invites_confirm_message": "¿Eliminar todos los códigos de invitación inválidos? Se conservarán los códigos activos y no vencidos.",
|
||||
"txt_delete_invalid_invites_failed": "Error al eliminar invitaciones inválidas",
|
||||
"txt_delete_invite": "Eliminar invitación",
|
||||
"txt_delete_invite_confirm_message": "¿Eliminar este código de invitación? Esta acción no se puede deshacer.",
|
||||
"txt_delete_invite_failed": "Error al eliminar invitación",
|
||||
"txt_invite_code_required": "Código de invitación (obligatorio)",
|
||||
"txt_invite_created": "Invitación creada",
|
||||
"txt_invite_deleted": "Invitación eliminada",
|
||||
"txt_invalid_invites_deleted": "Invitaciones inválidas eliminadas",
|
||||
"txt_invite_revoked": "Invitación revocada",
|
||||
"txt_revoke_invite_failed": "Error al revocar invitación",
|
||||
"txt_invite_validity_hours": "Validez de la invitación en horas",
|
||||
@@ -1162,6 +1167,7 @@ const es: Record<string, string> = {
|
||||
"txt_log_action_admin_invite_create": "Create invite",
|
||||
"txt_log_action_admin_invite_delete": "Delete invite",
|
||||
"txt_log_action_admin_invite_delete_all": "Clear invites",
|
||||
"txt_log_action_admin_invite_delete_invalid": "Delete invalid invites",
|
||||
"txt_log_action_admin_invite_revoke": "Revoke invite",
|
||||
"txt_log_action_admin_user_delete": "Delete user",
|
||||
"txt_log_action_admin_user_status": "Change user status",
|
||||
|
||||
@@ -582,12 +582,17 @@ const ru: Record<string, string> = {
|
||||
"txt_identity_details": "Данные личности",
|
||||
"txt_ie_browser": "IE-браузер",
|
||||
"txt_create_invite_failed": "Не удалось создать приглашение",
|
||||
"txt_delete_invalid": "Удалить недействительные",
|
||||
"txt_delete_invalid_invites": "Удалить недействительные приглашения",
|
||||
"txt_delete_invalid_invites_confirm_message": "Удалить все недействительные пригласительные коды? Активные и не истекшие коды будут сохранены.",
|
||||
"txt_delete_invalid_invites_failed": "Не удалось удалить недействительные приглашения",
|
||||
"txt_delete_invite": "Удалить приглашение",
|
||||
"txt_delete_invite_confirm_message": "Удалить этот пригласительный код? Это действие нельзя отменить.",
|
||||
"txt_delete_invite_failed": "Не удалось удалить приглашение",
|
||||
"txt_invite_code_required": "Пригласительный код (обязательно)",
|
||||
"txt_invite_created": "Приглашение создано",
|
||||
"txt_invite_deleted": "Приглашение удалено",
|
||||
"txt_invalid_invites_deleted": "Недействительные приглашения удалены",
|
||||
"txt_invite_revoked": "Приглашение отозвано",
|
||||
"txt_revoke_invite_failed": "Не удалось отозвать приглашение",
|
||||
"txt_invite_validity_hours": "Срок действия приглашения (часы)",
|
||||
@@ -1162,6 +1167,7 @@ const ru: Record<string, string> = {
|
||||
"txt_log_action_admin_invite_create": "Create invite",
|
||||
"txt_log_action_admin_invite_delete": "Delete invite",
|
||||
"txt_log_action_admin_invite_delete_all": "Clear invites",
|
||||
"txt_log_action_admin_invite_delete_invalid": "Delete invalid invites",
|
||||
"txt_log_action_admin_invite_revoke": "Revoke invite",
|
||||
"txt_log_action_admin_user_delete": "Delete user",
|
||||
"txt_log_action_admin_user_status": "Change user status",
|
||||
|
||||
@@ -582,12 +582,17 @@ const zhCN: Record<string, string> = {
|
||||
"txt_identity_details": "身份详情",
|
||||
"txt_ie_browser": "IE 浏览器",
|
||||
"txt_create_invite_failed": "创建邀请码失败",
|
||||
"txt_delete_invalid": "删除无效",
|
||||
"txt_delete_invalid_invites": "删除无效邀请码",
|
||||
"txt_delete_invalid_invites_confirm_message": "确定删除所有无效邀请码吗?仍有效且未过期的邀请码会保留。",
|
||||
"txt_delete_invalid_invites_failed": "删除无效邀请码失败",
|
||||
"txt_delete_invite": "删除邀请码",
|
||||
"txt_delete_invite_confirm_message": "确定删除该邀请码吗?删除后无法恢复。",
|
||||
"txt_delete_invite_failed": "删除邀请码失败",
|
||||
"txt_invite_code_required": "邀请码(必填)",
|
||||
"txt_invite_created": "邀请码已创建",
|
||||
"txt_invite_deleted": "邀请码已删除",
|
||||
"txt_invalid_invites_deleted": "无效邀请码已删除",
|
||||
"txt_invite_revoked": "邀请码已撤销",
|
||||
"txt_revoke_invite_failed": "撤销邀请码失败",
|
||||
"txt_invite_validity_hours": "邀请码有效期(小时)",
|
||||
@@ -1162,6 +1167,7 @@ const zhCN: Record<string, string> = {
|
||||
"txt_log_action_admin_invite_create": "创建邀请",
|
||||
"txt_log_action_admin_invite_delete": "删除邀请",
|
||||
"txt_log_action_admin_invite_delete_all": "清空邀请",
|
||||
"txt_log_action_admin_invite_delete_invalid": "删除无效邀请",
|
||||
"txt_log_action_admin_invite_revoke": "撤销邀请",
|
||||
"txt_log_action_admin_user_delete": "删除用户",
|
||||
"txt_log_action_admin_user_status": "修改用户状态",
|
||||
|
||||
@@ -582,12 +582,17 @@ const zhTW: Record<string, string> = {
|
||||
"txt_identity_details": "身份詳情",
|
||||
"txt_ie_browser": "IE 瀏覽器",
|
||||
"txt_create_invite_failed": "創建邀請碼失敗",
|
||||
"txt_delete_invalid": "刪除無效",
|
||||
"txt_delete_invalid_invites": "刪除無效邀請碼",
|
||||
"txt_delete_invalid_invites_confirm_message": "確定刪除所有無效邀請碼嗎?仍有效且未過期的邀請碼會保留。",
|
||||
"txt_delete_invalid_invites_failed": "刪除無效邀請碼失敗",
|
||||
"txt_delete_invite": "刪除邀請碼",
|
||||
"txt_delete_invite_confirm_message": "確定刪除此邀請碼嗎?刪除後無法復原。",
|
||||
"txt_delete_invite_failed": "刪除邀請碼失敗",
|
||||
"txt_invite_code_required": "邀請碼(必填)",
|
||||
"txt_invite_created": "邀請碼已創建",
|
||||
"txt_invite_deleted": "邀請碼已刪除",
|
||||
"txt_invalid_invites_deleted": "無效邀請碼已刪除",
|
||||
"txt_invite_revoked": "邀請碼已撤銷",
|
||||
"txt_revoke_invite_failed": "撤銷邀請碼失敗",
|
||||
"txt_invite_validity_hours": "邀請碼有效期(小時)",
|
||||
@@ -1162,6 +1167,7 @@ const zhTW: Record<string, string> = {
|
||||
"txt_log_action_admin_invite_create": "建立邀請",
|
||||
"txt_log_action_admin_invite_delete": "刪除邀請",
|
||||
"txt_log_action_admin_invite_delete_all": "清空邀請",
|
||||
"txt_log_action_admin_invite_delete_invalid": "刪除無效邀請",
|
||||
"txt_log_action_admin_invite_revoke": "撤銷邀請",
|
||||
"txt_log_action_admin_user_delete": "刪除使用者",
|
||||
"txt_log_action_admin_user_status": "修改使用者狀態",
|
||||
|
||||
Reference in New Issue
Block a user