'use client'; import { useCallback, useState } from 'react'; import type { DeckCard } from '@linkder/db'; import { Deck } from '@/components/deck'; import { api } from '@/lib/trpc'; /** * Bridges the server-rendered deck to the swipe mutation. * * Swipes are optimistic: the card leaves immediately and the write happens in * the background. A rejected right-swipe (usually the open-request cap) surfaces * as a banner rather than snapping the card back — the person has moved on, and * the pro is still on the deck server-side, so they will see them again on the * next load. */ export function DeckClient({ jobId, initialCards }: { jobId: string; initialCards: DeckCard[] }) { const [notice, setNotice] = useState<{ kind: 'sent' | 'error'; text: string } | null>(null); const utils = api.useUtils(); const swipe = api.deck.swipe.useMutation({ onSuccess: (result, variables) => { if (result.requested) { const card = initialCards.find((c) => c.proId === variables.proId); setNotice({ kind: 'sent', text: `Job sent to ${card?.name ?? 'the pro'}. You will hear back once they accept.`, }); } // Invalidate rather than revalidatePath, so the same call works unchanged // from React Native. void utils.deck.list.invalidate({ jobId }); }, onError: (error) => { setNotice({ kind: 'error', text: error.message }); }, }); const onDecide = useCallback( (proId: string, direction: 'left' | 'right') => { swipe.mutate({ jobId, proId, direction }); }, [jobId, swipe], ); return (