dispatch-console / web /src /components /MembersPanel.jsx
secutorpro's picture
members panel
741bf09 verified
Raw History Blame Contribute Delete
3.24 kB
import { useState } from 'react';
const EMPTY = { name: '', callsign: '', device_id: '', group_id: '' };
export default function MembersPanel({ members, groups, sosIds = new Set(), selected, onSelect, onSave, onDelete }) {
const [editing, setEditing] = useState(null); // null | {} (new) | member
const [form, setForm] = useState(EMPTY);
const [error, setError] = useState('');
const start = (m) => {
setEditing(m || {});
setForm({
name: m?.name || '',
callsign: m?.callsign || '',
device_id: m?.device_id || '',
group_id: m?.group_id ?? '',
});
};
const submit = async (e) => {
e.preventDefault();
setError('');
try {
await onSave(editing?.id ?? null, {
...form,
group_id: form.group_id === '' ? null : Number(form.group_id),
});
setEditing(null);
setForm(EMPTY);
} catch (err) {
setError(err.message);
}
};
const remove = async (m) => {
if (!confirm(`Remove ${m.name}?`)) return;
setError('');
try {
await onDelete(m.id);
} catch (err) {
setError(err.message);
}
};
return (
<section className="panel">
<h2>
Members ({members.length})
<button className="icon-btn" style={{ float: 'right' }} onClick={() => (editing ? (setEditing(null), setForm(EMPTY)) : start(null))}>
{editing ? '×' : '+'}
</button>
</h2>
{error && <p className="error">{error}</p>}
{editing && (
<form className="member-form" onSubmit={submit}>
<input placeholder="Name" required value={form.name} onChange={(e) => setForm({ ...form, name: e.target.value })} />
<div className="form-row">
<input placeholder="Callsign" value={form.callsign} onChange={(e) => setForm({ ...form, callsign: e.target.value })} />
<input placeholder="Device ID (unique)" value={form.device_id} onChange={(e) => setForm({ ...form, device_id: e.target.value })} disabled={!!editing.id} />
</div>
<select value={form.group_id ?? ''} onChange={(e) => setForm({ ...form, group_id: e.target.value })}>
<option value="">No group</option>
{groups.map((g) => <option key={g.id} value={g.id}>{g.name}</option>)}
</select>
<div className="form-row">
<button className="primary">{editing.id ? 'Save' : 'Add member'}</button>
{editing.id && <button type="button" className="danger" onClick={() => remove(editing)}>Delete</button>}
</div>
</form>
)}
{members.map((m) => (
<div key={m.id} className={`mrow ${selected === m.id ? 'selected' : ''}`} onClick={() => onSelect(m.id)}>
<span className={`st ${m.status === 'online' ? 'online' : ''} ${sosIds.has(m.id) ? 'sos' : ''}`} />
<span className="nm">
{m.name}
<span className="sub"> · {m.group_name || '—'}{m.callsign ? ` · ${m.callsign}` : ''}</span>
</span>
<span className="bat">{m.battery != null ? `${m.battery}%` : ''}</span>
<button className="icon-btn" onClick={(e) => { e.stopPropagation(); start(m); }}>✎</button>
</div>
))}
</section>
);
}