"use client"; import { useEffect, useMemo, useState } from "react"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { useLocale, useTranslations } from "next-intl"; import { Plus, Trash2 } from "lucide-react"; import { apiDelete, apiGet, apiGetPaged, apiPost } from "@/lib/api/client"; import { useAuthStore } from "@/lib/stores/auth.store"; import { formatCurrency, formatNumber } from "@/lib/format"; import { isoTodayTehran } from "@/lib/reports/analytics"; import { PageHeader } from "@/components/layout/page-header"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { JalaliDateField } from "@/components/ui/jalali-date-field"; import { LabeledField } from "@/components/ui/labeled-field"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; type Branch = { id: string; name: string }; type ShiftDto = { id: string; branchId: string; status: string; }; export type ExpenseCategory = | "Supplies" | "Utilities" | "Salary" | "Rent" | "Maintenance" | "Other"; export type ExpenseRow = { id: string; cafeId: string; branchId: string; shiftId?: string | null; category: ExpenseCategory; amount: number; note?: string | null; receiptImageUrl?: string | null; createdByUserId: string; createdAt: string; }; const CATEGORIES: ExpenseCategory[] = [ "Supplies", "Utilities", "Salary", "Rent", "Maintenance", "Other", ]; const MANAGER_ROLES = new Set(["Owner", "Manager"]); export function ExpensesScreen() { const t = useTranslations("expenses"); const tCommon = useTranslations("common"); const locale = useLocale(); const numberLocale = locale === "en" ? "en-US" : "fa-IR"; const cafeId = useAuthStore((s) => s.user?.cafeId); const role = useAuthStore((s) => s.user?.role ?? ""); const queryClient = useQueryClient(); const today = isoTodayTehran(); const [branchId, setBranchId] = useState(""); const [from, setFrom] = useState(today); const [to, setTo] = useState(today); const [showModal, setShowModal] = useState(false); const [category, setCategory] = useState("Supplies"); const [amount, setAmount] = useState(""); const [note, setNote] = useState(""); const [linkShift, setLinkShift] = useState(true); const { data: branches = [] } = useQuery({ queryKey: ["branches", cafeId], queryFn: () => apiGet(`/api/cafes/${cafeId}/branches`), enabled: !!cafeId, }); useEffect(() => { if (!branchId && branches.length > 0) setBranchId(branches[0]!.id); }, [branchId, branches]); const { data: currentShift } = useQuery({ queryKey: ["shift-current", cafeId, branchId], queryFn: async () => { try { return await apiGet( `/api/cafes/${cafeId}/branches/${branchId}/shifts/current` ); } catch { return null; } }, enabled: !!cafeId && !!branchId, }); const listKey = ["expenses", cafeId, branchId, from, to] as const; const { data: listResponse, isLoading } = useQuery({ queryKey: listKey, queryFn: () => apiGetPaged( `/api/cafes/${cafeId}/expenses?branchId=${encodeURIComponent(branchId)}&from=${from}&to=${to}&page=1&pageSize=50` ), enabled: !!cafeId && !!branchId && !!from && !!to, }); const rows = useMemo(() => listResponse?.items ?? [], [listResponse?.items]); const totalAmount = useMemo(() => rows.reduce((s, r) => s + r.amount, 0), [rows]); const createExpense = useMutation({ mutationFn: () => apiPost(`/api/cafes/${cafeId}/expenses`, { branchId, shiftId: linkShift && currentShift ? currentShift.id : null, category, amount: Number(amount), note: note.trim() || null, receiptImageUrl: null, }), onSuccess: () => { queryClient.invalidateQueries({ queryKey: listKey }); setShowModal(false); setAmount(""); setNote(""); setCategory("Supplies"); }, }); const deleteExpense = useMutation({ mutationFn: (id: string) => apiDelete(`/api/cafes/${cafeId}/expenses/${id}`), onSuccess: () => queryClient.invalidateQueries({ queryKey: listKey }), }); const canDelete = MANAGER_ROLES.has(role); if (!cafeId) return null; return (
setShowModal(true)} disabled={!branchId} > {t("addExpense")} } />

{t("periodTotal")}

{formatCurrency(totalAmount, numberLocale)}

{t("listTitle")} {canDelete ? {isLoading ? ( ) : rows.length === 0 ? ( ) : ( rows.map((row) => ( {canDelete ? ( ) : null} )) )}
{t("colDate")} {t("colCategory")} {t("colNote")} {t("colAmount")} : null}
{t("loading")}
{t("empty")}
{new Date(row.createdAt).toLocaleString( locale === "en" ? "en-GB" : "fa-IR", { dateStyle: "short", timeStyle: "short" } )} {t(`categories.${row.category}`)} {row.note ?? "—"} {formatCurrency(row.amount, numberLocale)}
{listResponse?.meta ? (

{t("rowCount", { count: formatNumber(listResponse.meta.total, numberLocale), })}

) : null}
{showModal ? (
{t("addExpense")} setAmount(e.target.value)} /> setNote(e.target.value)} placeholder={t("notePlaceholder")} /> {currentShift ? ( ) : (

{t("noOpenShift")}

)}
) : null}
); }