EventBuzz_Console/src/app/components/participants/ParticipantBulkDialogs.tsx

143 lines
7.4 KiB
TypeScript

import React from "react";
import type { Event } from "../../../services/api/types";
import type { ParticipantListRecord } from "../../../services/api/participantLists";
export type BulkDialogKind = null | "addTags" | "removeTags" | "assignEvents" | "newList" | "addToList";
export function ParticipantBulkDialogs({
bulkDialog,
bulkBusy,
selectedCount,
tagBulkInput,
onTagBulkInputChange,
newListName,
onNewListNameChange,
newListDesc,
onNewListDescChange,
eventsPick,
eventPickIds,
onToggleEventPick,
fixedLists,
addToListId,
onAddToListIdChange,
onClose,
onApplyTags,
onAssignEvents,
onCreateList,
onAddToList,
}: {
bulkDialog: BulkDialogKind;
bulkBusy: boolean;
selectedCount: number;
tagBulkInput: string;
onTagBulkInputChange: (v: string) => void;
newListName: string;
onNewListNameChange: (v: string) => void;
newListDesc: string;
onNewListDescChange: (v: string) => void;
eventsPick: Event[];
eventPickIds: Set<string>;
onToggleEventPick: (id: string) => void;
fixedLists: ParticipantListRecord[];
addToListId: string;
onAddToListIdChange: (id: string) => void;
onClose: () => void;
onApplyTags: (action: "add_tags" | "remove_tags") => void;
onAssignEvents: () => void;
onCreateList: () => void;
onAddToList: () => void;
}) {
const overlay = (children: React.ReactNode) => (
<div
role="dialog"
aria-modal="true"
style={{ position: "fixed", inset: 0, background: "rgba(0,0,0,0.45)", zIndex: 205, display: "flex", alignItems: "center", justifyContent: "center" }}
onClick={() => !bulkBusy && onClose()}
>
<div
style={{ background: "var(--card)", borderRadius: "var(--radius-card)", padding: "20px", width: "min(440px, 92vw)", maxHeight: "80vh", overflow: "auto", boxShadow: "var(--shadow-xl)" }}
onClick={(e) => e.stopPropagation()}
>
{children}
</div>
</div>
);
const footer = (primary: React.ReactNode) => (
<div style={{ display: "flex", justifyContent: "flex-end", gap: "8px", marginTop: "14px" }}>
<button type="button" disabled={bulkBusy} onClick={onClose} style={{ padding: "7px 14px", borderRadius: "var(--radius-button)", border: "1px solid var(--border)", background: "var(--card)", cursor: "pointer", fontSize: "var(--text-sm)" }}>Cancel</button>
{primary}
</div>
);
if (bulkDialog === "addTags" || bulkDialog === "removeTags") {
return overlay(
<>
<h3 style={{ fontFamily: "var(--font-inter)", fontSize: "var(--text-base)", margin: "0 0 8px" }}>{bulkDialog === "addTags" ? "Add tags" : "Remove tags"}</h3>
<p style={{ fontSize: "var(--text-xs)", color: "var(--muted)", margin: "0 0 12px", fontFamily: "var(--font-noto-sans)" }}>Apply to {selectedCount} selected (comma-separated).</p>
<input value={tagBulkInput} onChange={(e) => onTagBulkInputChange(e.target.value)} placeholder="e.g. VIP, Sponsor" style={{ width: "100%", padding: "8px 12px", borderRadius: "var(--radius-button)", border: "1px solid var(--border)", fontSize: "var(--text-sm)", boxSizing: "border-box" }} />
{footer(
<button type="button" disabled={bulkBusy} onClick={() => onApplyTags(bulkDialog === "addTags" ? "add_tags" : "remove_tags")} style={{ padding: "7px 14px", borderRadius: "var(--radius-button)", border: "none", background: "var(--primary)", color: "var(--primary-foreground)", cursor: "pointer", fontSize: "var(--text-sm)" }}>Apply</button>
)}
</>
);
}
if (bulkDialog === "assignEvents") {
return overlay(
<>
<h3 style={{ fontFamily: "var(--font-inter)", fontSize: "var(--text-base)", margin: "0 0 8px" }}>Assign to event(s)</h3>
<p style={{ fontSize: "var(--text-xs)", color: "var(--muted)", margin: "0 0 12px", fontFamily: "var(--font-noto-sans)" }}>{selectedCount} people · adds pending membership where missing.</p>
<div style={{ maxHeight: "240px", overflowY: "auto", border: "1px solid var(--border)", borderRadius: "var(--radius-button)", padding: "8px" }}>
{eventsPick.map((ev) => (
<label key={ev._id} style={{ display: "flex", alignItems: "center", gap: "8px", padding: "6px 4px", cursor: "pointer", fontSize: "var(--text-sm)", fontFamily: "var(--font-noto-sans)" }}>
<input type="checkbox" checked={eventPickIds.has(ev._id)} onChange={() => onToggleEventPick(ev._id)} />
{ev.name}
</label>
))}
</div>
{footer(
<button type="button" disabled={bulkBusy || eventPickIds.size === 0} onClick={onAssignEvents} style={{ padding: "7px 14px", borderRadius: "var(--radius-button)", border: "none", background: "var(--primary)", color: "var(--primary-foreground)", cursor: "pointer", fontSize: "var(--text-sm)" }}>Assign</button>
)}
</>
);
}
if (bulkDialog === "newList") {
return overlay(
<>
<h3 style={{ fontFamily: "var(--font-inter)", fontSize: "var(--text-base)", margin: "0 0 8px" }}>New custom list</h3>
<p style={{ fontSize: "var(--text-xs)", color: "var(--muted)", margin: "0 0 12px", fontFamily: "var(--font-noto-sans)" }}>Fixed list with {selectedCount} selected people.</p>
<input value={newListName} onChange={(e) => onNewListNameChange(e.target.value)} placeholder="List name" style={{ width: "100%", padding: "8px 12px", borderRadius: "var(--radius-button)", border: "1px solid var(--border)", marginBottom: "8px", boxSizing: "border-box", fontSize: "var(--text-sm)" }} />
<textarea value={newListDesc} onChange={(e) => onNewListDescChange(e.target.value)} placeholder="Description (optional)" rows={3} style={{ width: "100%", padding: "8px 12px", borderRadius: "var(--radius-button)", border: "1px solid var(--border)", boxSizing: "border-box", fontSize: "var(--text-sm)", resize: "vertical" }} />
{footer(
<button type="button" disabled={bulkBusy || !newListName.trim()} onClick={onCreateList} style={{ padding: "7px 14px", borderRadius: "var(--radius-button)", border: "none", background: "var(--primary)", color: "var(--primary-foreground)", cursor: "pointer", fontSize: "var(--text-sm)" }}>Create</button>
)}
</>
);
}
if (bulkDialog === "addToList") {
return overlay(
<>
<h3 style={{ fontFamily: "var(--font-inter)", fontSize: "var(--text-base)", margin: "0 0 8px" }}>Add to existing list</h3>
<p style={{ fontSize: "var(--text-xs)", color: "var(--muted)", margin: "0 0 12px", fontFamily: "var(--font-noto-sans)" }}>Append {selectedCount} people to a fixed list.</p>
{fixedLists.length === 0 ? (
<p style={{ fontSize: "var(--text-sm)", color: "var(--muted)" }}>No fixed lists yet. Create one first.</p>
) : (
<select value={addToListId} onChange={(e) => onAddToListIdChange(e.target.value)} style={{ width: "100%", padding: "8px 12px", borderRadius: "var(--radius-button)", border: "1px solid var(--border)", fontSize: "var(--text-sm)" }}>
{fixedLists.map((L) => (
<option key={L._id} value={L._id}>{L.name}</option>
))}
</select>
)}
{footer(
<button type="button" disabled={bulkBusy || fixedLists.length === 0 || !addToListId} onClick={onAddToList} style={{ padding: "7px 14px", borderRadius: "var(--radius-button)", border: "none", background: "var(--primary)", color: "var(--primary-foreground)", cursor: "pointer", fontSize: "var(--text-sm)" }}>Add</button>
)}
</>
);
}
return null;
}