"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 { createSubscriptionRecord, deleteSubscriptionRecord, updateSubscriptionRecord } from "./actions"; import { CreditCard, FileEdit, MoreHorizontal, Plus, RefreshCw, StopCircle, Trash2 } 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 SubscriptionRow = { id: string; name: string; amount: number; currency: string; billing_cycle: "monthly" | "yearly" | "weekly"; status: "active" | "cancelled"; category: string | null; next_billing_date: string | null; created_at: string; translations?: LocalizedFieldValues; }; type SubscriptionsClientProps = { subscriptions: SubscriptionRow[]; localization: { defaultLocale: string; locales: LocalizedFieldLocale[]; }; }; const billingCycles = ["weekly", "monthly", "yearly"] as const; const subscriptionStatuses = ["active", "cancelled"] as const; const currencyOptions = ["TRY", "USD", "EUR", "GBP"] as const; export function SubscriptionsClient({ subscriptions, localization }: SubscriptionsClientProps) { const t = useTranslations(); const activeMonthlyTotal = subscriptions .filter((subscription) => subscription.status === "active") .reduce((total, subscription) => total + monthlyEquivalent(subscription), 0); return (

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

{t("business.subscriptions.stats.monthlyTotal")}

{formatCurrency(activeMonthlyTotal, "TRY")}

{t("business.subscriptions.stats.monthlyTotalDesc")}

{t("business.subscriptions.table.name")}{t("business.subscriptions.fields.category")}{t("business.common.amount")}{t("business.subscriptions.fields.billingCycle")}{t("business.common.status")}{t("business.subscriptions.fields.nextBillingDate")}{t("business.common.actions")} {subscriptions.length === 0 ? ( ) : ( subscriptions.map((subscription) => ( )) )}
{t("business.subscriptions.empty")}
{subscription.name} {subscription.category || "-"} {formatCurrency(subscription.amount, subscription.currency)} {t(`business.subscriptions.billingCycle.${subscription.billing_cycle}`)} {subscription.next_billing_date ? formatDate(subscription.next_billing_date) : "-"}
); } function SubscriptionMenu({ subscription, localization }: { subscription: SubscriptionRow; localization: SubscriptionsClientProps["localization"] }) { const t = useTranslations(); return ( {subscription.status === "active" ? : } {subscription.status === "active" ? t("business.subscriptions.actions.cancel") : t("business.subscriptions.actions.reactivate")}
); } function SubscriptionDialog({ mode, subscription, localization, trigger = "button" }: { mode: "create" | "edit"; subscription?: SubscriptionRow; localization: SubscriptionsClientProps["localization"]; trigger?: "button" | "menu"; }) { const t = useTranslations(); const [open, setOpen] = useState(false); const [isSubmitting, setIsSubmitting] = useState(false); const action = mode === "create" ? createSubscriptionRecord : updateSubscriptionRecord; async function handleSubmit(formData: FormData) { setIsSubmitting(true); try { await action(formData); setOpen(false); toast.success(t(mode === "create" ? "business.subscriptions.messages.created" : "business.subscriptions.messages.updated")); } catch (error) { toast.error(resolveTranslatedError(t, error, "business.subscriptions.errors.saveFailed")); } finally { setIsSubmitting(false); } } return ( {trigger === "menu" ? ( ) : ( )}
{subscription ? : null} {t(mode === "create" ? "business.subscriptions.form.createTitle" : "business.subscriptions.form.editTitle")} {t("business.subscriptions.form.description")}
({ ...field, label: t(`business.subscriptions.fields.${field.name}`), placeholder: "placeholder" in field && typeof field.placeholder === "string" ? t(`business.subscriptions.placeholders.${field.name}`) : undefined, }))} values={subscription?.translations} fallbackValues={{ name: subscription?.name, category: subscription?.category }} />
{currencyOptions.map((currency) => {currency})} {billingCycles.map((cycle) => {t(`business.subscriptions.billingCycle.${cycle}`)})} {subscriptionStatuses.map((status) => {t(`business.subscriptions.status.${status}`)})}
); } function SubscriptionStatusBadge({ status }: { status: SubscriptionRow["status"] }) { const t = useTranslations(); return status === "active" ? {t("business.subscriptions.status.active")} : {t("business.subscriptions.status.cancelled")}; } 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 monthlyEquivalent(subscription: SubscriptionRow) { if (subscription.billing_cycle === "yearly") return subscription.amount / 12; if (subscription.billing_cycle === "weekly") return subscription.amount * 4.33; return subscription.amount; } 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}T00:00:00`)); } 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); }