"use client" import { useCallback, useMemo, useState } from "react" import { useRouter } from "next/navigation" import { useTranslations } from "next-intl" import { toast } from "sonner" import { AlertCircle, ArrowLeft, Check, ChevronsUpDown, Info, Leaf, ShieldAlert, User, } from "lucide-react" import type { AvailableBatch, Member, QuotaStatus } from "@/types/api" import { getMockQuota, mockAvailableBatches } from "@/data/mock/distributions" import { mockMembers } from "@/data/mock/members" import { Badge } from "@/components/ui/badge" import { Button } from "@/components/ui/button" import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from "@/components/ui/card" import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, } from "@/components/ui/command" import { Input } from "@/components/ui/input" import { Label } from "@/components/ui/label" import { Progress } from "@/components/ui/progress" // Step indicator component function StepIndicator({ currentStep, steps, }: { currentStep: number steps: string[] }) { return (
{steps.map((step, i) => (
{i < currentStep ? : i + 1}
{step} {i < steps.length - 1 && (
)}
))}
) } // Quota bar with color coding function QuotaBar({ label, used, limit, unit, }: { label: string used: number limit: number unit: string }) { const percent = (used / limit) * 100 const colorClass = percent >= 80 ? "bg-red-500" : percent >= 50 ? "bg-amber-500" : "bg-green-500" return (
{label} {used} / {limit} {unit}
) } export default function NewDistributionPage() { const t = useTranslations("distributions") const router = useRouter() const [step, setStep] = useState(0) const [selectedMember, setSelectedMember] = useState(null) const [quota, setQuota] = useState(null) const [selectedBatch, setSelectedBatch] = useState( null ) const [amount, setAmount] = useState("") const [memberSearch, setMemberSearch] = useState("") const [showMemberList, setShowMemberList] = useState(false) const steps = [t("step1"), t("step2"), t("step3"), t("step4")] // Filter active members for the combobox const activeMembers = useMemo( () => mockMembers.filter((m) => m.status === "ACTIVE"), [] ) const filteredMembers = useMemo(() => { if (!memberSearch) return activeMembers const search = memberSearch.toLowerCase() return activeMembers.filter( (m) => `${m.firstName} ${m.lastName}`.toLowerCase().includes(search) || m.memberNumber.toLowerCase().includes(search) ) }, [memberSearch, activeMembers]) // Check if member is blocked const isMemberBlocked = useCallback((member: Member) => { return member.status === "SUSPENDED" || member.status === "EXPELLED" }, []) // Check if member is under 21 const isUnder21 = useCallback((member: Member) => { const birthDate = new Date(member.dateOfBirth) const today = new Date() const age = today.getFullYear() - birthDate.getFullYear() const monthDiff = today.getMonth() - birthDate.getMonth() if ( monthDiff < 0 || (monthDiff === 0 && today.getDate() < birthDate.getDate()) ) { return age - 1 < 21 } return age < 21 }, []) // Handle member selection const handleSelectMember = useCallback( (member: Member) => { setSelectedMember(member) setShowMemberList(false) if (isMemberBlocked(member)) { return // Stay on step 0, show error } // Load quota const q = getMockQuota(member.id) setQuota(q) setStep(1) }, [isMemberBlocked] ) // Validation for amount const amountNum = parseFloat(amount) || 0 const validationErrors = useMemo(() => { const errors: string[] = [] if (!selectedBatch || amountNum <= 0) return errors if (amountNum > selectedBatch.availableGrams) { errors.push(t("exceedsBatch")) } if (quota && amountNum > quota.dailyLimitGrams - quota.dailyUsedGrams) { errors.push(t("exceedsDaily", { limit: quota.dailyLimitGrams })) } if (quota && amountNum > quota.monthlyLimitGrams - quota.monthlyUsedGrams) { errors.push(t("exceedsMonthly", { limit: quota.monthlyLimitGrams })) } return errors }, [amountNum, selectedBatch, quota, t]) const canProceedToConfirm = selectedBatch && amountNum > 0 && validationErrors.length === 0 // Confirm distribution const handleConfirm = () => { // Mock: log + toast + redirect console.log("Distribution recorded:", { memberId: selectedMember?.id, memberName: `${selectedMember?.firstName} ${selectedMember?.lastName}`, batchId: selectedBatch?.id, strainName: selectedBatch?.strainName, amountGrams: amountNum, recordedBy: "Maria Schulz", recordedAt: new Date().toISOString(), status: "COMPLETED", }) toast.success(t("success")) router.push("/distributions") } return (
{/* Header */}

{t("newDistribution")}

{/* Step indicator */} {/* Step 1: Member Selection */} {step === 0 && ( {t("step1")} {t("selectMember")} {/* Member search combobox */}
setShowMemberList(!showMemberList)} > {selectedMember ? ( {selectedMember.firstName} {selectedMember.lastName} ( {selectedMember.memberNumber}) ) : ( {t("selectMember")} )}
{showMemberList && (
Kein Mitglied gefunden. {filteredMembers.slice(0, 8).map((member) => ( handleSelectMember(member)} className="cursor-pointer" >
{member.firstName} {member.lastName} {member.memberNumber}
{member.status !== "ACTIVE" && ( {member.status} )}
))}
)}
{/* Selected member card */} {selectedMember && (

{selectedMember.firstName} {selectedMember.lastName}

{selectedMember.memberNumber} · Mitglied seit{" "} {new Date(selectedMember.joinedAt).toLocaleDateString( "de-DE" )}

{selectedMember.status === "ACTIVE" ? "Aktiv" : selectedMember.status}
{/* Blocked member warning */} {isMemberBlocked(selectedMember) && (

{t("memberBlocked")}

)} {/* Under 21 info */} {!isMemberBlocked(selectedMember) && isUnder21(selectedMember) && (

{t("under21Info")}

)}
)} {/* If member is active and selected, show "Next" button */} {selectedMember && !isMemberBlocked(selectedMember) && step === 0 && ( )}
)} {/* Step 2: Quota Check */} {step === 1 && quota && ( {t("step2")} {selectedMember?.firstName} {selectedMember?.lastName} {quota.isUnder21 && " (unter 21)"} {quota.isUnder21 && (

{t("under21Info")}

)}
)} {/* Step 3: Batch Selection & Amount */} {step === 2 && ( {t("step3")} {/* Batch selection */}
{mockAvailableBatches.map((batch) => (
setSelectedBatch(batch)} className={`flex cursor-pointer items-center justify-between rounded-lg border p-3 transition-colors ${ selectedBatch?.id === batch.id ? "border-primary bg-primary/5" : "border-border hover:bg-muted/50" }`} >

{batch.strainName}

THC: {batch.thcPercent}%

{batch.availableGrams}g {t("available")}
))}
{/* Amount input */} {selectedBatch && (
setAmount(e.target.value)} placeholder="0.0" className="font-mono text-lg" /> {/* Validation errors */} {validationErrors.length > 0 && (
{validationErrors.map((error) => (
{error}
))}
)} {/* Show remaining after this distribution */} {amountNum > 0 && validationErrors.length === 0 && quota && (

Tagesrest danach:{" "} {( quota.dailyLimitGrams - quota.dailyUsedGrams - amountNum ).toFixed(1)} g

Monatsrest danach:{" "} {( quota.monthlyLimitGrams - quota.monthlyUsedGrams - amountNum ).toFixed(1)} g

)}
)}
)} {/* Step 4: Confirmation */} {step === 3 && selectedMember && selectedBatch && ( {t("step4")} {t("summary")} {/* Summary card */}
{t("member")} {selectedMember.firstName} {selectedMember.lastName}
{t("strain")} {selectedBatch.strainName}
{t("amount")} {amountNum}g
{t("staff")} Maria Schulz
)}
) }