try to do better
This commit is contained in:
96
frontend/src/components/family/InviteModal.tsx
Normal file
96
frontend/src/components/family/InviteModal.tsx
Normal file
@@ -0,0 +1,96 @@
|
||||
import { useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Copy, Check, Loader2 } from 'lucide-react';
|
||||
import { Modal, Button } from '../ui';
|
||||
import { useInviteLink } from '../../hooks';
|
||||
import { InviteLinkResponse } from '../../types';
|
||||
|
||||
interface InviteModalProps {
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
export function InviteModal({ onClose }: InviteModalProps) {
|
||||
const { t } = useTranslation();
|
||||
const { createLink } = useInviteLink();
|
||||
const [inviteLink, setInviteLink] = useState<InviteLinkResponse | null>(null);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [copied, setCopied] = useState(false);
|
||||
|
||||
const handleCreateLink = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
const link = await createLink({ expires_in_hours: 168 });
|
||||
setInviteLink(link);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleCopy = async () => {
|
||||
if (!inviteLink) return;
|
||||
try {
|
||||
await navigator.clipboard.writeText(inviteLink.invite_url);
|
||||
setCopied(true);
|
||||
setTimeout(() => setCopied(false), 2000);
|
||||
} catch (error) {
|
||||
console.error('Failed to copy:', error);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal isOpen={true} onClose={onClose} title={t('family.inviteMember')}>
|
||||
{!inviteLink ? (
|
||||
<div className="text-center py-6">
|
||||
<p className="text-gray-700 dark:text-gray-300 mb-6">
|
||||
{t('invite.description')}
|
||||
</p>
|
||||
<Button
|
||||
variant="primary"
|
||||
onClick={handleCreateLink}
|
||||
disabled={loading}
|
||||
fullWidth
|
||||
>
|
||||
{loading ? (
|
||||
<>
|
||||
<Loader2 className="w-5 h-5 mr-2 animate-spin" />
|
||||
{t('common.loading')}
|
||||
</>
|
||||
) : (
|
||||
t('invite.create')
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
) : (
|
||||
<div className="space-y-4">
|
||||
<div className="p-4 bg-gray-100 dark:bg-gray-700 rounded-lg">
|
||||
<p className="text-sm text-gray-600 dark:text-gray-400 mb-2">
|
||||
{t('invite.link')}
|
||||
</p>
|
||||
<p className="text-sm font-mono break-all text-gray-900 dark:text-white">
|
||||
{inviteLink.invite_url}
|
||||
</p>
|
||||
</div>
|
||||
<Button
|
||||
variant="primary"
|
||||
onClick={handleCopy}
|
||||
fullWidth
|
||||
>
|
||||
{copied ? (
|
||||
<>
|
||||
<Check className="w-5 h-5 mr-2" />
|
||||
{t('invite.copied')}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Copy className="w-5 h-5 mr-2" />
|
||||
{t('invite.copy')}
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user