← back to Trademarks Copyright

src/components/DropEditor.tsx

112 lines

"use client";

import { useEffect, useState } from "react";

type Item = {
  id: number; position: number;
  headline: string; blurb: string;
  pro_extra: string | null; cta_text: string | null; cta_url: string | null;
  source_kind: string; source_id: number;
};

export default function DropEditor({ dropId, onClose }: { dropId: number; onClose: () => void }) {
  const [items, setItems] = useState<Item[]>([]);
  const [loading, setLoading] = useState(true);
  const [savingId, setSavingId] = useState<number | null>(null);
  const [saved, setSaved] = useState<Record<number, boolean>>({});

  useEffect(() => {
    fetch(`/api/drops/drop-items/${dropId}`)
      .then((r) => r.json())
      .then((j) => { setItems(j.items || []); setLoading(false); });
  }, [dropId]);

  function update(id: number, field: keyof Item, value: string) {
    setItems((L) => L.map((it) => (it.id === id ? { ...it, [field]: value } : it)));
    setSaved((s) => ({ ...s, [id]: false }));
  }

  async function save(it: Item) {
    setSavingId(it.id);
    try {
      const r = await fetch(`/api/drops/drop-items/${it.id}`, {
        method: "PATCH",
        headers: { "content-type": "application/json" },
        body: JSON.stringify({
          headline: it.headline,
          blurb: it.blurb,
          pro_extra: it.pro_extra,
          cta_text: it.cta_text,
          cta_url: it.cta_url,
        }),
      });
      if (r.ok) setSaved((s) => ({ ...s, [it.id]: true }));
    } finally { setSavingId(null); }
  }

  return (
    <div className="fixed inset-0 z-50 flex items-start justify-center bg-black/40 p-4 overflow-auto" onClick={onClose}>
      <div className="card w-full max-w-4xl bg-parchment my-10" onClick={(e) => e.stopPropagation()}>
        <div className="flex items-center justify-between border-b border-ink/10 px-5 py-3">
          <h2 className="text-lg font-semibold">Edit drop #{dropId}</h2>
          <button onClick={onClose} className="btn-ghost">Close</button>
        </div>
        {loading ? (
          <div className="p-6 text-ink/50">Loading…</div>
        ) : items.length === 0 ? (
          <div className="p-6 text-ink/50">No items.</div>
        ) : (
          <div className="divide-y divide-ink/10">
            {items.map((it) => (
              <div key={it.id} className="p-5 space-y-2">
                <div className="flex items-center gap-3">
                  <span className="text-xs text-ink/50">#{it.position}</span>
                  <span className="tag">{it.source_kind}:{it.source_id}</span>
                  <div className="ml-auto flex items-center gap-2">
                    {saved[it.id] && <span className="text-xs text-emerald-700">✓ saved</span>}
                    <button className="btn" disabled={savingId !== null} onClick={() => save(it)}>
                      {savingId === it.id ? "Saving…" : "Save"}
                    </button>
                  </div>
                </div>
                <input
                  value={it.headline}
                  onChange={(e) => update(it.id, "headline", e.target.value)}
                  className="w-full font-semibold text-lg"
                />
                <textarea
                  value={it.blurb}
                  onChange={(e) => update(it.id, "blurb", e.target.value)}
                  rows={3}
                  className="w-full text-sm"
                />
                <textarea
                  value={it.pro_extra ?? ""}
                  onChange={(e) => update(it.id, "pro_extra", e.target.value)}
                  rows={2}
                  placeholder="PRO-only extra (tactical hint, leave blank for none)"
                  className="w-full text-sm bg-brass/10 border-brass/30"
                />
                <div className="flex gap-2">
                  <input
                    value={it.cta_text ?? ""}
                    onChange={(e) => update(it.id, "cta_text", e.target.value)}
                    placeholder="CTA label"
                    className="w-40"
                  />
                  <input
                    value={it.cta_url ?? ""}
                    onChange={(e) => update(it.id, "cta_url", e.target.value)}
                    placeholder="CTA URL"
                    className="flex-1"
                  />
                </div>
              </div>
            ))}
          </div>
        )}
      </div>
    </div>
  );
}