Service Dates Tab

Developer guide for the Service Dates calendar and detail panel used on Assembly and Component detail pages.

1. Screenshot

Service Dates — Assembly (web)

Live screenshot from dev environment (Assembly detail, Service Dates tab)

2. Component Tree

ServiceDates                         components/service-dates/index.tsx
 props: asset, assetType, serviceTypes, permissions, userAgId, serviceDates, loading, refetch
 |- [hasServiceDates = true]
 |   '- div.flex.flex-col.lg:flex-row  height: calc(100vh - 200px)
 |       |- LEFT (lg:w-1/2) — Calendar card
 |       |   '- div.rounded-lg.border.border-gray-200.bg-white
 |       |       |- Card Header: "Service Dates" + Add Service button
 |       |       '- DashboardCalendarBase    components/dashboard-calendar/index.tsx
 |       |           props: dashboardState, calendarView, setCalendarView,
 |       |                  hideMapButton, hideExpandButton, hideAssetColumn,
 |       |                  hideLocationColumn, selectedEventId, onEventClick
 |       |           |- View toggle: Day | Week | Month | List
 |       |           |- Today + Prev/Next nav
 |       |           |- MonthView             dashboard-calendar/month-view.tsx
 |       |           |- WeekView              dashboard-calendar/week-view.tsx
 |       |           |- TodayView             dashboard-calendar/today-view.tsx
 |       |           |- ListView              dashboard-calendar/list-view.tsx
 |       |           '- CalendarLegend        dashboard-calendar/legend.tsx
 |       '- RIGHT (flex-1) — Detail panel
 |           '- ServiceDateDetail
 |               |- Header: service_type_name + date + time + Edit button
 |               |- Status + Due grid (2 cols)
 |               |- Notes section (allNotes from items)
 |               |- Documents section (images + file list)
 |               '- Items section (kit multi-asset, shown when items.length > 1)
 |- [hasServiceDates = false]
 |   '- EmptyState                   components/empty-state/index.tsx
 |       props: cardTitle="Service Dates", icon=CalendarDaysIcon,
 |              title, description, actionLabel (if canManage)
 |- [assetType = 'kit']
 |   '- ServiceDates (same component as asy/comp — list + detail split)
 |       Events are kit-level (one row per SD, not per item)
 |       Detail panel appends "Associated Assets" section AFTER Documents
 |       Notes + Documents aggregate across root + items via V2 items[] naturally
 |- AddServiceModal                  components/add-service-modal/index.tsx
 '- UpdateServiceModal               components/update-service-modal/index.tsx
     props: serviceDate, fromKitId (deeplink), handleDeleteServiceDate

3. Design Tokens

ElementTailwind Classes
Outer layoutflex flex-col gap-4 lg:flex-row with height: calc(100vh - 200px)
Calendar cardflex w-full flex-shrink-0 flex-col overflow-hidden lg:w-1/2
Inner: rounded-lg border border-gray-200 bg-white
Card headerflex items-center justify-between border-b border-gray-100 px-5 py-4
Card header titletext-lg font-bold text-gray-900
Add Service buttonbg-ag_red hover:bg-ag_red/90 inline-flex items-center gap-1.5 rounded-lg px-3 py-1.5 text-sm font-medium text-white
Detail panelflex-1 overflow-y-auto rounded-lg border border-gray-200 bg-white
Detail headerborder-b border-gray-100 px-6 py-5
Edit button (detail)inline-flex items-center gap-1.5 rounded-lg border border-gray-200 bg-white px-3 py-1.5 text-sm font-medium text-gray-700 shadow-sm hover:bg-gray-50
View toggle (active)bg-ag_red text-white px-2.5 py-1 text-xs font-medium
View toggle (inactive)text-gray-600 hover:bg-gray-50 px-2.5 py-1 text-xs font-medium
Selected row (list)bg-red-50/60 border-l-2 border-l-ag_red
Unselected rowhover:bg-gray-50
Status doth-1.5 w-1.5 rounded-full + color from getStatusClasses()
Status: CompletedBadge: bg-green-50 text-green-700   Dot: bg-emerald-500
Status: OverdueBadge: bg-red-50 text-red-700   Dot: bg-ag_red
Status: ScheduledBadge: bg-blue-50 text-blue-700   Dot: bg-blue-500
Status: OpenBadge: bg-gray-100 text-gray-600   Dot: bg-gray-400
Notes cardrounded-lg bg-gray-50 px-3 py-2
Section labeltext-xs font-semibold uppercase tracking-wide text-gray-500 with icon
Empty state cardrounded-lg border border-gray-200 bg-white with header + p-12 text-center
Column splitLeft: w-full lg:w-1/2   Right: flex-1
Notes/docs count badgeIcon: h-3 w-3   Text: text-[10px] text-gray-400

