Py-detect / src /app /shared /case-store.service.ts
RajalashmiNagarajan
adminpage update
86b4aeb
import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable } from 'rxjs';
export interface PoliceCase {
// Optional metadata used by your UI
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;
// Store raw form data from infopage so all entered fields can be displayed
// Use array of key/value pairs for safe rendering
formData?: Array<{ key: string; value: any }> | Record<string, any>;
selected?: boolean; // <-- Add this line for table selection
}
@Injectable({ providedIn: 'root' })
export class CaseStoreService {
private readonly storageKey = 'py_detect_police_cases';
private cases: PoliceCase[] = [];
// Observable subject to broadcast changes
private casesSubject = new BehaviorSubject<PoliceCase[]>([]);
/** Observable for components to subscribe to case list updates */
getCases$(): Observable<PoliceCase[]> {
return this.casesSubject.asObservable();
}
constructor() {
this.load();
}
/** Create (newest first) */
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());
}
/** Read */
getPoliceCases(): PoliceCase[] {
return this.cases;
}
/** Update by array index */
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());
}
}
/** Delete by array index */
deletePoliceCaseAt(index: number): void {
if (index >=0 && index < this.cases.length) {
this.cases.splice(index,1);
this.save();
this.casesSubject.next(this.cases.slice());
}
}
/** Update by caseId */
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());
}
}
/**
* Convenience: map Info page reactive-form value to PoliceCase and store it.
* Call with the whole this.form.value from InfopageComponent.
*/
addFromInfoForm(formValue: any): void {
const crime = (formValue && formValue.crime) || {};
const suspect = (formValue && formValue.suspect) || {};
const notes = (formValue && formValue.notes) || {};
// Merge raw inputs so we capture everything entered on the Info page
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: '—', // not captured on Info page
address: crime.location || '—',
pincode: '', // not captured on Info page
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 || ''
},
// store raw form data so UI can display all entered fields
formData: this.convertToKeyValue(mergedRaw || {})
};
this.addPoliceCase(mapped);
}
/** Add or update from Info page form */
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 || '' ,
// mark when infopage submission occurred
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 || '',
// Save full raw form data. Merge wrapper fields so everything entered is preserved.
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) {
// Merge existing object to preserve other metadata where possible
this.cases[idx] = { ...this.cases[idx], ...mapped };
// Ensure lastUpdated reflects this infopage update
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);
}
}
/**
* Convert an object (or already key/value array) into an array of {key, value}
*/
private convertToKeyValue(data: any): Array<{ key: string; value: any }> {
if (!data) return [];
if (Array.isArray(data)) {
// assume already in the desired shape
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)) {
// store arrays as JSON string for readability
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)) {
// arrays -> stringify
result.push({ key: newKey, value: JSON.stringify(v) });
} else {
result.push({ key: newKey, value: v });
}
}
};
if (typeof data === 'object') {
recurse(data, '');
return result;
}
// primitive
return [{ key: 'value', value: data }];
}
// Simple debug helper to log saved cases (can be removed later)
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 { }
}
/** Persist to localStorage (safe to keep; remove if not needed) */
private save(): void {
try { localStorage.setItem(this.storageKey, JSON.stringify(this.cases)); } catch { }
}
/** Load from localStorage */
private load(): void {
try {
const raw = localStorage.getItem(this.storageKey);
this.cases = raw ? (JSON.parse(raw) as PoliceCase[]) : [];
} catch {
this.cases = [];
}
// Seed a default case if none exist (for development/testing)
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();
}
// Emit current cases to subscribers
this.casesSubject.next(this.cases.slice());
}
}