feat(frontend): QR-Code-Dialog auf Objekt-Detailseiten (Modul 22)
Wiederverwendbarer QrCodeDialog (authentifizierter Blob-Fetch) auf Volk-, Bienenstand-, Koenigin-, Honigcharge-Detailseiten und je Lagerbehaelter-Zeile eingebunden.
This commit is contained in:
1 parent
dd88b6a92c
commit
8b7fd61c1c
8 files changed
+102
-3
No files matched your search
@@ -0,0 +1,65 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { QrCode } from "lucide-react";
|
||||
import { fetchQrCodeSvg, QrEntityType } from "@/lib/qr/api";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@/components/ui/dialog";
|
||||
|
||||
interface QrCodeDialogProps {
|
||||
entityType: QrEntityType;
|
||||
id: string;
|
||||
label?: string;
|
||||
}
|
||||
|
||||
export function QrCodeDialog({ entityType, id, label = "QR-Code" }: QrCodeDialogProps) {
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
const { data: blob, isLoading, isError } = useQuery({
|
||||
queryKey: ["qr", entityType, id],
|
||||
queryFn: () => fetchQrCodeSvg(entityType, id),
|
||||
enabled: open,
|
||||
});
|
||||
|
||||
const objectUrl = useMemo(() => (blob ? URL.createObjectURL(blob) : null), [blob]);
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
if (objectUrl) URL.revokeObjectURL(objectUrl);
|
||||
};
|
||||
}, [objectUrl]);
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={setOpen}>
|
||||
<DialogTrigger
|
||||
render={
|
||||
<Button variant="outline" size="sm">
|
||||
<QrCode className="size-4" />
|
||||
{label}
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
<DialogContent className="flex flex-col items-center gap-4">
|
||||
<DialogHeader>
|
||||
<DialogTitle>{label}</DialogTitle>
|
||||
</DialogHeader>
|
||||
{isLoading ? <p className="text-sm text-muted-foreground">Lädt…</p> : null}
|
||||
{isError ? (
|
||||
<p role="alert" className="text-sm text-destructive">
|
||||
QR-Code konnte nicht geladen werden.
|
||||
</p>
|
||||
) : null}
|
||||
{objectUrl ? (
|
||||
// eslint-disable-next-line @next/next/no-img-element -- blob: object URL, next/image cannot handle this
|
||||
<img src={objectUrl} alt="QR-Code" className="size-64 rounded-lg border bg-white p-3" />
|
||||
) : null}
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user