297 lines
10 KiB
TypeScript
297 lines
10 KiB
TypeScript
"use client"
|
||
|
||
import { useState } from "react"
|
||
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "@/components/ui/dialog"
|
||
import { Button } from "@/components/ui/button"
|
||
import { Download, ImageIcon, FileText, Box, Loader2 } from "lucide-react"
|
||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
|
||
import { Checkbox } from "@/components/ui/checkbox"
|
||
import { Label } from "@/components/ui/label"
|
||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
|
||
import { getDesignShoppingList } from "@/lib/actions/export.actions"
|
||
import { useToast } from "@/hooks/use-toast"
|
||
import { usePlannerExport } from "@/hooks/use-planner-export"
|
||
import type { Design } from "@/lib/types/planner.types"
|
||
|
||
interface ExportDialogProps {
|
||
open: boolean
|
||
onOpenChange: (open: boolean) => void
|
||
design: Design
|
||
}
|
||
|
||
export function ExportDialog({ open, onOpenChange, design }: ExportDialogProps) {
|
||
const [loading, setLoading] = useState(false)
|
||
const [selectedAngles, setSelectedAngles] = useState<string[]>(["iso"])
|
||
const [resolution, setResolution] = useState<"hd" | "fhd" | "4k" | "8k">("fhd")
|
||
const { toast } = useToast()
|
||
|
||
// Get export functions from the hook (only works inside Canvas context)
|
||
// We'll pass the design and use a ref to access canvas
|
||
|
||
const handleImageExport = async () => {
|
||
setLoading(true)
|
||
try {
|
||
// Get canvas element
|
||
const canvas = document.querySelector("canvas")
|
||
if (!canvas) {
|
||
throw new Error("Canvas not found")
|
||
}
|
||
|
||
// Import utilities
|
||
const { captureCanvasScreenshot, downloadDataUrl, getResolutionDimensions } = await import("@/lib/utils/canvas-export")
|
||
|
||
const dimensions = getResolutionDimensions(resolution)
|
||
const dataUrl = await captureCanvasScreenshot(canvas, {
|
||
...dimensions,
|
||
format: "png",
|
||
})
|
||
|
||
// Download image
|
||
const filename = `${design.name}-${selectedAngles.join("-")}.png`
|
||
downloadDataUrl(dataUrl, filename)
|
||
|
||
toast({
|
||
title: "Sikeres exportálás",
|
||
description: "Kép sikeresen exportálva",
|
||
})
|
||
onOpenChange(false)
|
||
} catch (error: any) {
|
||
toast({
|
||
title: "Hiba",
|
||
description: error.message,
|
||
variant: "destructive",
|
||
})
|
||
} finally {
|
||
setLoading(false)
|
||
}
|
||
}
|
||
|
||
const handlePDFExport = async () => {
|
||
setLoading(true)
|
||
try {
|
||
// Get canvas and capture screenshot
|
||
const canvas = document.querySelector("canvas")
|
||
if (!canvas) {
|
||
throw new Error("Canvas not found")
|
||
}
|
||
|
||
const { captureCanvasScreenshot } = await import("@/lib/utils/canvas-export")
|
||
const dataUrl = await captureCanvasScreenshot(canvas, {
|
||
width: 1920,
|
||
height: 1080,
|
||
format: "png",
|
||
})
|
||
|
||
// Get shopping list
|
||
const shoppingList = await getDesignShoppingList(design.id)
|
||
|
||
// Generate PDF
|
||
const { generateDesignPDF, downloadPDF } = await import("@/lib/utils/pdf-generator")
|
||
const pdfBlob = await generateDesignPDF(
|
||
design,
|
||
[{ name: "3D View", dataUrl }],
|
||
shoppingList,
|
||
{
|
||
includeImages: true,
|
||
includeShoppingList: true,
|
||
includeDimensions: true,
|
||
includeMaterials: true,
|
||
includeQRCode: true,
|
||
watermark: true,
|
||
}
|
||
)
|
||
|
||
const filename = `${design.name}-Report.pdf`
|
||
downloadPDF(pdfBlob, filename)
|
||
|
||
toast({
|
||
title: "Sikeres exportálás",
|
||
description: "PDF riport sikeresen létrehozva",
|
||
})
|
||
onOpenChange(false)
|
||
} catch (error: any) {
|
||
toast({
|
||
title: "Hiba",
|
||
description: error.message,
|
||
variant: "destructive",
|
||
})
|
||
} finally {
|
||
setLoading(false)
|
||
}
|
||
}
|
||
|
||
const handle3DExport = async () => {
|
||
setLoading(true)
|
||
try {
|
||
toast({
|
||
title: "Exportálás folyamatban",
|
||
description: "3D modell előkészítése...",
|
||
})
|
||
|
||
// Note: Actual GLB export requires access to THREE.js scene
|
||
// This is a placeholder - would need scene access from Canvas
|
||
toast({
|
||
title: "Funkció fejlesztés alatt",
|
||
description: "3D modell export hamarosan elérhető",
|
||
})
|
||
|
||
onOpenChange(false)
|
||
} catch (error: any) {
|
||
toast({
|
||
title: "Hiba",
|
||
description: error.message,
|
||
variant: "destructive",
|
||
})
|
||
} finally {
|
||
setLoading(false)
|
||
}
|
||
}
|
||
|
||
return (
|
||
<Dialog open={open} onOpenChange={onOpenChange}>
|
||
<DialogContent className="max-w-2xl">
|
||
<DialogHeader>
|
||
<DialogTitle>Terv exportálása</DialogTitle>
|
||
<DialogDescription>Válassz exportálási formátumot és beállításokat</DialogDescription>
|
||
</DialogHeader>
|
||
|
||
<Tabs defaultValue="image" className="w-full">
|
||
<TabsList className="grid w-full grid-cols-3">
|
||
<TabsTrigger value="image" className="gap-2">
|
||
<ImageIcon className="w-4 h-4" />
|
||
Képek
|
||
</TabsTrigger>
|
||
<TabsTrigger value="pdf" className="gap-2">
|
||
<FileText className="w-4 h-4" />
|
||
PDF Riport
|
||
</TabsTrigger>
|
||
<TabsTrigger value="3d" className="gap-2">
|
||
<Box className="w-4 h-4" />
|
||
3D Modell
|
||
</TabsTrigger>
|
||
</TabsList>
|
||
|
||
<TabsContent value="image" className="space-y-4">
|
||
<div className="space-y-3">
|
||
<div>
|
||
<Label className="mb-2 block">Felbontás:</Label>
|
||
<Select value={resolution} onValueChange={(v: any) => setResolution(v)}>
|
||
<SelectTrigger>
|
||
<SelectValue />
|
||
</SelectTrigger>
|
||
<SelectContent>
|
||
<SelectItem value="hd">HD (1280×720)</SelectItem>
|
||
<SelectItem value="fhd">Full HD (1920×1080)</SelectItem>
|
||
<SelectItem value="4k">4K (3840×2160)</SelectItem>
|
||
<SelectItem value="8k">8K (7680×4320)</SelectItem>
|
||
</SelectContent>
|
||
</Select>
|
||
</div>
|
||
|
||
<Label>Válassz nézeteket:</Label>
|
||
<div className="space-y-2">
|
||
{[
|
||
{ value: "front", label: "Elölnézet" },
|
||
{ value: "back", label: "Hátulnézet" },
|
||
{ value: "left", label: "Bal oldal" },
|
||
{ value: "right", label: "Jobb oldal" },
|
||
{ value: "top", label: "Felülnézet" },
|
||
{ value: "iso", label: "Izometrikus (3D)" },
|
||
].map((angle) => (
|
||
<div key={angle.value} className="flex items-center gap-2">
|
||
<Checkbox
|
||
id={angle.value}
|
||
checked={selectedAngles.includes(angle.value)}
|
||
onCheckedChange={(checked) => {
|
||
setSelectedAngles(
|
||
checked ? [...selectedAngles, angle.value] : selectedAngles.filter((a) => a !== angle.value),
|
||
)
|
||
}}
|
||
/>
|
||
<Label htmlFor={angle.value} className="cursor-pointer">
|
||
{angle.label}
|
||
</Label>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
|
||
<Button onClick={handleImageExport} disabled={loading || selectedAngles.length === 0} className="w-full">
|
||
{loading ? (
|
||
<>
|
||
<Loader2 className="w-4 h-4 mr-2 animate-spin" />
|
||
Exportálás...
|
||
</>
|
||
) : (
|
||
<>
|
||
<Download className="w-4 h-4 mr-2" />
|
||
Kép letöltése ({resolution.toUpperCase()})
|
||
</>
|
||
)}
|
||
</Button>
|
||
</TabsContent>
|
||
|
||
<TabsContent value="pdf" className="space-y-4">
|
||
<div className="space-y-2 text-sm text-muted-foreground">
|
||
<p>A PDF riport tartalmazza:</p>
|
||
<ul className="list-disc list-inside space-y-1 ml-2">
|
||
<li>Terv képek (több nézetből)</li>
|
||
<li>Bevásárló lista termékekkel és árakkal</li>
|
||
<li>Szoba méretek és specifikációk</li>
|
||
<li>QR kód a terv megosztásához</li>
|
||
</ul>
|
||
</div>
|
||
|
||
<Button onClick={handlePDFExport} disabled={loading} className="w-full">
|
||
{loading ? (
|
||
<>
|
||
<Loader2 className="w-4 h-4 mr-2 animate-spin" />
|
||
Exportálás...
|
||
</>
|
||
) : (
|
||
<>
|
||
<Download className="w-4 h-4 mr-2" />
|
||
PDF letöltése
|
||
</>
|
||
)}
|
||
</Button>
|
||
</TabsContent>
|
||
|
||
<TabsContent value="3d" className="space-y-4">
|
||
<div className="rounded-lg bg-amber-500/10 border border-amber-500/20 p-4">
|
||
<p className="text-sm text-amber-600 font-medium">Prémium funkció</p>
|
||
<p className="text-sm text-muted-foreground mt-1">
|
||
3D modell exportálásához prémium előfizetés szükséges
|
||
</p>
|
||
</div>
|
||
|
||
<div className="space-y-2 text-sm text-muted-foreground">
|
||
<p>A .glb fájl importálható:</p>
|
||
<ul className="list-disc list-inside space-y-1 ml-2">
|
||
<li>Blender</li>
|
||
<li>SketchUp</li>
|
||
<li>AutoCAD</li>
|
||
<li>És más 3D szoftverek</li>
|
||
</ul>
|
||
</div>
|
||
|
||
<Button onClick={handle3DExport} disabled={loading} className="w-full">
|
||
{loading ? (
|
||
<>
|
||
<Loader2 className="w-4 h-4 mr-2 animate-spin" />
|
||
Exportálás...
|
||
</>
|
||
) : (
|
||
<>
|
||
<Download className="w-4 h-4 mr-2" />
|
||
.glb fájl letöltése
|
||
</>
|
||
)}
|
||
</Button>
|
||
</TabsContent>
|
||
</Tabs>
|
||
</DialogContent>
|
||
</Dialog>
|
||
)
|
||
}
|