4. Data Fields

Primary entity: ServiceDateV2Entity. Each service date has nested items[] (one per asset in a kit, or one for standalone).

FieldTypeSourceDisplay Location
Service Typestringsd.service_type_nameDetail header title, list view Service Type column
Datenumber (epoch)sd.root_dateDetail header (formatted), list view Date column
Start Timenumber | nullsd.root_start_timeDetail header (HH:mm), list view Time column
End Timenumber | nullsd.root_end_timeDetail header (HH:mm), list view Time column
Full Daybooleansd.root_is_full_dayDetail header ("Full day"), list view Time column
Statusnumber (enum)sd._itemStatus ?? items[0].statusDetail Status field, list view Status column with dot
Duecomputeddayjs diff from todayDetail Due field ("In 5 days", "3 days ago", "Today")
Notesarrayitems.flatMap(i => i.notes) · kit aggregates naturally via items[]Detail Notes section (same on asy/comp/kit)
Documentsarrayitems.flatMap(i => i.documents) · kit aggregates naturally via items[]Detail Docs section: thumbnails + file list (same on asy/comp/kit)
Itemsarraysd.itemsRenders as "Associated Assets" section in kit detail panel (after Documents)
is_root (derived)booleanitem.asset_id === sd.asset_idRoot edits cascade to children (backend); non-root edits are local
Note association (XOR)FKasset_id or service_date_items_skAsset-level note vs service-date-item note
Document association (XOR)FKservice_date_item_id or asset_note_idItem doc vs note attachment
Asset IDstring (ObjectId)sd.asset_idUsed to find relevant item for status
Asset Typestringsd.asset_typeCalendar event icon, permission resolution

Status enum: 1=Open, 2=Confirmed, 3=Completed. Overdue is a derived visual (status=1 + past due). Mapped via SERVICE_DATE_STATUS_2 from shared-layer.

5. Permissions

ActionRIGHTKEYCondition
View tab / listReadServiceDates
ReadServiceDatesAssembly, ReadServiceDatesComponent
Tab visible only with read permission for the asset type
Add Service DateManageServiceDates{AssetType}
ManageServiceDatesAssembly, ManageServiceDatesComponent
"+ Add Service" button visible only with manage permission
Edit Service DateManageServiceDates{AssetType}"Edit" button in detail panel. Opens UpdateServiceModal.
Delete Service DateManageServiceDates{AssetType}Inside UpdateServiceModal, confirmation required before delete

Permission resolved via: assetType === 'component' ? permissions[RIGHTKEYS.ManageServiceDatesComponent] : permissions[RIGHTKEYS.ManageServiceDatesAssembly]

6. Variants

DEFAULT List View with Detail

Split layout: calendar card (left 1/2) in List view with DashboardCalendarBase, detail panel (right 1/2) showing ServiceDateDetail. First item auto-selected. Selected row has bg-red-50/60 border-l-2 border-l-ag_red.

MONTH Month View

Calendar switches to month grid. Clicking a day navigates to Day view. Event dots shown on calendar cells. Detail panel still visible on the right.

EMPTY Empty State

When serviceDates.length === 0, renders shared EmptyState component with cardTitle="Service Dates", CalendarDaysIcon, and "+ Add Service" CTA (if canManage).

DETAIL Detail Panel with Documents

Right panel shows: header (service type + date/time), status/due grid, Notes section with gray cards, Documents section with image thumbnails (80x80 grid) and file list, Items section (for kits with multiple items).

DEEPLINK Deep Link (query param)

URL query ?serviceDate=123 auto-selects the service date in the master–detail panel (same behaviour for assembly / component / kit). Query params are stripped after processing.

KIT Kit -- List + Detail

Kit uses the same list + detail layout as assembly / component. Each row in the list is one kit-level service date (not per child item). The detail panel has identical sections / element order / Edit-button placement, with one kit-specific addition: an Associated Assets section appended AFTER Documents, listing the child items of sd.items[].

ADD Add Service (Assembly/Component)

Modal with: service type dropdown, date picker, start/end time inputs, full-day toggle, Save/Cancel buttons. Opens from the "+ Add Service" button or FAB.

ADD KIT Add Service (Kit)

Same modal as Assembly/Component PLUS an item selector table with checkboxes for each assembly/component in the kit. User selects which child assets receive the service date.

EDIT Edit Service (Web)

Modal overlay with three stacked sections: Service Details (type dropdown, date, time, full-day toggle, confirmed status), Documents (upload area, existing docs table with delete, upload button), Notes (add note textarea with file attach, existing notes list). Footer: Delete (red) + Cancel + Save. Source: components/update-service-modal/index.tsxServiceDetailsSection + DocumentsSection + NotesSection.

MOBILE ADD Add Service (Mobile)

