1299cd10ce
- /print/invoices/[id] sayfası: A4 fatura yazdırma/PDF (AutoPrint + PrintActionBar) - Fatura detayı header'ına PDF butonu eklendi (Yazdır yerine) - Appwrite Storage: entity-attachments bucket (20MB, şifreli) - Appwrite Tables: attachments collection (tenantId, entityType, entityId, fileId, name, size, mimeType) - attachment-actions.ts: fetchAttachmentsAction, uploadAttachmentAction, deleteAttachmentAction - AttachmentsPanel bileşeni: dosya yükleme/listeleme/silme, edit modunda görünür - Hizmet ve yazılım atama form sheet'lerine AttachmentsPanel entegrasyonu - /api/files/[attachmentId]: güvenli proxy indirme (tenant doğrulama + admin key ile Appwrite'a istek)
100 lines
2.9 KiB
TypeScript
100 lines
2.9 KiB
TypeScript
"use client";
|
||
|
||
import { useState, useTransition } from "react";
|
||
import { useRouter } from "next/navigation";
|
||
import { FileDown, Loader2, Pencil, Trash2 } from "lucide-react";
|
||
import { toast } from "sonner";
|
||
|
||
import { Button } from "@/components/ui/button";
|
||
import {
|
||
Dialog,
|
||
DialogContent,
|
||
DialogDescription,
|
||
DialogFooter,
|
||
DialogHeader,
|
||
DialogTitle,
|
||
} from "@/components/ui/dialog";
|
||
import { deleteInvoiceAction } from "@/lib/appwrite/invoice-actions";
|
||
|
||
import { InvoiceFormSheet } from "../../components/invoice-form-sheet";
|
||
import type { Customer, InvoiceRow } from "../../components/types";
|
||
|
||
type Props = { invoice: InvoiceRow; customers: Customer[] };
|
||
|
||
export function InvoiceHeaderActions({ invoice, customers }: Props) {
|
||
const router = useRouter();
|
||
const [editOpen, setEditOpen] = useState(false);
|
||
const [deleting, setDeleting] = useState(false);
|
||
const [busy, startTransition] = useTransition();
|
||
|
||
const handleDelete = () => {
|
||
startTransition(async () => {
|
||
const fd = new FormData();
|
||
fd.set("id", invoice.id);
|
||
const result = await deleteInvoiceAction(fd);
|
||
if (result.ok) {
|
||
toast.success("Fatura silindi.");
|
||
router.push("/invoices");
|
||
} else {
|
||
toast.error(result.error ?? "Silme başarısız.");
|
||
setDeleting(false);
|
||
}
|
||
});
|
||
};
|
||
|
||
return (
|
||
<>
|
||
<div className="flex flex-wrap gap-2">
|
||
<Button
|
||
variant="outline"
|
||
size="sm"
|
||
onClick={() => window.open(`/print/invoices/${invoice.id}`, "_blank")}
|
||
>
|
||
<FileDown className="size-3.5" />
|
||
PDF
|
||
</Button>
|
||
<Button variant="outline" size="sm" onClick={() => setEditOpen(true)}>
|
||
<Pencil className="size-3.5" />
|
||
Düzenle
|
||
</Button>
|
||
<Button
|
||
variant="ghost"
|
||
size="sm"
|
||
className="text-destructive hover:text-destructive"
|
||
onClick={() => setDeleting(true)}
|
||
>
|
||
<Trash2 className="size-3.5" />
|
||
Sil
|
||
</Button>
|
||
</div>
|
||
|
||
<InvoiceFormSheet
|
||
open={editOpen}
|
||
onOpenChange={setEditOpen}
|
||
invoice={invoice}
|
||
customers={customers}
|
||
/>
|
||
|
||
<Dialog open={deleting} onOpenChange={setDeleting}>
|
||
<DialogContent>
|
||
<DialogHeader>
|
||
<DialogTitle>Faturayı sil</DialogTitle>
|
||
<DialogDescription>
|
||
<strong>{invoice.number}</strong> ve tüm kalemleri silinecek. Bu işlem geri alınamaz.
|
||
</DialogDescription>
|
||
</DialogHeader>
|
||
<DialogFooter>
|
||
<Button variant="outline" onClick={() => setDeleting(false)} disabled={busy}>
|
||
Vazgeç
|
||
</Button>
|
||
<Button variant="destructive" onClick={handleDelete} disabled={busy}>
|
||
{busy ? <Loader2 className="size-4 animate-spin" /> : <Trash2 className="size-4" />}
|
||
Sil
|
||
</Button>
|
||
</DialogFooter>
|
||
</DialogContent>
|
||
</Dialog>
|
||
</>
|
||
);
|
||
}
|