* refactor components/navigation * refactor components/orders * refactor components/profile * refactor components/schedule * remove components/common/spinner
130 lines
4.2 KiB
TypeScript
130 lines
4.2 KiB
TypeScript
'use client';
|
|
|
|
import { CardSectionHeader } from '@/components/ui';
|
|
import { ContactsContextProvider } from '@/context/contacts';
|
|
import { useCustomerContacts } from '@/hooks/api/contacts';
|
|
// eslint-disable-next-line import/extensions
|
|
import AvatarPlaceholder from '@/public/avatar/avatar_placeholder.png';
|
|
import { useOrderStore } from '@/stores/order';
|
|
import { withContext } from '@/utils/context';
|
|
import { type CustomerFieldsFragment } from '@repo/graphql/types';
|
|
import { Card } from '@repo/ui/components/ui/card';
|
|
import { Label } from '@repo/ui/components/ui/label';
|
|
import { LoadingSpinner } from '@repo/ui/components/ui/spinner';
|
|
import { cn } from '@repo/ui/lib/utils';
|
|
import Image from 'next/image';
|
|
import { useEffect } from 'react';
|
|
|
|
type ContactsGridProps = {
|
|
readonly contacts: CustomerFieldsFragment[];
|
|
readonly onSelect: (contactId: null | string) => void;
|
|
readonly selected?: null | string;
|
|
readonly title: string;
|
|
};
|
|
|
|
export function ContactsGridBase({ contacts, onSelect, selected, title }: ContactsGridProps) {
|
|
return (
|
|
<Card className="p-4">
|
|
<div className="flex flex-col gap-4">
|
|
<CardSectionHeader title={title} />
|
|
<div className="grid max-h-screen grid-cols-4 gap-2 overflow-y-auto">
|
|
{contacts.map((contact) => {
|
|
if (!contact) return null;
|
|
|
|
const isCurrentUser = contact?.name === 'Я';
|
|
|
|
return (
|
|
<Label
|
|
className="flex cursor-pointer flex-col items-center"
|
|
key={contact?.documentId}
|
|
>
|
|
<input
|
|
checked={selected === contact?.documentId}
|
|
className="hidden"
|
|
name="user"
|
|
onChange={() => onSelect(contact?.documentId)}
|
|
type="radio"
|
|
value={contact?.documentId}
|
|
/>
|
|
<div
|
|
className={cn(
|
|
'w-20 h-20 rounded-full border-2 transition-all duration-75',
|
|
selected === contact?.documentId ? 'border-primary' : 'border-transparent',
|
|
)}
|
|
>
|
|
<div
|
|
className={cn(
|
|
'size-full rounded-full p-1',
|
|
isCurrentUser
|
|
? 'bg-gradient-to-r from-purple-500 to-pink-500'
|
|
: 'bg-transparent',
|
|
)}
|
|
>
|
|
<Image
|
|
alt={contact?.name}
|
|
className="size-full rounded-full object-cover"
|
|
height={80}
|
|
src={contact?.photoUrl || AvatarPlaceholder}
|
|
width={80}
|
|
/>
|
|
</div>
|
|
</div>
|
|
<span
|
|
className={cn(
|
|
'mt-2 max-w-20 break-words text-center text-sm font-medium',
|
|
isCurrentUser && 'font-bold',
|
|
)}
|
|
>
|
|
{contact?.name}
|
|
</span>
|
|
</Label>
|
|
);
|
|
})}
|
|
</div>
|
|
</div>
|
|
</Card>
|
|
);
|
|
}
|
|
|
|
export const MastersGrid = withContext(ContactsContextProvider)(function () {
|
|
const { contacts, isLoading, setFilter } = useCustomerContacts();
|
|
const masterId = useOrderStore((store) => store.masterId);
|
|
const setMasterId = useOrderStore((store) => store.setMasterId);
|
|
|
|
useEffect(() => {
|
|
setFilter('masters');
|
|
}, [setFilter]);
|
|
|
|
if (isLoading) return <LoadingSpinner />;
|
|
|
|
return (
|
|
<ContactsGridBase
|
|
contacts={contacts}
|
|
onSelect={(contactId) => setMasterId(contactId)}
|
|
selected={masterId}
|
|
title="Мастера"
|
|
/>
|
|
);
|
|
});
|
|
|
|
export const ClientsGrid = withContext(ContactsContextProvider)(function () {
|
|
const { contacts, isLoading, setFilter } = useCustomerContacts();
|
|
const clientId = useOrderStore((store) => store.clientId);
|
|
const setClientId = useOrderStore((store) => store.setClientId);
|
|
|
|
useEffect(() => {
|
|
setFilter('clients');
|
|
}, [setFilter]);
|
|
|
|
if (isLoading) return <LoadingSpinner />;
|
|
|
|
return (
|
|
<ContactsGridBase
|
|
contacts={contacts}
|
|
onSelect={(contactId) => setClientId(contactId)}
|
|
selected={clientId}
|
|
title="Клиенты"
|
|
/>
|
|
);
|
|
});
|