| 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 || '' , |
| 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.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()); |
| } |
| } |
|
|