Full-screen modal (not popup). Header: "Add Service Date" + close. Scrollable form: service type dropdown, date picker, time pickers, full-day toggle, document upload section. For kits: item selector with checkboxes. Fixed footer: Cancel + Save.

MOBILE EDIT Edit Service (Mobile)

Full-screen modal with pre-filled form. Same fields as add + confirmed toggle, documents section with existing docs and upload, notes section with existing notes and add note input. Fixed footer: Delete (red) + Cancel + Save.

7. Status

Web implementation complete (Assembly, Component)
DashboardCalendarBase reused from dashboard (Day/Week/Month/List views)
Permissions enforced (ReadServiceDates, ManageServiceDates per asset type)
Deep link support via ?serviceDate=X — selects the service date in the detail panel on any asset type
Document preview modal with navigation
Selected row highlighting in list view
Notes/docs count badges on list rows
Mobile (React Native) -- not started
Test coverage

8. Web Interactive Mockup

Click variant tabs to switch between states. Mockup reflects actual Tailwind classes from the codebase.

Service Dates

Service Calendar

April 2026

Date
Due In
Service Type
Status
Overdue Due soon Scheduled Completed Open

Pressure Test

22 Apr 2026 09:00 - 11:00

Status

Scheduled

Due

In 4 days

Notes (1)

Pressure test scheduled per client request. Use 1.5x working pressure.

15.04.2026 14:32

Documents (0)

No documents attached

Service Dates

Service Calendar

April 2026

Mon
Tue
Wed
Thu
Fri
Sat
Sun
30
31
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
1
2
3
Select a service date to view details

Service Dates

No service dates

There are no service dates scheduled for this asset yet.

Service Dates

Date
Due In
Service Type
Status

Hydraulic Flush

15 Mar 2026 Full day

Status

Completed

Due

34 days ago

Notes (2)

Flush completed successfully. No contamination detected.

15.03.2026 16:45

Used ISO 4406 cleanliness standard. Results: 16/14/11.

15.03.2026 17:02

Documents (3)

IMG
IMG

Service Dates

Service Calendar

April 2026

Date
Due In
Service Type
Status
Overdue Due soon Scheduled Completed Open

Pressure Test

22 Apr 2026 09:00 - 11:00

Status

Scheduled

Due

In 4 days

Notes (3)

Pressure test scheduled per client request. Use 1.5x working pressure.

15.04.2026 14:32

Torque wrench calibrated before the job. Cert expires May 2026.

18.04.2026 08:05

Flange bolts re-torqued to 95 Nm. Gasket replaced (part #G-2201).

18.04.2026 14:22

Documents (2)

pressure-cert.pdf
gauge-reading.jpg

Associated Assets (3)

  • 2" Gate Valve (Assembly · GV-0042) Open →
  • Hydraulic Hose 3/4" (Component · HH-0171) Open →
  • Pressure Gauge 100 bar (Component · PG-0088) Open →

Only kit service dates have this section — lists the assemblies / components scheduled under this service date (sd.items[]).

Add Service Date

Drag & drop files here, or browse

PDF, images, documents up to 10 MB

test-certificate.pdf 245 KB

Source: components/add-service-modal/index.tsx uses DocumentsSection

Add Service Date (Kit)

Which assemblies / components in this kit should receive this service date? All selected by default.

Asset Type
IMG
2" Gate Valve
Assembly
IMG
Hydraulic Hose 3/4"
Component
IMG
Pressure Gauge 0-600
Component

Edit Service Date

Service Details

Documents (2)

Drag & drop or browse

Name Updated At Type
test-certificate.pdf 15.04.2026 application/pdf
inspection-photo.jpg 15.04.2026 image/jpeg

Notes (1)

John Smith 15.04.2026 14:32

Pressure test scheduled per client request. Use 1.5x working pressure.

Components: UpdateServiceModalServiceDetailsSection + DocumentsSection + NotesSection  |  Source: components/update-service-modal/index.tsx

9. Mobile Design (React Native)

Proposed native layout for Service Dates. Card list with bottom sheet detail, FAB for adding. Variant switcher below.

9:41

Assemblies

2" Gate Valve

Info Service Notes Components Specs Location QR Code Label

Tab visibility depends on asset type and permissions

Pressure Test Scheduled
22 Apr 2026 09:00 - 11:00
In 4 days
1 0
Visual Inspection Overdue
10 Apr 2026 Full day
8 days overdue
2 1
Hydraulic Flush Completed
15 Mar 2026
Completed
2 3
Annual Recertification Open
30 May 2026

In 42 days

Dashboard
Search
Assets
QR Scan
Profile

Proposed mobile layout -- card list with bottom sheet detail, FAB opens Add Service modal directly (no context menu). Kit variants mirror the asy/comp layout with one addition: an Associated Assets section inserted after Documents in the bottom sheet (AB#94913).