chore: update user detail viewer date picker component
This commit is contained in:
parent
f764bcb627
commit
bcb1e0ef9d
@ -453,6 +453,7 @@
|
||||
"reason": "Ban Reason",
|
||||
"reasonPlaceholder": "Enter the reason for banning this user",
|
||||
"expires": "Ban Expires",
|
||||
"selectDate": "Select Date",
|
||||
"button": "Ban User",
|
||||
"success": "User has been banned",
|
||||
"error": "Failed to ban user"
|
||||
|
@ -454,6 +454,7 @@
|
||||
"reason": "封禁原因",
|
||||
"reasonPlaceholder": "请输入封禁该用户的原因",
|
||||
"expires": "封禁到期时间",
|
||||
"selectDate": "选择日期",
|
||||
"button": "封禁用户",
|
||||
"success": "用户已被封禁",
|
||||
"error": "封禁用户失败"
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { UserAvatar } from '@/components/layout/user-avatar';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Calendar } from '@/components/ui/calendar';
|
||||
import {
|
||||
Drawer,
|
||||
DrawerClose,
|
||||
@ -11,15 +12,21 @@ import {
|
||||
DrawerTitle,
|
||||
DrawerTrigger,
|
||||
} from '@/components/ui/drawer';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from '@/components/ui/popover';
|
||||
import { Separator } from '@/components/ui/separator';
|
||||
import { Textarea } from '@/components/ui/textarea';
|
||||
import { useIsMobile } from '@/hooks/use-mobile';
|
||||
import { authClient } from '@/lib/auth-client';
|
||||
import type { User } from '@/lib/auth-types';
|
||||
import { formatDate } from '@/lib/formatter';
|
||||
import { cn } from '@/lib/utils';
|
||||
import {
|
||||
CalendarIcon,
|
||||
Loader2Icon,
|
||||
MailCheckIcon,
|
||||
MailQuestionIcon,
|
||||
@ -40,7 +47,7 @@ export function UserDetailViewer({ user }: UserDetailViewerProps) {
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [error, setError] = useState<string | undefined>();
|
||||
const [banReason, setBanReason] = useState('');
|
||||
const [banExpiresAt, setBanExpiresAt] = useState<string>('');
|
||||
const [banExpiresAt, setBanExpiresAt] = useState<Date | undefined>();
|
||||
|
||||
const handleBan = async () => {
|
||||
if (!banReason) {
|
||||
@ -57,19 +64,18 @@ export function UserDetailViewer({ user }: UserDetailViewerProps) {
|
||||
setError('');
|
||||
|
||||
try {
|
||||
const expiresAt = banExpiresAt ? new Date(banExpiresAt) : null;
|
||||
await authClient.admin.banUser({
|
||||
userId: user.id,
|
||||
banReason,
|
||||
banExpiresIn: expiresAt
|
||||
? Math.floor((expiresAt.getTime() - Date.now()) / 1000)
|
||||
banExpiresIn: banExpiresAt
|
||||
? Math.floor((banExpiresAt.getTime() - Date.now()) / 1000)
|
||||
: undefined,
|
||||
});
|
||||
|
||||
toast.success(t('ban.success'));
|
||||
// Reset form
|
||||
setBanReason('');
|
||||
setBanExpiresAt('');
|
||||
setBanExpiresAt(undefined);
|
||||
} catch (err) {
|
||||
const error = err as Error;
|
||||
console.error('Failed to ban user:', error);
|
||||
@ -234,13 +240,33 @@ export function UserDetailViewer({ user }: UserDetailViewerProps) {
|
||||
/>
|
||||
</div>
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="ban-expires">{t('ban.expires')}</Label>
|
||||
<Input
|
||||
id="ban-expires"
|
||||
type="datetime-local"
|
||||
value={banExpiresAt}
|
||||
onChange={(e) => setBanExpiresAt(e.target.value)}
|
||||
/>
|
||||
<Label>{t('ban.expires')}</Label>
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
variant="outline"
|
||||
className={cn(
|
||||
'justify-start text-left font-normal cursor-pointer',
|
||||
!banExpiresAt && 'text-muted-foreground'
|
||||
)}
|
||||
>
|
||||
<CalendarIcon />
|
||||
{banExpiresAt ? (
|
||||
formatDate(banExpiresAt)
|
||||
) : (
|
||||
<span>{t('ban.selectDate')}</span>
|
||||
)}
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-auto p-0" align="start">
|
||||
<Calendar
|
||||
mode="single"
|
||||
selected={banExpiresAt}
|
||||
onSelect={setBanExpiresAt}
|
||||
initialFocus
|
||||
/>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</div>
|
||||
<Button
|
||||
type="submit"
|
||||
|
@ -1,8 +1,8 @@
|
||||
'use client';
|
||||
|
||||
import { getUsersAction } from '@/actions/get-users';
|
||||
import type { User } from '@/components/admin/users-table';
|
||||
import { UsersTable } from '@/components/admin/users-table';
|
||||
import type { User } from '@/lib/auth-types';
|
||||
import type { SortingState } from '@tanstack/react-table';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import { useEffect, useState } from 'react';
|
||||
@ -60,9 +60,9 @@ export function UsersPageClient() {
|
||||
pageSize={pageSize}
|
||||
search={search}
|
||||
loading={loading}
|
||||
onSearch={setSearch}
|
||||
onPageChange={setPageIndex}
|
||||
onPageSizeChange={setPageSize}
|
||||
onSearch={setSearch}
|
||||
onSortingChange={setSorting}
|
||||
/>
|
||||
</>
|
||||
|
@ -241,9 +241,9 @@ interface UsersTableProps {
|
||||
pageSize: number;
|
||||
search: string;
|
||||
loading?: boolean;
|
||||
onSearch: (search: string) => void;
|
||||
onPageChange: (page: number) => void;
|
||||
onPageSizeChange: (size: number) => void;
|
||||
onSearch: (search: string) => void;
|
||||
onSortingChange?: (sorting: SortingState) => void;
|
||||
}
|
||||
|
||||
@ -257,9 +257,9 @@ export function UsersTable({
|
||||
pageSize,
|
||||
search,
|
||||
loading,
|
||||
onSearch,
|
||||
onPageChange,
|
||||
onPageSizeChange,
|
||||
onSearch,
|
||||
onSortingChange,
|
||||
}: UsersTableProps) {
|
||||
const [sorting, setSorting] = useState<SortingState>([]);
|
||||
|
Loading…
Reference in New Issue
Block a user