Collapse Departments and Assignees pickers in the event form

Both lists grow with staff/department count and were always fully
expanded — matches the History section's existing collapsible pattern,
showing a summary of the current selection when closed.
This commit is contained in:
jtricerolph 2026-07-26 09:17:22 +00:00
parent d6542f4503
commit 056680999c

View file

@ -64,6 +64,8 @@ export default function EventForm({ eventId, initialDate, occurrenceStart, scope
const [historyOpen, setHistoryOpen] = useState(false) const [historyOpen, setHistoryOpen] = useState(false)
const [history, setHistory] = useState<ActivityLogEntry[] | null>(null) const [history, setHistory] = useState<ActivityLogEntry[] | null>(null)
const [deptsOpen, setDeptsOpen] = useState(false)
const [assigneesOpen, setAssigneesOpen] = useState(false)
useEffect(() => { useEffect(() => {
fetchCalendars().then(setCalendars).catch(() => {}) fetchCalendars().then(setCalendars).catch(() => {})
@ -303,51 +305,77 @@ export default function EventForm({ eventId, initialDate, occurrenceStart, scope
)} )}
<div className="field"> <div className="field">
<label>Departments</label>
{editingOccurrence ? ( {editingOccurrence ? (
<div className="chip-bar" style={{ margin: 0 }}> <>
{selectedDepts.length === 0 && <span className="field-hint">None</span>} <label>Departments</label>
{selectedDepts.map(d => <span key={d.id} className="badge badge-outline">{d.name}</span>)} <div className="chip-bar" style={{ margin: 0 }}>
</div> {selectedDepts.length === 0 && <span className="field-hint">None</span>}
{selectedDepts.map(d => <span key={d.id} className="badge badge-outline">{d.name}</span>)}
</div>
</>
) : ( ) : (
<div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}> <div className="filter-section" style={{ marginBottom: 0 }}>
{departments.map(dept => ( <div className="filter-section-header" onClick={() => setDeptsOpen(v => !v)}>
<label key={dept.id} className="field-check"> <span className="filter-section-label">Departments</span>
<input <span className={`filter-section-summary${selectedDepts.length === 0 ? ' muted' : ''}`}>
type="checkbox" {selectedDepts.length === 0 ? 'None selected' : selectedDepts.map(d => d.name).join(', ')}
checked={selectedDepts.some(d => d.id === dept.id)} </span>
onChange={() => toggleDept(dept)} <ChevronDown size={14} strokeWidth={1.75} className={`filter-section-chevron${deptsOpen ? ' open' : ''}`} />
disabled={!permitted} </div>
/> {deptsOpen && (
{dept.name} <div style={{ display: 'flex', flexDirection: 'column', gap: 4, marginTop: 8 }}>
</label> {departments.map(dept => (
))} <label key={dept.id} className="field-check">
{departments.length === 0 && <span className="field-hint">No departments configured.</span>} <input
type="checkbox"
checked={selectedDepts.some(d => d.id === dept.id)}
onChange={() => toggleDept(dept)}
disabled={!permitted}
/>
{dept.name}
</label>
))}
{departments.length === 0 && <span className="field-hint">No departments configured.</span>}
</div>
)}
</div> </div>
)} )}
</div> </div>
<div className="field"> <div className="field">
<label>Assignees</label>
{editingOccurrence ? ( {editingOccurrence ? (
<div className="chip-bar" style={{ margin: 0 }}> <>
{selectedAssignees.length === 0 && <span className="field-hint">None</span>} <label>Assignees</label>
{selectedAssignees.map(a => <span key={a.email} className="badge badge-outline">{a.name}</span>)} <div className="chip-bar" style={{ margin: 0 }}>
</div> {selectedAssignees.length === 0 && <span className="field-hint">None</span>}
{selectedAssignees.map(a => <span key={a.email} className="badge badge-outline">{a.name}</span>)}
</div>
</>
) : ( ) : (
<div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}> <div className="filter-section" style={{ marginBottom: 0 }}>
{users.map(u => ( <div className="filter-section-header" onClick={() => setAssigneesOpen(v => !v)}>
<label key={u.email} className="field-check"> <span className="filter-section-label">Assignees</span>
<input <span className={`filter-section-summary${selectedAssignees.length === 0 ? ' muted' : ''}`}>
type="checkbox" {selectedAssignees.length === 0 ? 'None selected' : selectedAssignees.map(a => a.name).join(', ')}
checked={selectedAssignees.some(a => a.email === u.email)} </span>
onChange={() => toggleAssignee(u)} <ChevronDown size={14} strokeWidth={1.75} className={`filter-section-chevron${assigneesOpen ? ' open' : ''}`} />
disabled={!permitted} </div>
/> {assigneesOpen && (
{u.name} <div style={{ display: 'flex', flexDirection: 'column', gap: 4, marginTop: 8 }}>
</label> {users.map(u => (
))} <label key={u.email} className="field-check">
{users.length === 0 && <span className="field-hint">No staff available.</span>} <input
type="checkbox"
checked={selectedAssignees.some(a => a.email === u.email)}
onChange={() => toggleAssignee(u)}
disabled={!permitted}
/>
{u.name}
</label>
))}
{users.length === 0 && <span className="field-hint">No staff available.</span>}
</div>
)}
</div> </div>
)} )}
</div> </div>