Some more UI changes. Also added device issue indicator
This commit is contained in:
@@ -367,6 +367,8 @@ export default function DeviceDetail() {
|
||||
const [savingNotes, setSavingNotes] = useState(false);
|
||||
const notesRef = useRef(null);
|
||||
const [usersLoading, setUsersLoading] = useState(false);
|
||||
const [unresolvedIssues, setUnresolvedIssues] = useState(0);
|
||||
const notesPanelRef = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
loadData();
|
||||
@@ -396,6 +398,14 @@ export default function DeviceDetail() {
|
||||
setDeviceUsers([]);
|
||||
}).finally(() => setUsersLoading(false));
|
||||
|
||||
// Load unresolved issues count
|
||||
api.get(`/equipment/notes?device_id=${id}`).then((data) => {
|
||||
const issues = (data.notes || []).filter(
|
||||
(n) => (n.category === "issue" || n.category === "action_item") && n.status !== "completed"
|
||||
);
|
||||
setUnresolvedIssues(issues.length);
|
||||
}).catch(() => setUnresolvedIssues(0));
|
||||
|
||||
// Reverse geocode
|
||||
const coords = parseCoordinates(d.device_location_coordinates);
|
||||
if (coords) {
|
||||
@@ -944,7 +954,7 @@ export default function DeviceDetail() {
|
||||
</SectionCard>
|
||||
);
|
||||
|
||||
const notesSection = <NotesPanel deviceId={id} />;
|
||||
const notesSection = <div ref={notesPanelRef}><NotesPanel deviceId={id} /></div>;
|
||||
const logsSection = <DeviceLogsPanel deviceSerial={device.device_id} />;
|
||||
|
||||
// ===== Layout rendering =====
|
||||
@@ -1021,10 +1031,11 @@ export default function DeviceDetail() {
|
||||
<button onClick={() => navigate("/devices")} className="text-sm hover:underline mb-2 inline-block" style={{ color: "var(--accent)" }}>
|
||||
← Back to Devices
|
||||
</button>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="flex items-center gap-4">
|
||||
<h1 className="text-2xl font-bold" style={{ color: "var(--text-heading)" }}>
|
||||
{device.device_name || "Unnamed Device"}
|
||||
</h1>
|
||||
<div style={{ width: 1, height: 24, backgroundColor: "var(--border-primary)" }} />
|
||||
<div style={{ display: "flex", alignItems: "center", gap: "0.5rem" }}>
|
||||
<span
|
||||
className="w-3 h-3 rounded-full inline-block"
|
||||
@@ -1039,6 +1050,19 @@ export default function DeviceDetail() {
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
{unresolvedIssues > 0 && (
|
||||
<>
|
||||
<div style={{ width: 1, height: 24, backgroundColor: "var(--border-primary)" }} />
|
||||
<button
|
||||
onClick={() => notesPanelRef.current?.scrollIntoView({ behavior: "smooth", block: "start" })}
|
||||
className="flex items-center gap-1.5 px-2.5 py-1 text-xs font-medium rounded-md cursor-pointer hover:opacity-80 transition-opacity"
|
||||
style={{ backgroundColor: "var(--danger-bg)", color: "var(--danger-text)", border: "none" }}
|
||||
>
|
||||
<span style={{ fontSize: "0.85rem", lineHeight: 1 }}>⚠</span>
|
||||
{unresolvedIssues} Issue{unresolvedIssues !== 1 ? "s" : ""} Unresolved
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{canEdit && (
|
||||
|
||||
@@ -201,7 +201,7 @@ export default function NotesPanel({ deviceId, userId }) {
|
||||
{note.title}
|
||||
</span>
|
||||
</div>
|
||||
<p className="text-xs truncate" style={{ color: "var(--text-muted)" }}>{note.content}</p>
|
||||
<p className="text-xs" style={{ color: "var(--text-muted)", display: "-webkit-box", WebkitLineClamp: 3, WebkitBoxOrient: "vertical", overflow: "hidden" }}>{note.content}</p>
|
||||
<p className="text-xs mt-1" style={{ color: "var(--text-muted)" }}>
|
||||
{note.created_by && `${note.created_by} · `}{note.created_at}
|
||||
</p>
|
||||
@@ -256,7 +256,7 @@ export default function NotesPanel({ deviceId, userId }) {
|
||||
{msg.subject || "No subject"}
|
||||
</span>
|
||||
</div>
|
||||
<p className="text-xs truncate" style={{ color: "var(--text-muted)" }}>{msg.message}</p>
|
||||
<p className="text-xs" style={{ color: "var(--text-muted)", display: "-webkit-box", WebkitLineClamp: 3, WebkitBoxOrient: "vertical", overflow: "hidden" }}>{msg.message}</p>
|
||||
<p className="text-xs mt-1" style={{ color: "var(--text-muted)" }}>
|
||||
{msg.sender_name && `${msg.sender_name} · `}{msg.phone && `${msg.phone} · `}{msg.date_sent}
|
||||
</p>
|
||||
@@ -269,7 +269,7 @@ export default function NotesPanel({ deviceId, userId }) {
|
||||
return (
|
||||
<section
|
||||
className="rounded-lg border p-6"
|
||||
style={{ backgroundColor: "var(--bg-card)", borderColor: "var(--border-primary)" }}
|
||||
style={{ backgroundColor: "var(--bg-card)", borderColor: "var(--border-primary)", minWidth: 0, overflow: "hidden" }}
|
||||
>
|
||||
<div className="flex items-center justify-between mb-3">
|
||||
<h2 className="text-lg font-semibold" style={{ color: "var(--text-heading)" }}>
|
||||
|
||||
@@ -12,7 +12,7 @@ export default function Header() {
|
||||
}}
|
||||
>
|
||||
<h2 className="text-lg font-semibold" style={{ color: "var(--text-heading)" }}>
|
||||
Admin Panel
|
||||
BellSystems - Control Panel
|
||||
</h2>
|
||||
|
||||
<div className="flex items-center gap-4">
|
||||
|
||||
@@ -225,8 +225,8 @@ export default function MelodyDetail() {
|
||||
<Field label="Tone">
|
||||
<span className="capitalize">{info.melodyTone}</span>
|
||||
</Field>
|
||||
<Field label="Total Active Notes (bells)">{info.totalNotes}</Field>
|
||||
<Field label="Steps">{info.steps}</Field>
|
||||
<Field label="Total Active Notes (bells)">{info.totalNotes}</Field>
|
||||
<Field label="Min Speed">{info.minSpeed}</Field>
|
||||
<Field label="Max Speed">{info.maxSpeed}</Field>
|
||||
<Field label="Color">
|
||||
|
||||
@@ -309,14 +309,14 @@ export default function UserDetail() {
|
||||
</div>
|
||||
{/* Fields */}
|
||||
<dl className="grid grid-cols-2 md:grid-cols-3 gap-4 flex-1">
|
||||
<Field label="Document ID">
|
||||
<Field label="Title">{user.userTitle}</Field>
|
||||
<Field label="Phone">{user.phone_number}</Field>
|
||||
<Field label="UID">
|
||||
<span className="font-mono text-xs" style={{ color: "var(--text-muted)" }}>
|
||||
{user.id}
|
||||
{user.uid || user.id}
|
||||
</span>
|
||||
</Field>
|
||||
<Field label="UID">
|
||||
<span className="font-mono text-xs">{user.uid}</span>
|
||||
</Field>
|
||||
<Field label="Email">{user.email}</Field>
|
||||
<Field label="Status">
|
||||
<span
|
||||
className="px-2 py-0.5 text-xs rounded-full"
|
||||
@@ -331,9 +331,6 @@ export default function UserDetail() {
|
||||
{user.status || "unknown"}
|
||||
</span>
|
||||
</Field>
|
||||
<Field label="Email">{user.email}</Field>
|
||||
<Field label="Phone">{user.phone_number}</Field>
|
||||
<Field label="Title">{user.userTitle}</Field>
|
||||
</dl>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
Reference in New Issue
Block a user