refactor: remove incident management code and related tests
This commit is contained in:
1 parent
c69eccb5c1
commit
708da6b9f7
4 files changed
-146
No files matched your search
@@ -1,41 +0,0 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { ALL_TYPES, createIncident, filterIncidents, nextIncidentId } from './incidents'
|
||||
import { seedIncidents } from './seed'
|
||||
|
||||
describe('filterIncidents', () => {
|
||||
it('returns everything with an empty query and no type filter', () => {
|
||||
expect(filterIncidents(seedIncidents, '', ALL_TYPES)).toHaveLength(seedIncidents.length)
|
||||
})
|
||||
|
||||
it('matches title, id and location case-insensitively', () => {
|
||||
expect(filterIncidents(seedIncidents, 'FORKLIFT', ALL_TYPES).map((i) => i.id)).toEqual(['INC-2408'])
|
||||
expect(filterIncidents(seedIncidents, 'inc-2405', ALL_TYPES).map((i) => i.id)).toEqual(['INC-2405'])
|
||||
expect(filterIncidents(seedIncidents, 'line 3', ALL_TYPES).map((i) => i.id)).toEqual(['INC-2406'])
|
||||
})
|
||||
|
||||
it('filters by type', () => {
|
||||
expect(filterIncidents(seedIncidents, '', 'Hazard').map((i) => i.id)).toEqual(['INC-2407'])
|
||||
})
|
||||
})
|
||||
|
||||
describe('nextIncidentId', () => {
|
||||
it('increments the highest existing id', () => {
|
||||
expect(nextIncidentId(seedIncidents)).toBe('INC-2409')
|
||||
})
|
||||
|
||||
it('starts at INC-0001 when there are no incidents', () => {
|
||||
expect(nextIncidentId([])).toBe('INC-0001')
|
||||
})
|
||||
})
|
||||
|
||||
describe('createIncident', () => {
|
||||
it('assigns id, status, date and reporter', () => {
|
||||
const incident = createIncident(
|
||||
{ title: 'Spill', type: 'Hazard', severity: 'Low', building: 'Building A', location: 'Dock' },
|
||||
seedIncidents,
|
||||
'Alex Kim',
|
||||
new Date(2026, 9, 6, 9, 30),
|
||||
)
|
||||
expect(incident).toMatchObject({ id: 'INC-2409', status: 'New report', date: '2026-10-06', reporter: 'Alex Kim' })
|
||||
})
|
||||
})
|
||||
@@ -1,47 +0,0 @@
|
||||
import { toIsoDate } from './dates'
|
||||
import type { Tone } from './tones'
|
||||
import type { Incident, IncidentStatus, IncidentType, NewIncident, Severity } from './types'
|
||||
|
||||
export const ALL_TYPES = 'All incidents'
|
||||
export type TypeFilter = IncidentType | typeof ALL_TYPES
|
||||
|
||||
export function filterIncidents(incidents: Incident[], query: string, type: TypeFilter): Incident[] {
|
||||
const needle = query.trim().toLowerCase()
|
||||
return incidents.filter(
|
||||
(incident) =>
|
||||
`${incident.title} ${incident.id} ${incident.location}`.toLowerCase().includes(needle) &&
|
||||
(type === ALL_TYPES || incident.type === type),
|
||||
)
|
||||
}
|
||||
|
||||
/** Next sequential ID after the highest existing `INC-####`. Temporary until the backend assigns IDs. */
|
||||
export function nextIncidentId(incidents: Incident[]): string {
|
||||
const highest = incidents.reduce((max, { id }) => Math.max(max, Number(id.replace(/^INC-/, '')) || 0), 0)
|
||||
return `INC-${String(highest + 1).padStart(4, '0')}`
|
||||
}
|
||||
|
||||
export const isOpen = (incident: Incident) => incident.status !== 'Resolved'
|
||||
|
||||
export const typeTone: Record<IncidentType, Tone> = {
|
||||
'Near miss': 'amber',
|
||||
Hazard: 'sky',
|
||||
Injury: 'coral',
|
||||
'Property damage': 'mint',
|
||||
}
|
||||
|
||||
export const severityDotClass: Record<Severity, string> = {
|
||||
High: 'bg-coral-strong',
|
||||
Medium: 'bg-[#d8a631]',
|
||||
Low: 'bg-[#52a57e]',
|
||||
}
|
||||
|
||||
export function statusClass(status: IncidentStatus): string {
|
||||
if (status === 'Resolved') return 'bg-mint-soft text-[#398461]'
|
||||
if (status === 'Review required') return 'bg-coral-soft text-[#c75e4b]'
|
||||
return 'bg-[#fff0d2] text-[#9a7319]'
|
||||
}
|
||||
|
||||
/** Builds a full incident record from a submitted report. */
|
||||
export function createIncident(draft: NewIncident, existing: Incident[], reporter: string, now: Date): Incident {
|
||||
return { ...draft, id: nextIncidentId(existing), status: 'New report', date: toIsoDate(now), reporter }
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
import type { Incident, Person, Site } from './types'
|
||||
|
||||
// Demo data for the UI prototype. Replaced by the API in Phase 1.
|
||||
|
||||
export const currentUser: Person = { name: 'Jordan Lee', initials: 'JL', role: 'Safety manager' }
|
||||
|
||||
export const workspace = { name: 'Northstar Co.', initials: 'NC' }
|
||||
|
||||
export const seedIncidents: Incident[] = [
|
||||
{ id: 'INC-2408', title: 'Forklift reversed into pallet stack', type: 'Near miss', severity: 'High', status: 'Investigation', building: 'Warehouse 04', location: 'Loading bay C', date: '2024-08-28', reporter: 'Jordan Lee' },
|
||||
{ id: 'INC-2407', title: 'Wet floor near employee entrance', type: 'Hazard', severity: 'Medium', status: 'Action open', building: 'Building A', location: 'Ground floor lobby', date: '2024-08-27', reporter: 'Maya Chen' },
|
||||
{ id: 'INC-2406', title: 'Hand laceration during material handling', type: 'Injury', severity: 'High', status: 'Review required', building: 'Fabrication 02', location: 'Line 3', date: '2024-08-26', reporter: 'Sam Rivera' },
|
||||
{ id: 'INC-2405', title: 'Damaged guardrail on mezzanine', type: 'Property damage', severity: 'Low', status: 'Resolved', building: 'Warehouse 01', location: 'Mezzanine east', date: '2024-08-24', reporter: 'Priya Shah' },
|
||||
]
|
||||
|
||||
export const sites: Site[] = [
|
||||
{ name: 'North Campus', buildings: ['Building A', 'Warehouse 04', 'Lab 2'], incidentCount: 12 },
|
||||
{ name: 'South Campus', buildings: ['Fabrication 02', 'Yard', 'Office block'], incidentCount: 7 },
|
||||
{ name: 'West Campus', buildings: ['Warehouse 01', 'Loading dock'], incidentCount: 5 },
|
||||
]
|
||||
@@ -1,38 +0,0 @@
|
||||
export const incidentTypes = ['Near miss', 'Hazard', 'Injury', 'Property damage'] as const
|
||||
export type IncidentType = (typeof incidentTypes)[number]
|
||||
|
||||
export const severities = ['Low', 'Medium', 'High'] as const
|
||||
export type Severity = (typeof severities)[number]
|
||||
|
||||
export type IncidentStatus = 'New report' | 'Investigation' | 'Action open' | 'Review required' | 'Resolved'
|
||||
|
||||
export interface Incident {
|
||||
id: string
|
||||
title: string
|
||||
type: IncidentType
|
||||
severity: Severity
|
||||
status: IncidentStatus
|
||||
site?: string
|
||||
building: string
|
||||
location: string
|
||||
/** ISO calendar date, e.g. `2024-08-28` */
|
||||
date: string
|
||||
reporter: string
|
||||
details?: string
|
||||
cause?: string
|
||||
response?: string
|
||||
}
|
||||
|
||||
export type NewIncident = Omit<Incident, 'id' | 'status' | 'date' | 'reporter'>
|
||||
|
||||
export interface Site {
|
||||
name: string
|
||||
buildings: string[]
|
||||
incidentCount: number
|
||||
}
|
||||
|
||||
export interface Person {
|
||||
name: string
|
||||
initials: string
|
||||
role: string
|
||||
}
|
||||
Reference in new issue
Block a user