105 lines
4.0 KiB
TypeScript
105 lines
4.0 KiB
TypeScript
'use client';
|
||
|
||
import { useEffect, useState } from 'react';
|
||
import { useRouter } from 'next/navigation';
|
||
import { ChevronRight, Heart, Plus, UsersRound } from 'lucide-react';
|
||
import { useAuth } from '@/components/id/auth-provider';
|
||
import { IdShell } from '@/components/id/shell';
|
||
import { useToast } from '@/components/id/toast-provider';
|
||
import { Button } from '@/components/ui/button';
|
||
import { Input } from '@/components/ui/input';
|
||
import { useRequireAuth } from '@/hooks/use-require-auth';
|
||
import { apiFetch, FamilyGroup, fetchFamilyGroups, getApiErrorMessage } from '@/lib/api';
|
||
import { defaultFamilyGroupName } from '@/lib/family-defaults';
|
||
|
||
export default function FamilyPage() {
|
||
const router = useRouter();
|
||
const { user, token } = useAuth();
|
||
const { isReady, isPinLocked } = useRequireAuth();
|
||
const { showToast } = useToast();
|
||
const [groups, setGroups] = useState<FamilyGroup[]>([]);
|
||
const [name, setName] = useState('');
|
||
const [creating, setCreating] = useState(false);
|
||
|
||
useEffect(() => {
|
||
if (user?.displayName) {
|
||
setName(defaultFamilyGroupName(user.displayName));
|
||
}
|
||
}, [user?.displayName]);
|
||
|
||
useEffect(() => {
|
||
if (!user || !token || isPinLocked) return;
|
||
fetchFamilyGroups(user.id, token)
|
||
.then((response) => setGroups(response.groups ?? []))
|
||
.catch((error) => {
|
||
const message = getApiErrorMessage(error, 'Не удалось загрузить семью');
|
||
if (message) showToast(message);
|
||
});
|
||
}, [isPinLocked, showToast, token, user]);
|
||
|
||
async function createGroup() {
|
||
if (!user || !token) return;
|
||
setCreating(true);
|
||
try {
|
||
const group = await apiFetch<FamilyGroup>('/family/groups', {
|
||
method: 'POST',
|
||
body: JSON.stringify({ ownerId: user.id, name })
|
||
}, token);
|
||
router.push(`/family/${group.id}`);
|
||
} catch (error) {
|
||
const message = getApiErrorMessage(error, 'Не удалось создать семью');
|
||
if (message) showToast(message);
|
||
} finally {
|
||
setCreating(false);
|
||
}
|
||
}
|
||
|
||
if (!isReady) {
|
||
return (
|
||
<IdShell active="/family">
|
||
<div className="py-20 text-center text-[#667085]">Загрузка...</div>
|
||
</IdShell>
|
||
);
|
||
}
|
||
|
||
return (
|
||
<IdShell active="/family" wide>
|
||
<p className="text-sm text-[#667085]">Семья</p>
|
||
<h1 className="text-4xl font-medium tracking-tight">Семейный доступ</h1>
|
||
<p className="mt-2 text-[#667085]">Приглашайте близких, общайтесь в чатах и управляйте семейной группой.</p>
|
||
|
||
<div className="mt-8 flex gap-3">
|
||
<Input value={name} onChange={(event) => setName(event.target.value)} placeholder="Название семьи" />
|
||
<Button onClick={() => void createGroup()} disabled={creating || !name.trim()}>
|
||
{creating ? 'Создаём...' : (<><Plus className="h-4 w-4" />Создать</>)}
|
||
</Button>
|
||
</div>
|
||
|
||
<div className="mt-8 space-y-3">
|
||
{groups.length ? groups.map((group) => (
|
||
<button
|
||
key={group.id}
|
||
type="button"
|
||
onClick={() => router.push(`/family/${group.id}`)}
|
||
className="flex w-full items-center gap-4 rounded-[24px] bg-[#f4f5f8] p-5 text-left transition hover:bg-[#eceef4]"
|
||
>
|
||
<div className="flex h-12 w-12 items-center justify-center rounded-2xl bg-white">
|
||
<Heart className="h-5 w-5" />
|
||
</div>
|
||
<div className="flex-1">
|
||
<h2 className="font-semibold">{group.name}</h2>
|
||
<p className="text-sm text-[#667085]">{(group.members ?? []).length} участников</p>
|
||
</div>
|
||
<ChevronRight className="h-5 w-5 text-[#a8adbc]" />
|
||
</button>
|
||
)) : (
|
||
<div className="rounded-[24px] bg-[#f4f5f8] p-5 text-[#667085]">
|
||
<UsersRound className="mb-3 h-6 w-6" />
|
||
Семейных групп пока нет
|
||
</div>
|
||
)}
|
||
</div>
|
||
</IdShell>
|
||
);
|
||
}
|