diff --git a/frontend/src/app/(dashboard)/appointments/page.tsx b/frontend/src/app/(dashboard)/appointments/page.tsx index bf7734b..ef0152d 100644 --- a/frontend/src/app/(dashboard)/appointments/page.tsx +++ b/frontend/src/app/(dashboard)/appointments/page.tsx @@ -17,8 +17,8 @@ import { ScheduleDayPicker } from '@/components/ui/shared/ScheduleDayPicker'; import { ToastStack } from '@/components/ui/shared/Toast'; import { useToast } from '@/lib/hooks/useToast'; import type { AppointmentPurpose } from '@/types/appointment'; -import { formatApiErrorMessage } from '@/lib/formatApiError'; -import { compareLocalDayStart, getLocalDayIsoRange, startOfLocalDay } from '@/lib/appointmentTime'; +import { formatApiErrorMessage } from '@/components/shared/formatApiError'; +import { compareLocalDayStart, getLocalDayIsoRange, startOfLocalDay } from '@/components/appointments/appointmentTime'; const EMPTY_PATIENT_FORM: CreatePatientInput = { firstName: '', diff --git a/frontend/src/app/(dashboard)/patients/page.tsx b/frontend/src/app/(dashboard)/patients/page.tsx index 75a3ccf..9acc77f 100644 --- a/frontend/src/app/(dashboard)/patients/page.tsx +++ b/frontend/src/app/(dashboard)/patients/page.tsx @@ -4,7 +4,7 @@ import { useEffect, useMemo, useState } from 'react'; import { Button } from '@/components/ui/shared/Button'; import { ToastStack } from '@/components/ui/shared/Toast'; import { patientsApi } from '@/lib/api/patients'; -import { formatApiErrorMessage } from '@/lib/formatApiError'; +import { formatApiErrorMessage } from '@/components/shared/formatApiError'; import { useAuth } from '@/lib/hooks/useAuth'; import { useToast } from '@/lib/hooks/useToast'; import { hasPermission } from '@/components/shared/permissions'; diff --git a/frontend/src/lib/appointmentOverlapLayout.ts b/frontend/src/components/appointments/appointmentOverlapLayout.ts similarity index 100% rename from frontend/src/lib/appointmentOverlapLayout.ts rename to frontend/src/components/appointments/appointmentOverlapLayout.ts diff --git a/frontend/src/lib/appointmentTime.ts b/frontend/src/components/appointments/appointmentTime.ts similarity index 100% rename from frontend/src/lib/appointmentTime.ts rename to frontend/src/components/appointments/appointmentTime.ts diff --git a/frontend/src/lib/formatApiError.ts b/frontend/src/components/shared/formatApiError.ts similarity index 100% rename from frontend/src/lib/formatApiError.ts rename to frontend/src/components/shared/formatApiError.ts diff --git a/frontend/src/components/shared/organizationTypeIcon.ts b/frontend/src/components/shared/organizationTypeIcon.ts new file mode 100644 index 0000000..99816ab --- /dev/null +++ b/frontend/src/components/shared/organizationTypeIcon.ts @@ -0,0 +1,16 @@ +import { Building2, Beaker, type LucideIcon } from 'lucide-react'; +import type { Organization } from '@/types/organization'; + +/** Clinic → Building2, Lab → Beaker (switch-organization cards). */ +export function organizationTypeIcon(type: Organization['type']): LucideIcon { + return type === 'CLINIC' ? Building2 : Beaker; +} + +/** Organizations tab lists counterpart orgs (labs for clinics, clinics for labs). */ +export function counterpartOrganizationType( + currentType: Organization['type'] | undefined, +): Organization['type'] { + if (currentType === 'CLINIC') return 'LAB'; + if (currentType === 'LAB') return 'CLINIC'; + return 'CLINIC'; +} diff --git a/frontend/src/lib/treatmentSelection.ts b/frontend/src/components/shared/treatmentSelection.ts similarity index 89% rename from frontend/src/lib/treatmentSelection.ts rename to frontend/src/components/shared/treatmentSelection.ts index 482d00d..e3ac585 100644 --- a/frontend/src/lib/treatmentSelection.ts +++ b/frontend/src/components/shared/treatmentSelection.ts @@ -1,4 +1,4 @@ -import { isSameLocalCalendarDay } from '@/lib/appointmentTime'; +import { isSameLocalCalendarDay } from '@/components/appointments/appointmentTime'; import type { TreatmentAppointment } from '@/types/treatment'; /** diff --git a/frontend/src/components/ui/appointments/AppointmentBookingModal.tsx b/frontend/src/components/ui/appointments/AppointmentBookingModal.tsx index 914c053..17921df 100644 --- a/frontend/src/components/ui/appointments/AppointmentBookingModal.tsx +++ b/frontend/src/components/ui/appointments/AppointmentBookingModal.tsx @@ -12,7 +12,7 @@ import { compareLocalDayStart, formatTimeForInput, isSameLocalCalendarDay, -} from '@/lib/appointmentTime'; +} from '@/components/appointments/appointmentTime'; interface AppointmentBookingModalProps { open: boolean; diff --git a/frontend/src/components/ui/appointments/AppointmentScheduleGrid.tsx b/frontend/src/components/ui/appointments/AppointmentScheduleGrid.tsx index 13f2912..041d050 100644 --- a/frontend/src/components/ui/appointments/AppointmentScheduleGrid.tsx +++ b/frontend/src/components/ui/appointments/AppointmentScheduleGrid.tsx @@ -2,12 +2,12 @@ import { useMemo, useState } from 'react'; import type { AppointmentColumnProvider, AppointmentRecord } from '@/types/appointment'; -import { formatHourLabel } from '@/lib/appointmentTime'; +import { formatHourLabel } from '@/components/appointments/appointmentTime'; import { computeAppointmentLaneLayouts, findOverlapCluster, lanePositionStyles, -} from '@/lib/appointmentOverlapLayout'; +} from '@/components/appointments/appointmentOverlapLayout'; import { purposeStyle } from '@/components/ui/appointments/appointmentPurposeStyles'; import { AppointmentOverlapPopover } from '@/components/ui/appointments/AppointmentOverlapPopover'; diff --git a/frontend/src/components/ui/organizations/OrganizationSelectorContent.tsx b/frontend/src/components/ui/organizations/OrganizationSelectorContent.tsx index bfe1140..3283092 100644 --- a/frontend/src/components/ui/organizations/OrganizationSelectorContent.tsx +++ b/frontend/src/components/ui/organizations/OrganizationSelectorContent.tsx @@ -3,7 +3,9 @@ import { useMemo, useState } from 'react'; import { useAuth } from '@/lib/hooks/useAuth'; import { canCreateOrganizationFromCurrentOrg } from '@/components/shared/permissions'; -import { Building2, Beaker, Mail } from 'lucide-react'; +import { Building2, Mail } from 'lucide-react'; +import type { Organization } from '@/types/organization'; +import { organizationTypeIcon } from '@/components/shared/organizationTypeIcon'; import { Input } from '@/components/ui/shared/Input'; import { Button } from '@/components/ui/shared/Button'; @@ -26,8 +28,10 @@ export function OrganizationSelectorContent() { const [organizationEmail, setOrganizationEmail] = useState(''); const [organizationType, setOrganizationType] = useState<'CLINIC' | 'LAB'>('CLINIC'); - const getIcon = (type: string) => - type === 'CLINIC' ? : ; + const renderOrgTypeIcon = (type: Organization['type']) => { + const Icon = organizationTypeIcon(type); + return ; + }; const handleCreateOrganization = async () => { try { @@ -158,7 +162,7 @@ export function OrganizationSelectorContent() { className="surface-card p-6 transition-all text-left flex items-center gap-4 hover:border-primary/60" >
- {getIcon(org.type)} + {renderOrgTypeIcon(org.type)}
diff --git a/frontend/src/components/ui/shared/OrganizationCard.tsx b/frontend/src/components/ui/shared/OrganizationCard.tsx index 0d67055..2d785f1 100644 --- a/frontend/src/components/ui/shared/OrganizationCard.tsx +++ b/frontend/src/components/ui/shared/OrganizationCard.tsx @@ -1,7 +1,8 @@ // src/components/ui/OrganizationCard.tsx import React from 'react'; -import { Building2, Beaker, ChevronRight } from 'lucide-react'; +import { ChevronRight } from 'lucide-react'; import type { Organization } from '@/types/organization'; +import { organizationTypeIcon } from '@/components/shared/organizationTypeIcon'; interface OrganizationCardProps { organization: Organization; @@ -12,7 +13,7 @@ export const OrganizationCard: React.FC = ({ organization, onSelect, }) => { - const Icon = organization.type === 'CLINIC' ? Building2 : Beaker; + const Icon = organizationTypeIcon(organization.type); const typeText = organization.type === 'CLINIC' ? 'Dental Clinic' : 'Dental Lab'; return ( diff --git a/frontend/src/components/ui/shared/ScheduleDayPicker.tsx b/frontend/src/components/ui/shared/ScheduleDayPicker.tsx index 1684f56..e91d297 100644 --- a/frontend/src/components/ui/shared/ScheduleDayPicker.tsx +++ b/frontend/src/components/ui/shared/ScheduleDayPicker.tsx @@ -2,7 +2,7 @@ import { useEffect, useId, useRef, useState } from 'react'; import { ChevronDown, ChevronLeft, ChevronRight } from 'lucide-react'; -import { addCalendarDays, startOfLocalDay } from '@/lib/appointmentTime'; +import { addCalendarDays, startOfLocalDay } from '@/components/appointments/appointmentTime'; interface ScheduleDayPickerProps { value: Date; diff --git a/frontend/src/components/ui/shared/Sidebar.tsx b/frontend/src/components/ui/shared/Sidebar.tsx index 69561c5..80bc7f8 100644 --- a/frontend/src/components/ui/shared/Sidebar.tsx +++ b/frontend/src/components/ui/shared/Sidebar.tsx @@ -14,9 +14,13 @@ import { } from 'lucide-react'; import { useAuth } from '@/lib/hooks/useAuth'; import { canAccessAppointmentsSection, canViewTab } from '@/components/shared/permissions'; +import { + counterpartOrganizationType, + organizationTypeIcon, +} from '@/components/shared/organizationTypeIcon'; const menu = [ - { name: 'Today', path: '/today', icon: LayoutDashboard, read: 'TAB_TODAY_READ' as const }, + { name: 'Dashboard', path: '/today', icon: LayoutDashboard, read: 'TAB_TODAY_READ' as const }, { name: 'Staff', path: '/staff', icon: UserCog, read: 'TAB_STAFF_READ' as const }, { name: 'Patients', path: '/patients', icon: Users, read: 'TAB_PATIENTS_READ' as const }, { name: 'Appointment', path: '/appointments', icon: Calendar, read: 'TAB_APPOINTMENTS_READ' as const }, @@ -29,6 +33,9 @@ function Sidebar() { const pathname = usePathname(); const { currentOrganization } = useAuth(); const counterpartLabel = currentOrganization?.type === 'LAB' ? 'Clinics' : 'Labs'; + const organizationsTabIcon = organizationTypeIcon( + counterpartOrganizationType(currentOrganization?.type), + ); const visibleMenu = useMemo( () => { @@ -38,7 +45,7 @@ function Sidebar() { { name: counterpartLabel, path: '/organizations', - icon: FlaskConical, + icon: organizationsTabIcon, read: 'TAB_ORGANIZATIONS_READ' as const, }, menu[2], @@ -54,7 +61,7 @@ function Sidebar() { return canViewTab(currentOrganization, item.read); }); }, - [counterpartLabel, currentOrganization], + [counterpartLabel, organizationsTabIcon, currentOrganization], ); return ( diff --git a/frontend/src/components/ui/treatment/AppointmentsStrip.tsx b/frontend/src/components/ui/treatment/AppointmentsStrip.tsx index 15cc3a4..0a5cfb6 100644 --- a/frontend/src/components/ui/treatment/AppointmentsStrip.tsx +++ b/frontend/src/components/ui/treatment/AppointmentsStrip.tsx @@ -4,7 +4,7 @@ import { CalendarDays } from 'lucide-react'; import { purposeStyle } from '@/components/ui/appointments/appointmentPurposeStyles'; import { Card } from '@/components/ui/shared/Card'; import { ScheduleDayPicker } from '@/components/ui/shared/ScheduleDayPicker'; -import { startOfLocalDay } from '@/lib/appointmentTime'; +import { startOfLocalDay } from '@/components/appointments/appointmentTime'; import type { TreatmentAppointment } from '@/types/treatment'; interface AppointmentsStripProps { diff --git a/frontend/src/components/ui/treatment/TreatmentWorkspace.tsx b/frontend/src/components/ui/treatment/TreatmentWorkspace.tsx index 1e7230f..ed39b37 100644 --- a/frontend/src/components/ui/treatment/TreatmentWorkspace.tsx +++ b/frontend/src/components/ui/treatment/TreatmentWorkspace.tsx @@ -9,7 +9,7 @@ import { Button } from '@/components/ui/shared/Button'; import { Dropdown } from '@/components/ui/shared/Dropdown'; import { SearchBar } from '@/components/ui/shared/SearchBar'; import { Toast } from '@/components/ui/shared/Toast'; -import { compareLocalDayStart, isSameLocalCalendarDay, startOfLocalDay } from '@/lib/appointmentTime'; +import { compareLocalDayStart, isSameLocalCalendarDay, startOfLocalDay } from '@/components/appointments/appointmentTime'; import { fetchLinkedOrganizations, fetchMyAppointmentsForDay, @@ -17,7 +17,7 @@ import { saveTreatmentDraft, sendTreatmentRecord, } from '@/lib/mocks/treatmentMockApi'; -import { pickAutoAppointment } from '@/lib/treatmentSelection'; +import { pickAutoAppointment } from '@/components/shared/treatmentSelection'; import { canEditTreatment } from '@/components/shared/permissions'; import type { Organization } from '@/types/organization'; import type { diff --git a/frontend/src/lib/mocks/treatmentMockApi.ts b/frontend/src/lib/mocks/treatmentMockApi.ts index 21dbff9..93d1482 100644 --- a/frontend/src/lib/mocks/treatmentMockApi.ts +++ b/frontend/src/lib/mocks/treatmentMockApi.ts @@ -2,7 +2,7 @@ import { addCalendarDays, isSameLocalCalendarDay, startOfLocalDay, -} from '@/lib/appointmentTime'; +} from '@/components/appointments/appointmentTime'; import type { FdiToothId, LinkedOrganizationOption,