import { formatCountryLabel } from "@shared/location-support.js"; import type { VisaSponsor, VisaSponsorSearchResult, VisaSponsorStatusResponse, } from "@shared/types.js"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { AlertCircle, Building2, CheckCircle2, ChevronRight, Clock, Download, FileSpreadsheet, Loader2, MapPin, Search, Shield, X, } from "lucide-react"; import type React from "react"; import { useEffect, useMemo, useState } from "react"; import { toast } from "sonner"; import { useQueryErrorToast } from "@/client/hooks/useQueryErrorToast"; import { queryKeys } from "@/client/lib/queryKeys"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { Drawer, DrawerClose, DrawerContent } from "@/components/ui/drawer"; import { Input } from "@/components/ui/input"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { cn, formatDateTime } from "@/lib/utils"; import * as api from "../api"; import { DetailPanel, EmptyState, ListItem, ListPanel, PageHeader, PageMain, ScoreMeter, SplitLayout, StatusIndicator, } from "../components"; const getScoreTokens = (score: number) => { if (score >= 90) return { badge: "border-emerald-500/30 bg-emerald-500/10 text-emerald-200", }; if (score >= 70) return { badge: "border-amber-500/30 bg-amber-500/10 text-amber-200" }; if (score >= 50) return { badge: "border-orange-500/30 bg-orange-500/10 text-orange-200" }; return { badge: "border-rose-500/30 bg-rose-500/10 text-rose-200" }; }; const ALL_SOURCES_VALUE = "__all_sources__"; const getSearchScopeLabel = (countryLabel: string) => countryLabel === "All sources" ? "all sources" : `the ${countryLabel} source`; const getResultKey = ( result: Pick, ) => `${result.providerId}::${result.sponsor.organisationName}`; export const VisaSponsorsPage: React.FC = () => { const queryClient = useQueryClient(); // State const [searchQuery, setSearchQuery] = useState(""); const [debouncedSearchQuery, setDebouncedSearchQuery] = useState(""); const [selectedResultKey, setSelectedResultKey] = useState( null, ); const [selectedCountry, setSelectedCountry] = useState(null); // Loading states const [isDetailDrawerOpen, setIsDetailDrawerOpen] = useState(false); const [isDesktop, setIsDesktop] = useState(() => typeof window !== "undefined" ? window.matchMedia("(min-width: 1024px)").matches : false, ); const statusQuery = useQuery({ queryKey: queryKeys.visaSponsors.status(), queryFn: api.getVisaSponsorStatus, }); const status = statusQuery.data ?? null; useQueryErrorToast(statusQuery.error, "Failed to fetch status"); const statusProviders = status?.providers ?? []; const providerOptions = statusProviders.map((provider) => ({ value: provider.countryKey, label: formatCountryLabel(provider.countryKey), providerId: provider.providerId, })); const selectedCountryLabel = providerOptions.find((option) => option.value === selectedCountry)?.label ?? "All sources"; const searchScopeLabel = getSearchScopeLabel(selectedCountryLabel); const activeProviders = selectedCountry ? statusProviders.filter( (provider) => provider.countryKey === selectedCountry, ) : statusProviders; const totalSponsors = activeProviders.reduce( (sum, provider) => sum + provider.totalSponsors, 0, ); const latestUpdatedAt = activeProviders.reduce( (latest, provider) => { if (!provider.lastUpdated) return latest; if (!latest) return provider.lastUpdated; return new Date(provider.lastUpdated) > new Date(latest) ? provider.lastUpdated : latest; }, null, ); useEffect(() => { const timer = setTimeout(() => { setDebouncedSearchQuery(searchQuery); }, 300); return () => clearTimeout(timer); }, [searchQuery]); const searchQueryResult = useQuery({ queryKey: queryKeys.visaSponsors.search( debouncedSearchQuery.trim(), 100, 20, selectedCountry ?? undefined, ), queryFn: () => api.searchVisaSponsors({ query: debouncedSearchQuery.trim(), limit: 100, minScore: 20, country: selectedCountry ?? undefined, }), enabled: Boolean(debouncedSearchQuery.trim()), }); useQueryErrorToast(searchQueryResult.error, "Search failed"); const results = useMemo(() => { if (!debouncedSearchQuery.trim()) return []; return searchQueryResult.data?.results ?? []; }, [debouncedSearchQuery, searchQueryResult.data]); const selectedResult = useMemo( () => results.find((r) => getResultKey(r) === selectedResultKey) ?? null, [results, selectedResultKey], ); const selectedOrg = selectedResult?.sponsor.organisationName ?? null; const orgDetailsQuery = useQuery({ queryKey: queryKeys.visaSponsors.organization( selectedOrg ?? "", selectedResult?.providerId, ), queryFn: () => selectedOrg ? api.getVisaSponsorOrganization( selectedOrg, selectedResult?.providerId, ) : Promise.resolve([]), enabled: Boolean(selectedOrg), }); const orgDetails = orgDetailsQuery.data ?? []; useQueryErrorToast(orgDetailsQuery.error, "Failed to fetch details"); // Auto-select first result useEffect(() => { if (results.length === 0) { setSelectedResultKey(null); return; } if ( !selectedResultKey || !results.some((r) => getResultKey(r) === selectedResultKey) ) { setSelectedResultKey(getResultKey(results[0])); } }, [results, selectedResultKey]); useEffect(() => { if (!selectedResultKey) { setIsDetailDrawerOpen(false); } }, [selectedResultKey]); useEffect(() => { if (typeof window === "undefined") return; const media = window.matchMedia("(min-width: 1024px)"); const handleChange = () => setIsDesktop(media.matches); handleChange(); if (media.addEventListener) { media.addEventListener("change", handleChange); return () => media.removeEventListener("change", handleChange); } media.addListener(handleChange); return () => media.removeListener(handleChange); }, []); useEffect(() => { if (isDesktop && isDetailDrawerOpen) { setIsDetailDrawerOpen(false); } }, [isDesktop, isDetailDrawerOpen]); // Trigger manual update const updateListMutation = useMutation({ mutationFn: api.updateVisaSponsorList, onSuccess: async (result) => { queryClient.setQueryData(queryKeys.visaSponsors.status(), result.status); if (debouncedSearchQuery.trim()) { await queryClient.invalidateQueries({ queryKey: queryKeys.visaSponsors.search( debouncedSearchQuery.trim(), 100, 20, selectedCountry ?? undefined, ), }); } toast.success(result.message); }, onError: (error) => { const message = error instanceof Error ? error.message : "Update failed"; toast.error(message); }, }); const handleUpdate = async () => { await updateListMutation.mutateAsync(); }; const handleSelectOrg = (resultKey: string) => { setSelectedResultKey(resultKey); if (!isDesktop) { setIsDetailDrawerOpen(true); } }; const handleCountryChange = (value: string) => { setSelectedCountry(value === ALL_SOURCES_VALUE ? null : value); setSelectedResultKey(null); setIsDetailDrawerOpen(false); }; const isUpdateInProgress = updateListMutation.isPending || statusProviders.some((provider) => provider.isUpdating); const isLoadingStatus = statusQuery.isLoading; const isSearching = searchQueryResult.isFetching; const isLoadingDetails = orgDetailsQuery.isLoading; const detailPanelContent = !selectedResult ? (
Select a company

Pick a company from the results to see details here.

) : isLoadingDetails ? (
) : (
{/* Header */}
Licensed Sponsor {selectedResult && ( {selectedResult.score}% Match )}

{selectedOrg}

Source: {formatCountryLabel(selectedResult.countryKey)}

{/* Location */} {orgDetails.length > 0 && (orgDetails[0].townCity || orgDetails[0].county) && (
Location
{[orgDetails[0].townCity, orgDetails[0].county] .filter(Boolean) .join(", ")}
)} {/* Licence types / routes */}
Licensed Routes ({orgDetails.length})
{orgDetails.map((entry) => (
{entry.route}
Type & Rating: {" "} {entry.typeRating}
))}
{/* Info box */}
What does this mean?

This organisation appears in the selected sponsor source and may be able to sponsor workers on the routes listed above. Always verify the latest source entry before relying on it.

); return ( <> : undefined } subtitle="Search sponsor data across available sources" actions={ <> {status && (
{totalSponsors.toLocaleString()} sponsors {formatDateTime(latestUpdatedAt) || "Never"}
)} } /> {/* Search section */}
setSearchQuery(e.target.value)} className="pl-10 pr-10 h-10" autoFocus /> {searchQuery && ( )}

Enter a company name to check if they're a licensed visa sponsor in {searchScopeLabel}.

{/* Left panel - Results */} 0 ? (
{results.length} result{results.length !== 1 ? "s" : ""} {isSearching && ( )}
) : null } > {!isLoadingStatus && status && totalSponsors === 0 && ( {isUpdateInProgress ? ( <> Downloading... ) : ( <> Download List )} } /> )} {status && totalSponsors > 0 && !searchQuery && ( )} {searchQuery && !isSearching && results.length === 0 && ( )} {results.length > 0 && results.map((result) => ( handleSelectOrg(getResultKey(result))} className="gap-3" >
{result.sponsor.organisationName}
{(result.sponsor.townCity || result.sponsor.county) && (
{[ formatCountryLabel(result.countryKey), result.sponsor.townCity, result.sponsor.county, ] .filter(Boolean) .join(", ")}
)} {!result.sponsor.townCity && !result.sponsor.county && result.countryKey && (
{formatCountryLabel(result.countryKey)}
)}
))}
{/* Right panel - Details */} {detailPanelContent}
Sponsor details
{detailPanelContent}
); };