import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { LOCALES } from '@barev/i18n'; import { Badge, Button, Card, Field } from '@barev/ui'; import QRCode from 'qrcode'; import { confirmDialog, errorText, useI18n, useToast, useTRPC } from '@barev/web'; import { Fragment, useEffect, useState } from 'react'; const CATEGORIES = ['cafe', 'restaurant', 'shop', 'beauty', 'other'] as const; type Draft = { id?: string; category: (typeof CATEGORIES)[number]; name: string; offer: Record; address: string; active: boolean }; const EMPTY: Draft = { category: 'cafe', name: '', offer: { ru: '', en: '', zh: '', hy: '', es: '' }, address: '', active: true }; /** Партнёры клуба: что получает клиент по клубной карте — показывается в приложении на вкладке «Скидки» */ export function Partners() { const { t, locale } = useI18n(); const trpc = useTRPC(); const qc = useQueryClient(); const toast = useToast(); const list = useQuery(trpc.admin.partners.list.queryOptions()); const [d, setD] = useState(null); const [open, setOpen] = useState(null); const save = useMutation( trpc.admin.partners.save.mutationOptions({ onSuccess: () => { toast(t('admin.saved')); setD(null); void qc.invalidateQueries(); }, onError: (e) => toast(errorText(t, e), 'error'), }), ); return ( <>

{t('admin.nav.partners')}

{d && ( setD({ ...d, name: e.target.value })} /> {LOCALES.map((l) => ( setD({ ...d, offer: { ...d.offer, [l]: e.target.value } })} /> ))} setD({ ...d, address: e.target.value })} />
)} {list.data?.map((p) => { const offer = p.offer as Record; return ( {open === p.id && ( )} ); })}
{t('admin.partners.name')} {t('admin.partners.offer')} {t('admin.partners.address')}
{p.name}
{t(`client.partners.cat.${p.category}`)}
{t('admin.partners.summary', { offers: p.offers.length, members: p.members.length, visits: p._count.usages })}
{offer[locale] || offer.ru} {p.address ?? '—'}
); } type Offer = { id: string; title: unknown; minLevel: 'BAREV_PLUS' | 'ELITE' | null; limit: 'NONE' | 'ONCE' | 'WEEK' | 'MONTH'; limitCount: number; active: boolean }; type OfferDraft = { id?: string; title: Record; minLevel: Offer['minLevel']; limit: Offer['limit']; limitCount: number; active: boolean }; const LEVELS = [null, 'BAREV_PLUS', 'ELITE'] as const; const LIMITS = ['NONE', 'ONCE', 'WEEK', 'MONTH'] as const; /** Предложения партнёра по уровням и лимитам, ссылка для собственника, команда */ function PartnerDetails({ partner }: { partner: { id: string; offers: Offer[]; members: { id: string; role: 'OWNER' | 'STAFF'; user: { firstName: string | null; lastName: string | null; username: string | null } }[] } }) { const { t, locale } = useI18n(); const trpc = useTRPC(); const qc = useQueryClient(); const toast = useToast(); const [od, setOd] = useState(null); const [link, setLink] = useState(null); const [qr, setQr] = useState(''); useEffect(() => { if (link) void QRCode.toString(link, { type: 'svg', margin: 1 }).then(setQr); }, [link]); const done = { onSuccess: () => { toast(t('admin.saved')); setOd(null); void qc.invalidateQueries(); }, onError: (e: unknown) => toast(errorText(t, e), 'error'), }; const saveOffer = useMutation(trpc.admin.partners.saveOffer.mutationOptions(done)); const removeMember = useMutation(trpc.admin.partners.removeMember.mutationOptions(done)); const owner = useMutation(trpc.admin.partners.ownerInvite.mutationOptions({ onSuccess: (r) => setLink(r.url), onError: done.onError })); const levelName = (l: Offer['minLevel']) => (l === 'ELITE' ? 'Barev Elite' : l === 'BAREV_PLUS' ? 'Barev+' : t('admin.partners.allMembers')); const limitName = (o: { limit: Offer['limit']; limitCount: number }) => t(`admin.partners.limit_${o.limit}`, { count: o.limitCount }); return (
{t('admin.partners.offers')}
{od && (
{LOCALES.map((l) => ( setOd({ ...od, title: { ...od.title, [l]: e.target.value } })} /> ))} {(od.limit === 'WEEK' || od.limit === 'MONTH') && ( setOd({ ...od, limitCount: Number(e.target.value) || 1 })} /> )}
)} {partner.offers.length === 0 &&

{t('admin.partners.noOffers')}

} {partner.offers.map((o) => { const title = o.title as Record; return (
{title[locale] || title.ru}{' '} {levelName(o.minLevel)}{' '} {limitName(o)}
); })}
{t('admin.partners.team')}
{link && (
{t('admin.partners.ownerLinkHint')} e.target.select()} />
)} {partner.members.length === 0 &&

{t('admin.partners.noTeam')}

} {partner.members.map((m) => (
{m.user.firstName} {m.user.lastName ?? ''} {m.user.username && @{m.user.username}} · {t(m.role === 'OWNER' ? 'pro.partner.owner' : 'pro.partner.staff')}
))}
); }