Show equipment quantities on schedule + inspection event rows

Goal

Display equipment quantities (and optional direction) for job events on the schedule and inspection details screens in the inspector mobile app (inspector-app), consistent with how Attik resolves equipment from charges + events.

Backend data model (Mongo / attik-backend)

Collections & roles

  • charges — Line items on an inspection. charge.equipmentRequired is an array of { _equipmentCategoryId, value, direction? }. This is the source of truth for quantities when booking/sync sets counts.
  • events — Scheduled calendar events. event.equipmentRequired embeds category, optional direction, optional per-event value override, _equipmentIds / _equipmentId for specific units. If value is omitted, the UI treats quantity as “use charge default” and resolves the number from the linked charge row matching the same equipment category.
  • equipmentCategory — Category metadata (name, equipmentType: tool | reusable | consumable). Used for labels; type is not duplicated on the charge row.
  • equipment (pieces) — Physical units; referenced by id(s) on the event when applicable.

Diagram (charges ↔ events)

flowchart TB
  subgraph insp["Inspection"]
    C["charges[]"]
    E["events[]"]
  end

  E -->|"_chargeId"| C

  subgraph chargeEmb["Charge: equipmentRequired[]"]
    CQ["Per category: value, direction? — canonical quantities"]
  end

  subgraph eventEmb["Event: equipmentRequired"]
    CAT["_equipmentCategoryId"]
    VAL["value? optional override"]
    DIR["equipmentDirection?"]
    PID["_equipmentIds / _equipmentId"]
  end

  C --> chargeEmb
  E --> eventEmb

  CAT --> MATCH["Pick categoryId: event category OR first charge row"]
  CQ --> MATCH
  MATCH --> ROW["Matching charge row for categoryId"]
  VAL --> QTY{event value set?}
  QTY -->|yes| OUT["Use event value"]
  QTY -->|no| OUT2["Use charge row value"]
  ROW --> OUT2
  DIR --> DISP["Display qty + direction + units"]
  PID --> DISP
  OUT --> DISP
  OUT2 --> DISP

How charge + event interact (resolution)

  1. Link: event._chargeId → inspection charges where charge._id === event._chargeId.
  2. Category id to use for matching: event.equipmentRequired._equipmentCategoryId if set, else first row on linkedCharge.equipmentRequired (same rule as tools: resolveEventEquipmentCategoryId).
  3. Quantity: If typeof event.equipmentRequired.value === 'number', use it; else use the matching charge row’s value for that category (or first charge row when only one category row exists).
  4. Direction: Prefer event.equipmentRequired.equipmentDirection when present; else infer from charge row direction / workflow as needed.
  5. Multi-row charges: If the charge has multiple equipmentRequired rows and the event does not pin a category, tools default to the first charge row — mobile should match that behavior for consistency.

Reference implementation (web): toolsv2ServicesPayments.tsx (matchingChargeEquipmentRow, categoryIdForMatch), CreateEditEventModal.tsx (resolveEventEquipmentCategoryId).

API

Mobile already calls GET inspection/:id with populate: ['charges', 'services', 'people', 'reports', 'events'] (hooks/useInspectionDetails.ts). Verify responses include equipmentRequired on populated charges and events (full documents). If any field is stripped by aggregation, add a small backend follow-up to expose it.

Mobile app (inspector-app) — implementation notes

Types

  • Extend EventPopulated in types/index.ts with optional equipmentRequired, _chargeId, and any fields the API returns (align with toolsv2 event type / attik EventEquipmentRequiredType).
  • Extend Charge with optional equipmentRequired[] if not already present for populated charges.

Inspection details

  • components/inspection/EventsList.tsx — Under each event (name, time, inspector), render a compact equipment line when resolvable: category label (need category name: either populate equipment categories from API, map id → name via a small lookup endpoint/cache, or ship names in a parallel field — confirm with backend), quantity, optional in/out, optional piece label if _equipmentIds present.
  • Reuse or mirror [id].tsx data: inspection.charges + inspection.events passed into a small pure helper (e.g. resolveEventEquipmentDisplay(event, charges, categoryNameById?)) kept in lib/ or utils/.

Schedule

  • hooks/useSchedule.ts — Today populates charges but not events. Add events to populate so schedule cards can resolve equipment the same way as inspection details (or fetch events only when expanding a card — product call).
  • components/schedule/ScheduleCard.tsx — For items that represent events (or inspection rows that surface events), show the same compact equipment snippet when data exists. May require grouped/sub-items handling for eventGroup.

UX

  • Keep copy short on schedule (e.g. Radon × 2 · Out).
  • Hide row when no equipment on charge+event after resolution.
  • Match icons/severity patterns from tools if applicable (optional).

Acceptance criteria

  • [ ] Inspection details: each event with equipment-relevant charge shows resolved quantity (and direction when applicable).
  • [ ] Schedule: user can see equipment quantities for upcoming events without opening inspection (subject to populate/perf decision).
  • [ ] Behavior matches tools category fallback and charge-default semantics.
  • [ ] Types updated; no runtime errors when equipmentRequired is missing.

Out of scope / follow-ups

  • Editing equipment from mobile (read-only display only unless product asks).
  • Full parity with tools piece names may require equipment list or denormalized labels on API responses.

Related code (repos)

  • Backend models: attik-backendequipmentSchema.ts (EventEquipmentRequiredType, EquipmentQuantityType), chargeSchema.ts, eventSchema.ts.
  • Web UI reference: toolsv2ServicesPayments.tsx, CreateEditEventModal.tsx.
  • Mobile: inspector-appEventsList.tsx, ScheduleCard.tsx, useSchedule.ts, useInspectionDetails.ts, types/index.ts.

Please authenticate to join the conversation.

Upvoters
Status

Completed

Board
🏠

Main App

Date

2 months ago

Author

Linear

Subscribe to post

Get notified by email when there are changes.