feat: unified station mode with POS + repairs desk view
Phase 1: Station shell - /station route replaces /pos (with redirect) - Shared lock screen, activity tracking, auto-lock timer - Permission-gated tab bar (POS | Repairs | Lessons) - POSRegister embedded mode (skip lock/timer/topbar) - Sidebar navigates to /station Phase 2: Repairs station — front desk - Status bar with count badges per status group, clickable filters - Ticket queue panel with search and status filtering - Ticket detail panel with status progress, notes, photos, line items - Full stepped intake form: customer → item → problem/estimate → review - Service template quick-add for line items Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
import { useState } from 'react'
|
||||
import { RepairStatusBar } from './repair-status-bar'
|
||||
import { RepairQueuePanel } from './repair-queue-panel'
|
||||
import { RepairDetailPanel } from './repair-detail-panel'
|
||||
import { RepairIntakeForm } from './repair-intake-form'
|
||||
|
||||
interface RepairDeskViewProps {
|
||||
canEdit: boolean
|
||||
}
|
||||
|
||||
export function RepairDeskView({ canEdit }: RepairDeskViewProps) {
|
||||
const [selectedTicketId, setSelectedTicketId] = useState<string | null>(null)
|
||||
const [intakeMode, setIntakeMode] = useState(false)
|
||||
const [statusFilter, setStatusFilter] = useState<string[] | null>(null)
|
||||
const [activeFilterLabel, setActiveFilterLabel] = useState<string | null>(null)
|
||||
|
||||
function handleFilterChange(statuses: string[] | null) {
|
||||
setStatusFilter(statuses)
|
||||
// Track which group label is active for the status bar highlight
|
||||
if (!statuses) {
|
||||
setActiveFilterLabel(null)
|
||||
} else {
|
||||
// Map statuses back to group label
|
||||
const groups: Record<string, string> = {
|
||||
new: 'New', in_transit: 'New', intake: 'New',
|
||||
diagnosing: 'Diagnosing', pending_approval: 'Diagnosing',
|
||||
approved: 'In Progress', in_progress: 'In Progress', pending_parts: 'In Progress',
|
||||
ready: 'Ready',
|
||||
}
|
||||
setActiveFilterLabel(groups[statuses[0]] ?? null)
|
||||
}
|
||||
}
|
||||
|
||||
if (intakeMode) {
|
||||
return (
|
||||
<div className="flex flex-col h-full">
|
||||
<RepairIntakeForm
|
||||
onComplete={(ticketId) => {
|
||||
setIntakeMode(false)
|
||||
setSelectedTicketId(ticketId)
|
||||
}}
|
||||
onCancel={() => setIntakeMode(false)}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex flex-col h-full">
|
||||
<RepairStatusBar activeFilter={activeFilterLabel} onFilterChange={handleFilterChange} />
|
||||
<div className="flex flex-1 min-h-0">
|
||||
<div className="w-[35%] border-r border-border overflow-hidden">
|
||||
<RepairQueuePanel
|
||||
selectedTicketId={selectedTicketId}
|
||||
onSelectTicket={setSelectedTicketId}
|
||||
onNewIntake={() => setIntakeMode(true)}
|
||||
statusFilter={statusFilter}
|
||||
/>
|
||||
</div>
|
||||
<div className="w-[65%] overflow-hidden">
|
||||
<RepairDetailPanel ticketId={selectedTicketId} canEdit={canEdit} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user