big ui and intel updates
This commit is contained in:
@@ -72,6 +72,8 @@ export const c2api = {
|
||||
request(`/incidents/${id}`, { method: "DELETE" }),
|
||||
linkCallToIncident: (incidentId: string, callId: string) =>
|
||||
request(`/incidents/${incidentId}/calls/${callId}`, { method: "POST" }),
|
||||
summarizeIncident: (id: string) =>
|
||||
request(`/incidents/${id}/summarize`, { method: "POST" }),
|
||||
|
||||
// Alerts
|
||||
getAlerts: (acknowledged?: boolean) => {
|
||||
|
||||
@@ -40,7 +40,7 @@ export interface CallRecord {
|
||||
transcript_corrected: string | null;
|
||||
segments: TranscriptSegment[] | null;
|
||||
incident_id: string | null;
|
||||
location: { lat: number; lng: number } | null;
|
||||
location: string | null;
|
||||
tags: string[];
|
||||
status: "active" | "ended";
|
||||
}
|
||||
@@ -50,8 +50,11 @@ export interface IncidentRecord {
|
||||
title: string | null;
|
||||
type: string | null;
|
||||
status: "active" | "resolved";
|
||||
location: { lat: number; lng: number } | null;
|
||||
location: string | null;
|
||||
location_coords: { lat: number; lng: number } | null;
|
||||
call_ids: string[];
|
||||
system_ids: string[];
|
||||
talkgroup_ids: string[];
|
||||
started_at: string;
|
||||
updated_at: string;
|
||||
summary: string | null;
|
||||
|
||||
@@ -48,6 +48,39 @@ export function useCalls(limitCount = 50) {
|
||||
return { calls, loading, error };
|
||||
}
|
||||
|
||||
export function useCallsByIncident(incidentId: string | null) {
|
||||
const [calls, setCalls] = useState<CallRecord[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
if (!incidentId) { setLoading(false); return; }
|
||||
let unsubFirestore: (() => void) | undefined;
|
||||
|
||||
const unsubAuth = onAuthStateChanged(auth, (user) => {
|
||||
if (unsubFirestore) { unsubFirestore(); unsubFirestore = undefined; }
|
||||
if (!user) { setLoading(false); return; }
|
||||
|
||||
const toISO = (v: any): string | null =>
|
||||
v?.toDate?.()?.toISOString?.() ?? (typeof v === "string" ? v : null);
|
||||
|
||||
const q = query(collection(db, "calls"), where("incident_id", "==", incidentId));
|
||||
unsubFirestore = onSnapshot(q, (snap) => {
|
||||
const docs = snap.docs.map((d) => {
|
||||
const data = d.data();
|
||||
return { ...data, started_at: toISO(data.started_at) ?? "", ended_at: toISO(data.ended_at) } as CallRecord;
|
||||
});
|
||||
docs.sort((a, b) => a.started_at.localeCompare(b.started_at));
|
||||
setCalls(docs);
|
||||
setLoading(false);
|
||||
}, (err: FirestoreError) => { console.error("useCallsByIncident:", err); setLoading(false); });
|
||||
});
|
||||
|
||||
return () => { unsubAuth(); if (unsubFirestore) unsubFirestore(); };
|
||||
}, [incidentId]);
|
||||
|
||||
return { calls, loading };
|
||||
}
|
||||
|
||||
export function useActiveCalls() {
|
||||
const [calls, setCalls] = useState<CallRecord[]>([]);
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { collection, onSnapshot, query, orderBy, limit, where, FirestoreError } from "firebase/firestore";
|
||||
import { collection, doc, onSnapshot, query, orderBy, limit, where, FirestoreError } from "firebase/firestore";
|
||||
import { onAuthStateChanged } from "firebase/auth";
|
||||
import { db, auth } from "@/lib/firebase";
|
||||
import type { IncidentRecord } from "@/lib/types";
|
||||
@@ -58,6 +58,43 @@ export function useIncidents(limitCount = 100) {
|
||||
return { incidents, loading, error };
|
||||
}
|
||||
|
||||
export function useIncident(incidentId: string | null) {
|
||||
const [incident, setIncident] = useState<IncidentRecord | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
if (!incidentId) { setLoading(false); return; }
|
||||
let unsubFirestore: (() => void) | undefined;
|
||||
|
||||
const unsubAuth = onAuthStateChanged(auth, (user) => {
|
||||
if (unsubFirestore) { unsubFirestore(); unsubFirestore = undefined; }
|
||||
if (!user) { setLoading(false); return; }
|
||||
|
||||
const ref = doc(db, "incidents", incidentId);
|
||||
unsubFirestore = onSnapshot(ref, (snap) => {
|
||||
if (snap.exists()) {
|
||||
const data = snap.data();
|
||||
setIncident({
|
||||
...data,
|
||||
started_at: toISO(data.started_at),
|
||||
updated_at: toISO(data.updated_at),
|
||||
} as IncidentRecord);
|
||||
} else {
|
||||
setIncident(null);
|
||||
}
|
||||
setLoading(false);
|
||||
}, (err: FirestoreError) => {
|
||||
console.error("useIncident:", err);
|
||||
setLoading(false);
|
||||
});
|
||||
});
|
||||
|
||||
return () => { unsubAuth(); if (unsubFirestore) unsubFirestore(); };
|
||||
}, [incidentId]);
|
||||
|
||||
return { incident, loading };
|
||||
}
|
||||
|
||||
export function useActiveIncidents() {
|
||||
const [incidents, setIncidents] = useState<IncidentRecord[]>([]);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user