131 lines
4.4 KiB
TypeScript
131 lines
4.4 KiB
TypeScript
'use client'
|
|
|
|
import { Dialog } from '@headlessui/react'
|
|
import { useEffect, useState, useRef } from 'react'
|
|
import Button from './Button'
|
|
|
|
export type CookieEntry = { name: string; value: string }
|
|
|
|
type CookieModalProps = {
|
|
open: boolean
|
|
onClose: () => void
|
|
onApply: (cookies: CookieEntry[]) => void
|
|
initialCookies: CookieEntry[]
|
|
}
|
|
|
|
export default function CookieModal({
|
|
open,
|
|
onClose,
|
|
onApply,
|
|
initialCookies,
|
|
}: CookieModalProps) {
|
|
const [name, setName] = useState('')
|
|
const [value, setValue] = useState('')
|
|
const [cookies, setCookies] = useState<CookieEntry[]>([])
|
|
const wasOpen = useRef(false)
|
|
|
|
// ✅ Beim Öffnen: Inputs resetten UND Cookies aus Props übernehmen
|
|
useEffect(() => {
|
|
if (open && !wasOpen.current) {
|
|
setName('')
|
|
setValue('')
|
|
setCookies(initialCookies ?? [])
|
|
}
|
|
wasOpen.current = open
|
|
}, [open, initialCookies])
|
|
|
|
function addCookie() {
|
|
const n = name.trim()
|
|
const v = value.trim()
|
|
if (!n || !v) return
|
|
|
|
setCookies((prev) => {
|
|
const filtered = prev.filter((c) => c.name !== n)
|
|
return [...filtered, { name: n, value: v }]
|
|
})
|
|
|
|
setName('')
|
|
setValue('')
|
|
}
|
|
|
|
function removeCookie(n: string) {
|
|
setCookies((prev) => prev.filter((c) => c.name !== n))
|
|
}
|
|
|
|
function applyAndClose() {
|
|
onApply(cookies)
|
|
onClose()
|
|
}
|
|
|
|
return (
|
|
<Dialog open={open} onClose={onClose} className="relative z-50">
|
|
<div className="fixed inset-0 bg-black/40" aria-hidden="true" />
|
|
<div className="fixed inset-0 flex items-center justify-center p-4">
|
|
<Dialog.Panel className="w-full max-w-lg rounded-lg bg-white dark:bg-gray-800 p-6 shadow-xl dark:outline dark:-outline-offset-1 dark:outline-white/10">
|
|
<Dialog.Title className="text-base font-semibold text-gray-900 dark:text-white">
|
|
Zusätzliche Cookies
|
|
</Dialog.Title>
|
|
|
|
<div className="mt-4 grid grid-cols-1 sm:grid-cols-3 gap-2">
|
|
<input
|
|
value={name}
|
|
onChange={(e) => setName(e.target.value)}
|
|
placeholder="Name (z. B. cf_clearance)"
|
|
className="col-span-1 truncate rounded-md px-3 py-2 text-sm bg-white text-gray-900 dark:bg-white/10 dark:text-white"
|
|
/>
|
|
<input
|
|
value={value}
|
|
onChange={(e) => setValue(e.target.value)}
|
|
placeholder="Wert"
|
|
className="col-span-1 truncate sm:col-span-2 rounded-md px-3 py-2 text-sm bg-white text-gray-900 dark:bg-white/10 dark:text-white"
|
|
/>
|
|
</div>
|
|
|
|
<div className="mt-2">
|
|
<Button size="sm" variant="secondary" onClick={addCookie} disabled={!name.trim() || !value.trim()}>
|
|
Hinzufügen
|
|
</Button>
|
|
</div>
|
|
|
|
<div className="mt-4">
|
|
{cookies.length === 0 ? (
|
|
<div className="text-sm text-gray-500 dark:text-gray-400">Noch keine Cookies hinzugefügt.</div>
|
|
) : (
|
|
<table className="min-w-full text-sm border divide-y dark:divide-white/10">
|
|
<thead className="bg-gray-50 dark:bg-gray-700/50">
|
|
<tr>
|
|
<th className="px-3 py-2 text-left font-medium">Name</th>
|
|
<th className="px-3 py-2 text-left font-medium">Wert</th>
|
|
<th className="px-3 py-2" />
|
|
</tr>
|
|
</thead>
|
|
<tbody className="divide-y dark:divide-white/10">
|
|
{cookies.map((c) => (
|
|
<tr key={c.name}>
|
|
<td className="px-3 py-2 font-mono">{c.name}</td>
|
|
<td className="px-3 py-2 truncate max-w-[240px]">{c.value}</td>
|
|
<td className="px-3 py-2 text-right">
|
|
<button
|
|
onClick={() => removeCookie(c.name)}
|
|
className="text-xs text-red-600 hover:underline dark:text-red-400"
|
|
>
|
|
Entfernen
|
|
</button>
|
|
</td>
|
|
</tr>
|
|
))}
|
|
</tbody>
|
|
</table>
|
|
)}
|
|
</div>
|
|
|
|
<div className="mt-6 flex justify-end gap-2">
|
|
<Button variant="secondary" onClick={onClose}>Abbrechen</Button>
|
|
<Button variant="primary" onClick={applyAndClose}>Übernehmen</Button>
|
|
</div>
|
|
</Dialog.Panel>
|
|
</div>
|
|
</Dialog>
|
|
)
|
|
}
|