90 lines
2.6 KiB
TypeScript
90 lines
2.6 KiB
TypeScript
import { DatePicker } from '@/components/date-picker';
|
|
import { Button } from '@/components/ui/button';
|
|
import {
|
|
Dialog,
|
|
DialogContent,
|
|
DialogDescription,
|
|
DialogFooter,
|
|
DialogHeader,
|
|
DialogTitle
|
|
} from '@/components/ui/dialog';
|
|
import { Group } from '@/components/ui/group';
|
|
import { Input } from '@/components/ui/input';
|
|
import { useActiveServerId } from '@/features/app/hooks';
|
|
import { useForm } from '@/hooks/use-form';
|
|
import { getTRPCClient } from '@/lib/trpc';
|
|
import { getRandomString } from '@pulse/shared';
|
|
import { memo, useCallback } from 'react';
|
|
import { toast } from 'sonner';
|
|
import type { TDialogBaseProps } from '../types';
|
|
|
|
type TCreateInviteDialogProps = TDialogBaseProps & {
|
|
refetch?: () => void;
|
|
};
|
|
|
|
const CreateInviteDialog = memo(
|
|
({ refetch, close, isOpen }: TCreateInviteDialogProps) => {
|
|
const activeServerId = useActiveServerId();
|
|
const { r, rrn, values, setTrpcErrors } = useForm({
|
|
maxUses: 0,
|
|
expiresAt: 0,
|
|
code: getRandomString(24)
|
|
});
|
|
|
|
const handleCreate = useCallback(async () => {
|
|
if (!activeServerId) return;
|
|
const trpc = getTRPCClient();
|
|
|
|
try {
|
|
await trpc.invites.add.mutate({
|
|
...values,
|
|
serverId: activeServerId
|
|
});
|
|
toast.success('Invite created');
|
|
|
|
refetch?.();
|
|
close();
|
|
} catch (error) {
|
|
setTrpcErrors(error);
|
|
}
|
|
}, [close, refetch, setTrpcErrors, values, activeServerId]);
|
|
|
|
return (
|
|
<Dialog open={isOpen}>
|
|
<DialogContent onInteractOutside={close} close={close}>
|
|
<DialogHeader>
|
|
<DialogTitle>Create Server Invite</DialogTitle>
|
|
<DialogDescription>
|
|
Create a new invitation link for users to join the server.
|
|
</DialogDescription>
|
|
</DialogHeader>
|
|
|
|
<div className="space-y-4">
|
|
<Group label="Code">
|
|
<Input placeholder="Invite code" {...r('code')} />
|
|
</Group>
|
|
<Group label="Max uses" description="Use 0 for unlimited uses.">
|
|
<Input placeholder="Max uses" {...r('maxUses', 'number')} />
|
|
</Group>
|
|
<Group
|
|
label="Expires in"
|
|
description="Leave empty for no expiration."
|
|
>
|
|
<DatePicker {...rrn('expiresAt')} minDate={Date.now()} />
|
|
</Group>
|
|
</div>
|
|
|
|
<DialogFooter className="gap-2">
|
|
<Button variant="ghost" onClick={close}>
|
|
Cancel
|
|
</Button>
|
|
<Button onClick={handleCreate}>Create Invite</Button>
|
|
</DialogFooter>
|
|
</DialogContent>
|
|
</Dialog>
|
|
);
|
|
}
|
|
);
|
|
|
|
export { CreateInviteDialog };
|