"use client"
import { useRouter } from "next/navigation"
import { useState, useSyncExternalStore, useTransition } from "react"
import { CopyPlusIcon, DownloadIcon, ExternalLinkIcon, RefreshCwIcon, Trash2Icon } from "lucide-react"
import { Button, buttonVariants } from "@/components/ui/button"
import { CopyField } from "@/modules/admin/ui/components/copy-field"
import { deleteVariant, duplicateVariant, updateShare } from "../../../actions/variants"
import { dateFormat, SHARE_EXPIRY_OPTIONS } from "../../../lib/preview"
import type { EditorVariant } from "../../views/variant-editor"
const selectClass = "h-10 w-full rounded-md border bg-background px-3 text-sm outline-none focus-visible:ring-3 focus-visible:ring-ring/50"
const subscribe = () => () => {}
function Heading({ title, text }: { title: string; text?: string }) {
return (
)
}
export function SharePanel({ variant, clients, clientId, onClientChange, dirty }: {
variant: EditorVariant
clients: { id: string; name: string }[]
clientId: string | null
onClientChange: (clientId: string | null) => void
dirty: boolean
}) {
const router = useRouter()
const origin = useSyncExternalStore(subscribe, () => window.location.origin, () => "")
const [share, setShare] = useState({ token: variant.shareToken, expiresAt: variant.shareExpiresAt, expired: variant.shareState === "expired" })
// -1 = bestehendes Ablaufdatum beibehalten
const [expiry, setExpiry] = useState(variant.shareExpiresAt ? -1 : 0)
const [confirmDelete, setConfirmDelete] = useState(false)
const [exporting, setExporting] = useState(false)
const [error, setError] = useState(null)
const [pending, startTransition] = useTransition()
function run(action: () => Promise<{ error: string } | unknown>) {
startTransition(async () => {
const result = await action()
if (result && typeof result === "object" && "error" in result) setError(String(result.error))
else setError(null)
})
}
function applyShare(enabled: boolean, options: { regenerate?: boolean; days?: number } = {}) {
run(async () => {
const days = options.days ?? (expiry < 0 ? 0 : expiry)
const result = await updateShare(variant.id, { enabled, expiresInDays: days, regenerate: options.regenerate })
if (!("error" in result)) {
setShare({ ...result, expired: false })
setExpiry(result.expiresAt ? days : 0)
}
return result
})
}
async function exportProject() {
setExporting(true)
try {
const response = await fetch(`/api/templates/${variant.id}/export`)
if (!response.ok) {
const body = await response.json().catch(() => null)
setError(body?.error ?? "Export fehlgeschlagen.")
return
}
const fileName = /filename="([^"]+)"/.exec(response.headers.get("Content-Disposition") ?? "")?.[1] ?? "website.zip"
const link = document.createElement("a")
link.href = URL.createObjectURL(await response.blob())
link.download = fileName
link.click()
URL.revokeObjectURL(link.href)
setError(null)
} catch {
setError("Export fehlgeschlagen.")
} finally {
setExporting(false)
}
}
const url = share.token ? `${origin}/demo/${share.token}` : ""
return (
{share.token ? (
{share.expired && (
Dieser Link ist abgelaufen. Wähle eine neue Gültigkeit, um ihn wieder zu aktivieren.
)}
Öffnen
„Neuer Link“ macht den bisherigen Link ungültig.
) : (
)}
{dirty && Exportiert wird der gespeicherte Stand.
}
{dirty &&
Dupliziert wird der gespeicherte Stand.
}
{confirmDelete ? (
) : (
)}
{error &&
{error}
}
)
}