fa70168622
- /alisveris, /alisveris/:id ve /alisveris/:id/mod sayfaları; odak ve 30 sn yenileme - stok önerileri paneli, kalem ekle/düzenle/taşı, mağazaya gruplu kontrol listesi - dashboard Alışveriş kartı, kenar menü, ürün tipi formunda hacimli işareti Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
87 lines
2.8 KiB
TypeScript
87 lines
2.8 KiB
TypeScript
"use client";
|
||
|
||
import { useRouter } from "next/navigation";
|
||
import { useState } from "react";
|
||
import { toast } from "sonner";
|
||
import { ResponsiveDialog } from "@/components/responsive-dialog";
|
||
import { Button } from "@/components/ui/button";
|
||
import { Field, FieldError, FieldGroup, FieldLabel } from "@/components/ui/field";
|
||
import { Input } from "@/components/ui/input";
|
||
import { tr } from "@/i18n/tr";
|
||
import { saveShoppingListAction } from "../actions";
|
||
|
||
const t = tr.shopping;
|
||
|
||
/** Yeni liste / listeyi düzenle. Yeni liste açılınca detayına gider. */
|
||
export function ShoppingListDialog({
|
||
list,
|
||
onClose,
|
||
}: {
|
||
list: { id: string; name: string; note: string } | null;
|
||
onClose: () => void;
|
||
}) {
|
||
const router = useRouter();
|
||
const [v, setV] = useState({ name: list?.name ?? "", note: list?.note ?? "" });
|
||
const [errors, setErrors] = useState<Record<string, string | undefined>>({});
|
||
const [busy, setBusy] = useState(false);
|
||
|
||
async function submit(e: React.FormEvent) {
|
||
e.preventDefault();
|
||
setBusy(true);
|
||
const r = await saveShoppingListAction(list?.id ?? null, v);
|
||
setBusy(false);
|
||
if (!r.ok) {
|
||
setErrors({ ...r.fieldErrors, root: r.fieldErrors ? undefined : r.error });
|
||
return;
|
||
}
|
||
toast.success(t.toast.saved);
|
||
onClose();
|
||
if (!list && r.data && typeof r.data === "object" && "id" in r.data)
|
||
router.push(`/alisveris/${r.data.id}`);
|
||
}
|
||
|
||
return (
|
||
<ResponsiveDialog
|
||
open
|
||
onOpenChange={(o) => !o && onClose()}
|
||
title={list ? t.editTitle : t.createTitle}
|
||
footer={
|
||
<>
|
||
<Button variant="outline" type="button" onClick={onClose}>
|
||
{tr.common.cancel}
|
||
</Button>
|
||
<Button type="submit" form="shopping-list-form" disabled={busy}>
|
||
{tr.common.save}
|
||
</Button>
|
||
</>
|
||
}
|
||
>
|
||
<form id="shopping-list-form" onSubmit={submit} noValidate>
|
||
<FieldGroup>
|
||
<Field data-invalid={Boolean(errors.name)}>
|
||
<FieldLabel htmlFor="sl-name">{t.fields.name}</FieldLabel>
|
||
<Input
|
||
id="sl-name"
|
||
value={v.name}
|
||
placeholder={t.fields.namePlaceholder}
|
||
onChange={(e) => setV((s) => ({ ...s, name: e.target.value }))}
|
||
aria-invalid={Boolean(errors.name)}
|
||
autoFocus
|
||
/>
|
||
{errors.name ? <FieldError>{errors.name}</FieldError> : null}
|
||
</Field>
|
||
<Field>
|
||
<FieldLabel htmlFor="sl-note">{t.fields.note}</FieldLabel>
|
||
<Input
|
||
id="sl-note"
|
||
value={v.note}
|
||
onChange={(e) => setV((s) => ({ ...s, note: e.target.value }))}
|
||
/>
|
||
</Field>
|
||
{errors.root ? <FieldError>{errors.root}</FieldError> : null}
|
||
</FieldGroup>
|
||
</form>
|
||
</ResponsiveDialog>
|
||
);
|
||
}
|