|
|
import { Injectable } from '@angular/core'; |
|
|
import { BehaviorSubject, Observable } from 'rxjs'; |
|
|
|
|
|
export interface PoliceCase { |
|
|
|
|
|
caseId?: string; |
|
|
dateTime?: string; |
|
|
status?: 'Open' | 'Under Investigation' | 'Closed' | 'Archived'; |
|
|
crime?: string; |
|
|
police?: { |
|
|
name?: string; |
|
|
station?: string; |
|
|
address?: string; |
|
|
pincode?: string; |
|
|
dutyPerson?: string; |
|
|
modeOfCrime?: string; |
|
|
information?: string; |
|
|
}; |
|
|
accused?: { |
|
|
name?: string; |
|
|
age?: string | number; |
|
|
gender?: string; |
|
|
address?: string; |
|
|
occupation?: string; |
|
|
}; |
|
|
lastUpdated?: string; |
|
|
nextAction?: string; |
|
|
casePriority?: 'High' | 'Medium' | 'Low'; |
|
|
reportedBy?: string; |
|
|
verifiedBy?: string; |
|
|
briefDescription?: string; |
|
|
caseCategory?: string; |
|
|
|
|
|
|
|
|
formData?: Array<{ key: string; value: any }> | Record<string, any>; |
|
|
selected?: boolean; |
|
|
} |
|
|
|
|
|
@Injectable({ providedIn: 'root' }) |
|
|
export class CaseStoreService { |
|
|
private readonly storageKey = 'py_detect_police_cases'; |
|
|
private cases: PoliceCase[] = []; |
|
|
|
|
|
private casesSubject = new BehaviorSubject<PoliceCase[]>([]); |
|
|
|
|
|
|
|
|
getCases$(): Observable<PoliceCase[]> { |
|
|
return this.casesSubject.asObservable(); |
|
|
} |
|
|
|
|
|
constructor() { |
|
|
this.load(); |
|
|
} |
|
|
|
|
|
|
|
|
private getNextCaseId(): string { |
|
|
const max = this.cases |
|
|
.map(c => c.caseId) |
|
|
.map(id => parseInt((id || '').replace('CASE-', ''),10)) |
|
|
.filter(n => !isNaN(n)) |
|
|
.reduce((a, b) => Math.max(a, b),0); |
|
|
return `CASE-${(max +1).toString().padStart(3, '0')}`; |
|
|
} |
|
|
|
|
|
addPoliceCase(c: PoliceCase): void { |
|
|
if (!c.caseId) { |
|
|
c.caseId = this.getNextCaseId(); |
|
|
} |
|
|
c.lastUpdated = new Date().toISOString(); |
|
|
c.verifiedBy = c.verifiedBy || ''; |
|
|
this.cases.unshift(c); |
|
|
this.save(); |
|
|
this.debugLogCasesOperation('addPoliceCase', c); |
|
|
this.casesSubject.next(this.cases.slice()); |
|
|
} |
|
|
|
|
|
|
|
|
getPoliceCases(): PoliceCase[] { |
|
|
return this.cases; |
|
|
} |
|
|
|
|
|
|
|
|
updatePoliceCaseAt(index: number, updated: PoliceCase): void { |
|
|
if (index >=0 && index < this.cases.length) { |
|
|
updated.lastUpdated = new Date().toISOString(); |
|
|
this.cases[index] = updated; |
|
|
this.save(); |
|
|
this.casesSubject.next(this.cases.slice()); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
deletePoliceCaseAt(index: number): void { |
|
|
if (index >=0 && index < this.cases.length) { |
|
|
this.cases.splice(index,1); |
|
|
this.save(); |
|
|
this.casesSubject.next(this.cases.slice()); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
updatePoliceCaseById(caseId: string, updated: PoliceCase): void { |
|
|
const idx = this.cases.findIndex(c => c.caseId === caseId); |
|
|
if (idx !== -1) { |
|
|
updated.lastUpdated = new Date().toISOString(); |
|
|
this.cases[idx] = updated; |
|
|
this.save(); |
|
|
this.casesSubject.next(this.cases.slice()); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
addFromInfoForm(formValue: any): void { |
|
|
const crime = (formValue && formValue.crime) || {}; |
|
|
const suspect = (formValue && formValue.suspect) || {}; |
|
|
const notes = (formValue && formValue.notes) || {}; |
|
|
|
|
|
|
|
|
const mergedRaw = { |
|
|
...(formValue && formValue.formData ? formValue.formData : (formValue || {})), |
|
|
...crime, |
|
|
...suspect, |
|
|
...notes |
|
|
}; |
|
|
|
|
|
const mapped: PoliceCase = { |
|
|
caseId: crime.caseId || '', |
|
|
dateTime: crime.dateTime || '', |
|
|
status: notes.status || 'Open', |
|
|
crime: crime.crimeType || 'Unknown', |
|
|
police: { |
|
|
name: notes.officerInCharge || '—', |
|
|
station: '—', |
|
|
address: crime.location || '—', |
|
|
pincode: '', |
|
|
dutyPerson: notes.officerInCharge || '—', |
|
|
modeOfCrime: crime.crimeType || '—', |
|
|
information: notes.initialFindings || '' |
|
|
}, |
|
|
accused: { |
|
|
name: suspect.fullName || '—', |
|
|
age: suspect.age || '—', |
|
|
gender: suspect.gender || '—', |
|
|
address: suspect.address || '—', |
|
|
occupation: suspect.alias || '' |
|
|
}, |
|
|
|
|
|
formData: this.convertToKeyValue(mergedRaw || {}) |
|
|
}; |
|
|
|
|
|
this.addPoliceCase(mapped); |
|
|
} |
|
|
|
|
|
|
|
|
addOrUpdateFromInfoForm(formValue: any): void { |
|
|
const crime = (formValue && formValue.crime) || {}; |
|
|
const suspect = (formValue && formValue.suspect) || {}; |
|
|
const notes = (formValue && formValue.notes) || {}; |
|
|
const mapped: PoliceCase = { |
|
|
caseId: crime.caseId || (formValue && formValue['Case ID']) || '', |
|
|
dateTime: crime.dateTime || '' , |
|
|
|
|
|
lastUpdated: new Date().toISOString(), |
|
|
status: notes.status || 'Open', |
|
|
crime: crime.crimeType || 'Unknown', |
|
|
police: { |
|
|
name: notes.officerInCharge || '—', |
|
|
station: '—', |
|
|
address: crime.location || '—', |
|
|
pincode: '', |
|
|
dutyPerson: notes.officerInCharge || '—', |
|
|
modeOfCrime: crime.crimeType || '—', |
|
|
information: notes.initialFindings || '' |
|
|
}, |
|
|
accused: { |
|
|
name: suspect.fullName || '—', |
|
|
age: suspect.age || '—', |
|
|
gender: suspect.gender || '—', |
|
|
address: suspect.address || '—', |
|
|
occupation: suspect.alias || '' |
|
|
}, |
|
|
reportedBy: crime.reportedBy || '', |
|
|
verifiedBy: notes.verifiedBy || '', |
|
|
briefDescription: crime.briefDescription || '', |
|
|
|
|
|
formData: this.convertToKeyValue( |
|
|
{ |
|
|
...(formValue && formValue.formData ? formValue.formData : (formValue || {})), |
|
|
...crime, |
|
|
...suspect, |
|
|
...notes, |
|
|
...(formValue && formValue.legal ? formValue.legal : {}) |
|
|
} |
|
|
) |
|
|
}; |
|
|
|
|
|
const idx = this.cases.findIndex(c => c.caseId === mapped.caseId); |
|
|
if (idx !== -1) { |
|
|
|
|
|
this.cases[idx] = { ...this.cases[idx], ...mapped }; |
|
|
|
|
|
this.cases[idx].lastUpdated = mapped.lastUpdated || new Date().toISOString(); |
|
|
this.save(); |
|
|
this.debugLogCasesOperation('updatePoliceCase', mapped); |
|
|
this.casesSubject.next(this.cases.slice()); |
|
|
} else { |
|
|
this.addPoliceCase(mapped); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private convertToKeyValue(data: any): Array<{ key: string; value: any }> { |
|
|
if (!data) return []; |
|
|
if (Array.isArray(data)) { |
|
|
|
|
|
return data.map(item => { |
|
|
if (item && typeof item === 'object' && 'key' in item) return item; |
|
|
return { key: String(item), value: item }; |
|
|
}); |
|
|
} |
|
|
|
|
|
const result: Array<{ key: string; value: any }> = []; |
|
|
|
|
|
const isPlainObject = (v: any) => v && typeof v === 'object' && !(v instanceof Date) && !(v instanceof File) && !Array.isArray(v); |
|
|
|
|
|
const recurse = (obj: any, prefix = '') => { |
|
|
if (obj === null || obj === undefined) return; |
|
|
if (typeof obj !== 'object' || obj instanceof Date || obj instanceof File) { |
|
|
result.push({ key: prefix || 'value', value: obj }); |
|
|
return; |
|
|
} |
|
|
|
|
|
if (Array.isArray(obj)) { |
|
|
|
|
|
result.push({ key: prefix || 'value', value: JSON.stringify(obj) }); |
|
|
return; |
|
|
} |
|
|
|
|
|
for (const k of Object.keys(obj)) { |
|
|
const v = obj[k]; |
|
|
const newKey = prefix ? `${prefix}.${k}` : k; |
|
|
if (isPlainObject(v)) { |
|
|
recurse(v, newKey); |
|
|
} else if (Array.isArray(v)) { |
|
|
|
|
|
result.push({ key: newKey, value: JSON.stringify(v) }); |
|
|
} else { |
|
|
result.push({ key: newKey, value: v }); |
|
|
} |
|
|
} |
|
|
}; |
|
|
|
|
|
if (typeof data === 'object') { |
|
|
recurse(data, ''); |
|
|
return result; |
|
|
} |
|
|
|
|
|
|
|
|
return [{ key: 'value', value: data }]; |
|
|
} |
|
|
|
|
|
|
|
|
private debugLogCasesOperation(label: string, mapped?: PoliceCase) { |
|
|
try { |
|
|
console.log(`[CaseStore] ${label}`, mapped || null); |
|
|
console.log('[CaseStore] current cases:', JSON.parse(localStorage.getItem(this.storageKey) || '[]')); |
|
|
} catch { } |
|
|
} |
|
|
|
|
|
|
|
|
private save(): void { |
|
|
try { localStorage.setItem(this.storageKey, JSON.stringify(this.cases)); } catch { } |
|
|
} |
|
|
|
|
|
|
|
|
private load(): void { |
|
|
try { |
|
|
const raw = localStorage.getItem(this.storageKey); |
|
|
this.cases = raw ? (JSON.parse(raw) as PoliceCase[]) : []; |
|
|
} catch { |
|
|
this.cases = []; |
|
|
} |
|
|
|
|
|
if (this.cases.length ===0) { |
|
|
this.cases = [ |
|
|
{ |
|
|
caseId: 'CASE-001', |
|
|
dateTime: new Date().toISOString(), |
|
|
status: 'Open', |
|
|
crime: 'Theft', |
|
|
police: { |
|
|
name: 'Officer John Doe', |
|
|
station: 'Central Station', |
|
|
address: '123 Main St, City', |
|
|
pincode: '123456', |
|
|
dutyPerson: 'Officer John Doe', |
|
|
modeOfCrime: 'Burglary', |
|
|
information: 'Initial investigation started.' |
|
|
}, |
|
|
accused: { |
|
|
name: 'Jane Smith', |
|
|
age:30, |
|
|
gender: 'Female', |
|
|
address: '456 Side Rd, City', |
|
|
occupation: 'Unemployed' |
|
|
}, |
|
|
formData: [] |
|
|
} |
|
|
]; |
|
|
this.save(); |
|
|
} |
|
|
|
|
|
this.casesSubject.next(this.cases.slice()); |
|
|
} |
|
|
} |
|
|
|