"use client"; import { LocalizedFields, type LocalizedFieldLocale, type LocalizedFieldValues } from "@/components/i18n/localized-fields"; import { useTranslations } from "@/components/i18n/i18n-provider"; import { contentTranslationRegistry } from "@/lib/i18n/content"; import { getDocumentIntlLocale } from "@/lib/i18n/browser"; import { createProposalRecord, deleteProposalRecord, updateProposalRecord } from "./actions"; import { CheckCircle2, FileEdit, Mail, MoreHorizontal, Plus, Trash2, XCircle } from "lucide-react"; import { useState } from "react"; import { Badge, Button, Card, CardContent, Input, Label } from "poyraz-ui/atoms"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, toast, } from "poyraz-ui/molecules"; export type BusinessRelationOption = { id: string; name: string; client_id?: string | null; }; export type ProposalRow = { id: string; title: string; description: string | null; amount: number; currency: string; status: "draft" | "sent" | "accepted" | "rejected"; valid_until: string | null; client_id: string | null; project_id: string | null; clientName: string | null; projectName: string | null; created_at: string; translations?: LocalizedFieldValues; }; type ProposalsClientProps = { proposals: ProposalRow[]; clients: BusinessRelationOption[]; projects: BusinessRelationOption[]; localization: { defaultLocale: string; locales: LocalizedFieldLocale[]; }; }; const proposalStatuses = ["draft", "sent", "accepted", "rejected"] as const; const currencyOptions = ["TRY", "USD", "EUR", "GBP"] as const; export function ProposalsClient({ proposals, clients, projects, localization }: ProposalsClientProps) { const t = useTranslations(); return (

{t("business.proposals.title")}

{t("business.proposals.table.title")}{t("business.common.client")}{t("business.common.amount")}{t("business.common.status")}{t("business.proposals.table.validUntil")}{t("business.common.actions")} {proposals.length === 0 ? ( ) : ( proposals.map((proposal) => ( )) )}
{t("business.proposals.empty")}
{proposal.title} {proposal.projectName ? (
{proposal.projectName}
) : null}
{proposal.clientName || "-"} {formatCurrency(proposal.amount, proposal.currency)} {proposal.valid_until ? formatDate(proposal.valid_until) : "-"}
); } function ProposalMenu({ proposal, clients, projects, localization }: { proposal: ProposalRow; clients: BusinessRelationOption[]; projects: BusinessRelationOption[]; localization: ProposalsClientProps["localization"]; }) { const t = useTranslations(); return ( {t("business.proposals.actions.send")} {t("business.proposals.status.accepted")} {t("business.proposals.status.rejected")}
); } function ProposalDialog({ mode, proposal, clients, projects, localization, trigger = "button" }: { mode: "create" | "edit"; proposal?: ProposalRow; clients: BusinessRelationOption[]; projects: BusinessRelationOption[]; localization: ProposalsClientProps["localization"]; trigger?: "button" | "menu"; }) { const t = useTranslations(); const [open, setOpen] = useState(false); const [isSubmitting, setIsSubmitting] = useState(false); const action = mode === "create" ? createProposalRecord : updateProposalRecord; async function handleSubmit(formData: FormData) { setIsSubmitting(true); try { await action(formData); setOpen(false); toast.success(t(mode === "create" ? "business.proposals.messages.created" : "business.proposals.messages.updated")); } catch (error) { toast.error(resolveTranslatedError(t, error, "business.proposals.errors.saveFailed")); } finally { setIsSubmitting(false); } } return ( {trigger === "menu" ? ( ) : ( )}
{proposal ? : null} {t(mode === "create" ? "business.proposals.form.createTitle" : "business.proposals.form.editTitle")} {t("business.proposals.form.description")}
({ ...field, label: t(`business.proposals.fields.${field.name}`), placeholder: "placeholder" in field && typeof field.placeholder === "string" ? t(`business.proposals.placeholders.${field.name}`) : undefined, }))} values={proposal?.translations} fallbackValues={{ title: proposal?.title, description: proposal?.description }} />
{t("business.common.none")} {clients.map((client) => {client.name})} {t("business.common.none")} {projects.map((project) => {project.name})}
{currencyOptions.map((currency) => {currency})} {proposalStatuses.map((status) => {t(`business.proposals.status.${status}`)})}
); } function ProposalStatusBadge({ status }: { status: ProposalRow["status"] }) { const t = useTranslations(); if (status === "draft") return {t("business.proposals.status.draft")}; if (status === "sent") return {t("business.proposals.status.sent")}; if (status === "accepted") return {t("business.proposals.status.accepted")}; return {t("business.proposals.status.rejected")}; } function TableHead({ className = "", children }: { className?: string; children: React.ReactNode }) { return {children}; } function Field({ label, children }: { label: string; children: React.ReactNode }) { return
{children}
; } function SelectField({ name, label, defaultValue, children }: { name: string; label: string; defaultValue: string; children: React.ReactNode }) { return ( ); } function formatCurrency(amount: number, currency: string) { return new Intl.NumberFormat(getDocumentIntlLocale(), { style: "currency", currency }).format(amount); } function formatDate(value: string) { return new Intl.DateTimeFormat(getDocumentIntlLocale(), { day: "2-digit", month: "short", year: "numeric" }).format(new Date(value)); } function resolveTranslatedError(t: ReturnType, error: unknown, fallbackKey: string) { if (!(error instanceof Error)) return t(fallbackKey); if (/^business\./.test(error.message)) return t(error.message); return error.message || t(fallbackKey); }