"use client"; import { useState } from "react"; import { FieldType } from "@capakraken/shared"; import type { BlueprintFieldDefinition } from "@capakraken/shared"; import { trpc } from "~/lib/trpc/client.js"; interface Props { selectedIds: string[]; fieldDefs: BlueprintFieldDefinition[]; onClose: () => void; onSuccess: () => void; } export function BulkEditModal({ selectedIds, fieldDefs, onClose, onSuccess }: Props) { // Track which fields are included in the bulk update + their new values const [included, setIncluded] = useState>(new Set()); const [values, setValues] = useState>({}); const [error, setError] = useState(null); const utils = trpc.useUtils(); const mutation = trpc.resource.batchUpdateCustomFields.useMutation({ onSuccess: () => { void utils.resource.directory.invalidate(); void utils.resource.listStaff.invalidate(); onSuccess(); onClose(); }, onError: (err) => setError(err.message), }); function toggleInclude(key: string) { setIncluded((prev) => { const next = new Set(prev); if (next.has(key)) { next.delete(key); } else { next.add(key); } return next; }); } function setValue(key: string, value: unknown) { setValues((prev) => ({ ...prev, [key]: value })); } function handleSave() { setError(null); const fields: Record = {}; for (const key of included) { const val = values[key] ?? ""; fields[key] = typeof val === "string" || typeof val === "number" || typeof val === "boolean" ? val : String(val); } if (Object.keys(fields).length === 0) { setError("Select at least one field to update."); return; } mutation.mutate({ ids: selectedIds, fields }); } function handleBackdrop(e: React.MouseEvent) { if (e.target === e.currentTarget) onClose(); } const editableFields = fieldDefs.filter((f) => !f.required || included.has(f.key)); return (

Bulk Edit Custom Fields

Updating {selectedIds.length} resource{selectedIds.length !== 1 ? "s" : ""}

{fieldDefs.length === 0 && (

No custom fields defined. Configure them in Admin → Blueprints.

)} {fieldDefs.map((field) => (
{included.has(field.key) && ( setValue(field.key, v)} /> )}
))}
{error && (
{error}
)}

{included.size} field{included.size !== 1 ? "s" : ""} selected

); } function FieldInput({ field, value, onChange, }: { field: BlueprintFieldDefinition; value: unknown; onChange: (v: unknown) => void; }) { const str = value !== undefined && value !== null ? String(value) : ""; if (field.type === FieldType.BOOLEAN) { return ( ); } if (field.type === FieldType.SELECT && field.options) { return ( ); } if (field.type === FieldType.NUMBER) { return ( onChange(e.target.value ? Number(e.target.value) : "")} placeholder={field.placeholder} className="app-input" /> ); } if (field.type === FieldType.DATE) { return ( onChange(e.target.value)} className="app-input" /> ); } if (field.type === FieldType.TEXTAREA) { return (