feat: initialize project structure with core components and pages
- Added shared styles for UI components in `src/components/styles.ts`. - Created configuration constants in `src/lib/config.ts`. - Implemented date formatting and greeting functions in `src/lib/dates.ts` and corresponding tests in `src/lib/dates.test.ts`. - Developed incident management functions in `src/lib/incidents.ts` with tests in `src/lib/incidents.test.ts`. - Established navigation structure in `src/lib/navigation.ts`. - Seeded demo data for incidents and users in `src/lib/seed.ts`. - Defined tone classes for UI elements in `src/lib/tones.ts`. - Created type definitions for incidents and related entities in `src/lib/types.ts`. - Set up main application entry point in `src/main.tsx`. - Developed various pages including About, Analytics, Incidents, Locations, Overview, and Report Incident. - Configured testing setup in `src/test/setup.ts` and TypeScript configurations. - Integrated Vite for development and testing with appropriate plugins.
This commit is contained in:
1 parent
732d4d8931
commit
a382fa904a
53 files changed
+3523
-31
No files matched your search
@@ -0,0 +1,62 @@
|
||||
import { FileText, Filter, Plus, Search } from 'lucide-react'
|
||||
import { useState } from 'react'
|
||||
import { NavLink } from 'react-router-dom'
|
||||
import { IncidentTable } from '../components/IncidentTable'
|
||||
import { Page } from '../components/Page'
|
||||
import { PageIntro } from '../components/PageIntro'
|
||||
import { filterBox, panel, primaryButton, secondaryButton } from '../components/styles'
|
||||
import { ALL_TYPES, filterIncidents, type TypeFilter } from '../lib/incidents'
|
||||
import { incidentTypes, type Incident } from '../lib/types'
|
||||
|
||||
export function Incidents({ incidents }: { incidents: Incident[] }) {
|
||||
const [query, setQuery] = useState('')
|
||||
const [type, setType] = useState<TypeFilter>(ALL_TYPES)
|
||||
const filtered = filterIncidents(incidents, query, type)
|
||||
|
||||
return (
|
||||
<Page>
|
||||
<PageIntro
|
||||
eyebrow="Safety register"
|
||||
title="Incidents"
|
||||
copy="A complete record of reported events, hazards, and learnings."
|
||||
action={
|
||||
<NavLink className={primaryButton} to="/report">
|
||||
<Plus size={17} /> Report incident
|
||||
</NavLink>
|
||||
}
|
||||
/>
|
||||
<section className={`${panel} overflow-hidden`}>
|
||||
<div className="flex flex-wrap items-center gap-2.5 border-b border-line px-[17px] py-3.5 sm:flex-nowrap sm:px-6 sm:py-[18px]">
|
||||
<div className={`${filterBox} basis-full sm:max-w-[350px] sm:flex-1 sm:basis-auto`}>
|
||||
<Search size={17} />
|
||||
<input
|
||||
className="w-full bg-transparent text-xs text-ink outline-none"
|
||||
value={query}
|
||||
onChange={(event) => setQuery(event.target.value)}
|
||||
placeholder="Search incidents"
|
||||
aria-label="Search incidents"
|
||||
/>
|
||||
</div>
|
||||
<div className={`${filterBox} sm:ml-auto`}>
|
||||
<Filter size={16} />
|
||||
<select
|
||||
className="bg-transparent text-xs text-ink outline-none"
|
||||
value={type}
|
||||
onChange={(event) => setType(event.target.value as TypeFilter)}
|
||||
aria-label="Filter by type"
|
||||
>
|
||||
<option>{ALL_TYPES}</option>
|
||||
{incidentTypes.map((option) => (
|
||||
<option key={option}>{option}</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
<button type="button" className={secondaryButton}>
|
||||
<FileText size={16} /> Export
|
||||
</button>
|
||||
</div>
|
||||
<IncidentTable incidents={filtered} wide />
|
||||
</section>
|
||||
</Page>
|
||||
)
|
||||
}
|
||||
Reference in new issue
Block a user