test_task_crm/frontend/src/pages/organizations/organizations-page.tsx

92 lines
4.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { Building2, RefreshCw } from 'lucide-react'
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
import { Button } from '@/components/ui/button'
import { Skeleton } from '@/components/ui/skeleton'
import { useToast } from '@/components/ui/use-toast'
import { useOrganizationsQuery, useInvalidateOrganizations } from '@/features/organizations/hooks'
import { useAuthStore } from '@/stores/auth-store'
import { formatDate } from '@/lib/utils'
const OrganizationsPage = () => {
const { data: organizations, isLoading, isFetching } = useOrganizationsQuery()
const activeOrganizationId = useAuthStore((state) => state.activeOrganizationId)
const setActiveOrganization = useAuthStore((state) => state.setActiveOrganization)
const invalidate = useInvalidateOrganizations()
const { toast } = useToast()
const handleSwitch = (id: number) => {
setActiveOrganization(id)
toast({ title: 'Контекст переключён', description: 'Все запросы теперь выполняются в выбранной организации.' })
}
return (
<div className="space-y-6">
<div className="flex flex-col gap-3 md:flex-row md:items-center md:justify-between">
<div>
<h1 className="text-2xl font-semibold text-foreground">Организации</h1>
<p className="text-sm text-muted-foreground">Список компаний, к которым у вас есть доступ.</p>
</div>
<Button variant="outline" size="sm" className="gap-2" onClick={invalidate} disabled={isFetching}>
<RefreshCw className={`h-4 w-4 ${isFetching ? 'animate-spin' : ''}`} />
Обновить
</Button>
</div>
{isLoading ? (
<div className="grid gap-4 lg:grid-cols-2">
{[...Array(2)].map((_, index) => (
<Card key={index} className="border-dashed">
<CardHeader>
<Skeleton className="h-4 w-32" />
</CardHeader>
<CardContent>
<Skeleton className="h-6 w-24" />
<Skeleton className="mt-4 h-4 w-40" />
</CardContent>
</Card>
))}
</div>
) : organizations && organizations.length ? (
<div className="grid gap-4 lg:grid-cols-2">
{organizations.map((org) => (
<Card key={org.id} className={org.id === activeOrganizationId ? 'border-primary shadow-md' : undefined}>
<CardHeader className="flex flex-row items-center gap-3">
<div className="flex h-10 w-10 items-center justify-center rounded-full bg-primary/10 text-primary">
<Building2 className="h-5 w-5" />
</div>
<div>
<CardTitle className="text-lg">{org.name}</CardTitle>
<CardDescription>ID {org.id}</CardDescription>
</div>
</CardHeader>
<CardContent className="flex items-center justify-between">
<div>
<p className="text-sm text-muted-foreground">Создана {formatDate(org.created_at)}</p>
{org.id === activeOrganizationId ? (
<p className="text-sm font-medium text-primary">Активная организация</p>
) : null}
</div>
{org.id === activeOrganizationId ? null : (
<Button variant="outline" size="sm" onClick={() => handleSwitch(org.id)}>
Сделать активной
</Button>
)}
</CardContent>
</Card>
))}
</div>
) : (
<Card className="border-dashed text-center">
<CardHeader>
<CardTitle>Нет организаций</CardTitle>
<CardDescription>Обратитесь к администратору, чтобы вас добавили в рабочую область.</CardDescription>
</CardHeader>
</Card>
)}
</div>
)
}
export default OrganizationsPage