92 lines
4.1 KiB
TypeScript
92 lines
4.1 KiB
TypeScript
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
|