'use client' import { useState, useMemo } from 'react' import { Input } from '@/components/ui/input' import { Badge } from '@/components/ui/badge' import { Button } from '@/components/ui/button' import { Search, ChevronDown, ChevronUp, AlertTriangle, Info } from 'lucide-react' import { getCommonTemplates, getAdvancedTemplates, searchTemplates, type BookingTemplate, type TemplateGroup, } from '@/lib/bookkeeping/booking-templates' import type { EntityType } from '@/types' import type { SuggestedTemplate } from '@/lib/transactions/category-suggestions' const GROUP_ORDER: TemplateGroup[] = [ 'premises', 'vehicle', 'it_software', 'office_supplies', 'marketing', 'travel', 'representation', 'insurance', 'professional_services', 'bank_finance', 'telecom', 'education', 'personnel', 'revenue', 'financial', 'private_transfers', 'equipment', ] const GROUP_LABELS: Record = { premises: 'Lokalkostnader', vehicle: 'Fordon', it_software: 'IT & Programvara', office_supplies: 'Kontorsmaterial', marketing: 'Marknadsföring', travel: 'Resor & Transport', representation: 'Representation', insurance: 'Försäkringar', professional_services: 'Professionella tjänster', bank_finance: 'Bank & Finans', telecom: 'Telekom & Internet', education: 'Utbildning', personnel: 'Personal', revenue: 'Intäkter', financial: 'Finansiella poster', private_transfers: 'Privata transaktioner', equipment: 'Inventarier & Utrustning', } function getVatLabel(template: BookingTemplate): string | null { if (!template.vat_treatment) return null switch (template.vat_treatment) { case 'standard_25': return '25% moms' case 'reduced_12': return '12% moms' case 'reduced_6': return '6% moms' case 'reverse_charge': return 'Omvänd moms' case 'export': return 'Momsfri (export)' case 'exempt': return 'Momsfri' default: return null } } function groupTemplates(templates: BookingTemplate[]): Map { const grouped = new Map() for (const t of templates) { const list = grouped.get(t.group) || [] list.push(t) grouped.set(t.group, list) } return grouped } interface TemplateCardProps { template: BookingTemplate selected: boolean onClick: () => void compact?: boolean } function TemplateCard({ template, selected, onClick, compact }: TemplateCardProps) { const vatLabel = getVatLabel(template) return ( ) } interface TemplatePickerProps { direction: 'expense' | 'income' entityType?: EntityType suggestedTemplates?: SuggestedTemplate[] recentTemplateIds?: string[] onSelect: (template: BookingTemplate) => void selectedTemplateId?: string } export default function TemplatePicker({ direction, entityType, suggestedTemplates, onSelect, selectedTemplateId, }: TemplatePickerProps) { const [searchQuery, setSearchQuery] = useState('') const [showAdvanced, setShowAdvanced] = useState(false) // Map direction to template direction filter (transfers show in both) const templateDirection = direction === 'income' ? 'income' : 'expense' const commonTemplates = useMemo( () => getCommonTemplates(entityType, templateDirection), [entityType, templateDirection] ) const advancedTemplates = useMemo( () => getAdvancedTemplates(entityType, templateDirection), [entityType, templateDirection] ) // Also include transfer templates in both directions const commonTransfers = useMemo( () => getCommonTemplates(entityType, 'transfer'), [entityType] ) const advancedTransfers = useMemo( () => getAdvancedTemplates(entityType, 'transfer'), [entityType] ) const allCommon = useMemo( () => [...commonTemplates, ...commonTransfers], [commonTemplates, commonTransfers] ) const allAdvanced = useMemo( () => [...advancedTemplates, ...advancedTransfers], [advancedTemplates, advancedTransfers] ) // Search results const searchResults = useMemo(() => { if (!searchQuery.trim()) return null return searchTemplates(searchQuery, entityType).filter((t) => { if (t.direction === templateDirection || t.direction === 'transfer') return true return false }) }, [searchQuery, entityType, templateDirection]) // Group templates by group for display const commonGrouped = useMemo(() => groupTemplates(allCommon), [allCommon]) const advancedGrouped = useMemo(() => groupTemplates(allAdvanced), [allAdvanced]) const handleSelect = (template: BookingTemplate) => { onSelect(template) } // Suggested templates section const hasSuggestions = suggestedTemplates && suggestedTemplates.length > 0 return (
{/* Search bar */}
setSearchQuery(e.target.value)} placeholder="Sök mall..." className="pl-9 h-9" />
{/* Scrollable content */}
{/* Search results */} {searchResults !== null ? (

{searchResults.length === 0 ? 'Inga resultat' : `${searchResults.length} resultat`}

{searchResults.map((t) => ( handleSelect(t)} /> ))}
) : ( <> {/* Suggested templates */} {hasSuggestions && (

Föreslagna

{suggestedTemplates!.slice(0, 5).map((s) => { // Find the full template object const fullTemplate = allCommon.find((t) => t.id === s.template_id) || allAdvanced.find((t) => t.id === s.template_id) if (!fullTemplate) return null return ( handleSelect(fullTemplate)} compact /> ) })}
)} {/* Common templates grouped */}

Vanliga mallar

{GROUP_ORDER.filter((g) => commonGrouped.has(g)).map((group) => (

{GROUP_LABELS[group]}

{commonGrouped.get(group)!.map((t) => ( handleSelect(t)} compact /> ))}
))}
{/* Advanced templates (collapsible) */} {allAdvanced.length > 0 && (
{showAdvanced && (
{GROUP_ORDER.filter((g) => advancedGrouped.has(g)).map((group) => (

{GROUP_LABELS[group]}

{advancedGrouped.get(group)!.map((t) => ( handleSelect(t)} compact /> ))}
))}
)}
)} )}
) }