@burdenoff/microfe-crewfoundry 2026.1030.4 → 2026.1102.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/dist/crewfoundry/CrewFoundryRoot.d.ts.map +1 -1
  2. package/dist/crewfoundry/CrewFoundryRoot.js +14 -0
  3. package/dist/crewfoundry/CrewFoundryRoot.js.map +1 -1
  4. package/dist/crewfoundry/CrewFoundryRoutes.d.ts.map +1 -1
  5. package/dist/crewfoundry/CrewFoundryRoutes.js +27 -19
  6. package/dist/crewfoundry/CrewFoundryRoutes.js.map +1 -1
  7. package/dist/crewfoundry/components/field/DispatchBoardCard.d.ts +13 -0
  8. package/dist/crewfoundry/components/field/DispatchBoardCard.d.ts.map +1 -0
  9. package/dist/crewfoundry/components/field/DispatchBoardCard.js +124 -0
  10. package/dist/crewfoundry/components/field/DispatchBoardCard.js.map +1 -0
  11. package/dist/crewfoundry/components/field/FieldBadges.d.ts +12 -0
  12. package/dist/crewfoundry/components/field/FieldBadges.d.ts.map +1 -0
  13. package/dist/crewfoundry/components/field/FieldBadges.js +45 -0
  14. package/dist/crewfoundry/components/field/FieldBadges.js.map +1 -0
  15. package/dist/crewfoundry/components/field/MyDispatchItem.d.ts +12 -0
  16. package/dist/crewfoundry/components/field/MyDispatchItem.d.ts.map +1 -0
  17. package/dist/crewfoundry/components/field/MyDispatchItem.js +46 -0
  18. package/dist/crewfoundry/components/field/MyDispatchItem.js.map +1 -0
  19. package/dist/crewfoundry/components/field/MyShiftItem.d.ts +14 -0
  20. package/dist/crewfoundry/components/field/MyShiftItem.d.ts.map +1 -0
  21. package/dist/crewfoundry/components/field/MyShiftItem.js +84 -0
  22. package/dist/crewfoundry/components/field/MyShiftItem.js.map +1 -0
  23. package/dist/crewfoundry/components/field/ShiftsCard.d.ts +12 -0
  24. package/dist/crewfoundry/components/field/ShiftsCard.d.ts.map +1 -0
  25. package/dist/crewfoundry/components/field/ShiftsCard.js +84 -0
  26. package/dist/crewfoundry/components/field/ShiftsCard.js.map +1 -0
  27. package/dist/crewfoundry/components/field/fieldFormat.d.ts +8 -0
  28. package/dist/crewfoundry/components/field/fieldFormat.d.ts.map +1 -0
  29. package/dist/crewfoundry/components/field/fieldFormat.js +15 -0
  30. package/dist/crewfoundry/components/field/fieldFormat.js.map +1 -0
  31. package/dist/crewfoundry/components/field/fieldForms.d.ts +19 -0
  32. package/dist/crewfoundry/components/field/fieldForms.d.ts.map +1 -0
  33. package/dist/crewfoundry/components/field/fieldForms.js +223 -0
  34. package/dist/crewfoundry/components/field/fieldForms.js.map +1 -0
  35. package/dist/crewfoundry/components/forms/FormModal.d.ts +1 -1
  36. package/dist/crewfoundry/components/forms/FormModal.d.ts.map +1 -1
  37. package/dist/crewfoundry/components/forms/FormModal.js +1 -1
  38. package/dist/crewfoundry/components/forms/FormModal.js.map +1 -1
  39. package/dist/crewfoundry/lib/fieldOps.d.ts +105 -0
  40. package/dist/crewfoundry/lib/fieldOps.d.ts.map +1 -0
  41. package/dist/crewfoundry/lib/fieldOps.js +85 -0
  42. package/dist/crewfoundry/lib/fieldOps.js.map +1 -0
  43. package/dist/crewfoundry/lib/useFieldOpsData.d.ts +14 -0
  44. package/dist/crewfoundry/lib/useFieldOpsData.d.ts.map +1 -0
  45. package/dist/crewfoundry/lib/useFieldOpsData.js +31 -0
  46. package/dist/crewfoundry/lib/useFieldOpsData.js.map +1 -0
  47. package/dist/crewfoundry/pages/DashboardExecutiveDashboardPage.d.ts +8 -0
  48. package/dist/crewfoundry/pages/DashboardExecutiveDashboardPage.d.ts.map +1 -1
  49. package/dist/crewfoundry/pages/DashboardExecutiveDashboardPage.js +468 -212
  50. package/dist/crewfoundry/pages/DashboardExecutiveDashboardPage.js.map +1 -1
  51. package/dist/crewfoundry/pages/FieldMyWorkPagePage.d.ts +9 -0
  52. package/dist/crewfoundry/pages/FieldMyWorkPagePage.d.ts.map +1 -0
  53. package/dist/crewfoundry/pages/FieldMyWorkPagePage.js +141 -0
  54. package/dist/crewfoundry/pages/FieldMyWorkPagePage.js.map +1 -0
  55. package/dist/crewfoundry/pages/FieldOperationsPagePage.d.ts +9 -0
  56. package/dist/crewfoundry/pages/FieldOperationsPagePage.d.ts.map +1 -0
  57. package/dist/crewfoundry/pages/FieldOperationsPagePage.js +231 -0
  58. package/dist/crewfoundry/pages/FieldOperationsPagePage.js.map +1 -0
  59. package/dist/crewfoundry/pages/HiringCandidatesPagePage.js +24 -24
  60. package/dist/crewfoundry/pages/HrEmployeeProfilePagePage.js +4 -4
  61. package/dist/crewfoundry/store/crewfoundryStore.d.ts +47 -1
  62. package/dist/crewfoundry/store/crewfoundryStore.d.ts.map +1 -1
  63. package/dist/crewfoundry/store/crewfoundryStore.js +93 -66
  64. package/dist/crewfoundry/store/crewfoundryStore.js.map +1 -1
  65. package/dist/crewfoundry/store/fieldOpsStore.d.ts +76 -0
  66. package/dist/crewfoundry/store/fieldOpsStore.d.ts.map +1 -0
  67. package/dist/crewfoundry/store/fieldOpsStore.js +188 -0
  68. package/dist/crewfoundry/store/fieldOpsStore.js.map +1 -0
  69. package/package.json +1 -1
@@ -0,0 +1,45 @@
1
+ import { formatEnumLabel as e } from "../../utils/formatEnumLabel.js";
2
+ import { jsx as t } from "react/jsx-runtime";
3
+ import { Badge as n } from "@burdenoff/fe-libs/ui";
4
+ //#region src/crewfoundry/components/field/FieldBadges.tsx
5
+ var r = {
6
+ SCHEDULED: "outline",
7
+ IN_PROGRESS: "default",
8
+ COMPLETED: "secondary",
9
+ CANCELLED: "outline",
10
+ MISSED: "destructive"
11
+ }, i = {
12
+ OPEN: "outline",
13
+ ASSIGNED: "secondary",
14
+ EN_ROUTE: "default",
15
+ ON_SITE: "default",
16
+ COMPLETED: "secondary",
17
+ CANCELLED: "outline"
18
+ }, a = {
19
+ LOW: "outline",
20
+ NORMAL: "secondary",
21
+ HIGH: "default",
22
+ URGENT: "destructive"
23
+ };
24
+ function o({ status: i }) {
25
+ return /* @__PURE__ */ t(n, {
26
+ variant: r[i] ?? "outline",
27
+ children: e(i)
28
+ });
29
+ }
30
+ function s({ status: r }) {
31
+ return /* @__PURE__ */ t(n, {
32
+ variant: i[r] ?? "outline",
33
+ children: e(r)
34
+ });
35
+ }
36
+ function c({ priority: r }) {
37
+ return /* @__PURE__ */ t(n, {
38
+ variant: a[r] ?? "outline",
39
+ children: e(r)
40
+ });
41
+ }
42
+ //#endregion
43
+ export { c as DispatchPriorityBadge, s as DispatchStatusBadge, o as ShiftStatusBadge };
44
+
45
+ //# sourceMappingURL=FieldBadges.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FieldBadges.js","names":[],"sources":["../../../../src/crewfoundry/components/field/FieldBadges.tsx"],"sourcesContent":["import { Badge } from '@burdenoff/fe-libs/ui';\nimport type { DispatchPriority, DispatchStatus, ShiftStatus } from '../../lib/fieldOps';\nimport { formatEnumLabel } from '../../utils/formatEnumLabel';\n\ntype BadgeVariant = 'default' | 'secondary' | 'outline' | 'destructive';\n\nconst SHIFT_VARIANT: Record<ShiftStatus, BadgeVariant> = {\n SCHEDULED: 'outline',\n IN_PROGRESS: 'default',\n COMPLETED: 'secondary',\n CANCELLED: 'outline',\n MISSED: 'destructive',\n};\n\nconst DISPATCH_VARIANT: Record<DispatchStatus, BadgeVariant> = {\n OPEN: 'outline',\n ASSIGNED: 'secondary',\n EN_ROUTE: 'default',\n ON_SITE: 'default',\n COMPLETED: 'secondary',\n CANCELLED: 'outline',\n};\n\nconst PRIORITY_VARIANT: Record<DispatchPriority, BadgeVariant> = {\n LOW: 'outline',\n NORMAL: 'secondary',\n HIGH: 'default',\n URGENT: 'destructive',\n};\n\nexport function ShiftStatusBadge({ status }: { status: ShiftStatus }) {\n return <Badge variant={SHIFT_VARIANT[status] ?? 'outline'}>{formatEnumLabel(status)}</Badge>;\n}\n\nexport function DispatchStatusBadge({ status }: { status: DispatchStatus }) {\n return <Badge variant={DISPATCH_VARIANT[status] ?? 'outline'}>{formatEnumLabel(status)}</Badge>;\n}\n\nexport function DispatchPriorityBadge({ priority }: { priority: DispatchPriority }) {\n return (\n <Badge variant={PRIORITY_VARIANT[priority] ?? 'outline'}>{formatEnumLabel(priority)}</Badge>\n );\n}\n"],"mappings":";;;;AAMA,IAAM,IAAmD;CACvD,WAAW;CACX,aAAa;CACb,WAAW;CACX,WAAW;CACX,QAAQ;CACT,EAEK,IAAyD;CAC7D,MAAM;CACN,UAAU;CACV,UAAU;CACV,SAAS;CACT,WAAW;CACX,WAAW;CACZ,EAEK,IAA2D;CAC/D,KAAK;CACL,QAAQ;CACR,MAAM;CACN,QAAQ;CACT;AAED,SAAgB,EAAiB,EAAE,aAAmC;AACpE,QAAO,kBAAC,GAAD;EAAO,SAAS,EAAc,MAAW;YAAY,EAAgB,EAAO;EAAS,CAAA;;AAG9F,SAAgB,EAAoB,EAAE,aAAsC;AAC1E,QAAO,kBAAC,GAAD;EAAO,SAAS,EAAiB,MAAW;YAAY,EAAgB,EAAO;EAAS,CAAA;;AAGjG,SAAgB,EAAsB,EAAE,eAA4C;AAClF,QACE,kBAAC,GAAD;EAAO,SAAS,EAAiB,MAAa;YAAY,EAAgB,EAAS;EAAS,CAAA"}
@@ -0,0 +1,12 @@
1
+ import { CrewDispatch, DispatchStatus } from '../../lib/fieldOps';
2
+
3
+ interface MyDispatchItemProps {
4
+ dispatch: CrewDispatch;
5
+ focused: boolean;
6
+ busy: boolean;
7
+ onAdvance: (dispatch: CrewDispatch, next: DispatchStatus) => void;
8
+ }
9
+ /** One of the worker's own work orders with the moves they may make (BOFF-4205). */
10
+ export declare function MyDispatchItem({ dispatch, focused, busy, onAdvance }: MyDispatchItemProps): import("react").JSX.Element;
11
+ export {};
12
+ //# sourceMappingURL=MyDispatchItem.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MyDispatchItem.d.ts","sourceRoot":"","sources":["../../../../src/crewfoundry/components/field/MyDispatchItem.tsx"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,cAAc,EAGpB,MAAM,oBAAoB,CAAC;AAI5B,UAAU,mBAAmB;IAC3B,QAAQ,EAAE,YAAY,CAAC;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,OAAO,CAAC;IACd,SAAS,EAAE,CAAC,QAAQ,EAAE,YAAY,EAAE,IAAI,EAAE,cAAc,KAAK,IAAI,CAAC;CACnE;AAED,oFAAoF;AACpF,wBAAgB,cAAc,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,mBAAmB,+BAqCzF"}
@@ -0,0 +1,46 @@
1
+ import { DispatchPriorityBadge as e, DispatchStatusBadge as t } from "./FieldBadges.js";
2
+ import { STATUS_ACTION_LABEL as n, WORKER_NEXT_STATUS as r } from "../../lib/fieldOps.js";
3
+ import { formatWhen as i } from "./fieldFormat.js";
4
+ import { jsx as a, jsxs as o } from "react/jsx-runtime";
5
+ import { Button as s } from "@burdenoff/fe-libs/ui";
6
+ //#region src/crewfoundry/components/field/MyDispatchItem.tsx
7
+ function c({ dispatch: c, focused: l, busy: u, onAdvance: d }) {
8
+ return /* @__PURE__ */ o("li", {
9
+ "data-focused": l ? "true" : void 0,
10
+ className: `space-y-2 rounded-[var(--radius-card)] border bg-bg-surface p-4 ${l ? "border-border-strong" : "border-border-subtle"}`,
11
+ children: [
12
+ /* @__PURE__ */ o("div", {
13
+ className: "flex flex-wrap items-center justify-between gap-2",
14
+ children: [/* @__PURE__ */ a("p", {
15
+ className: "font-medium text-text-primary",
16
+ children: c.title
17
+ }), /* @__PURE__ */ o("div", {
18
+ className: "flex gap-1.5",
19
+ children: [/* @__PURE__ */ a(e, { priority: c.priority }), /* @__PURE__ */ a(t, { status: c.status })]
20
+ })]
21
+ }),
22
+ c.description ? /* @__PURE__ */ a("p", {
23
+ className: "text-sm text-text-secondary",
24
+ children: c.description
25
+ }) : null,
26
+ /* @__PURE__ */ o("p", {
27
+ className: "text-xs text-text-muted",
28
+ children: [[c.siteName, c.siteAddress].filter(Boolean).join(" · ") || "No site given", c.dueAt ? ` · due ${i(c.dueAt)}` : ""]
29
+ }),
30
+ /* @__PURE__ */ a("div", {
31
+ className: "flex flex-wrap gap-2",
32
+ children: r[c.status].map((e) => /* @__PURE__ */ a(s, {
33
+ size: "sm",
34
+ variant: e === "COMPLETED" ? "default" : "outline",
35
+ disabled: u,
36
+ onClick: () => d(c, e),
37
+ children: n[e]
38
+ }, e))
39
+ })
40
+ ]
41
+ });
42
+ }
43
+ //#endregion
44
+ export { c as MyDispatchItem };
45
+
46
+ //# sourceMappingURL=MyDispatchItem.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MyDispatchItem.js","names":[],"sources":["../../../../src/crewfoundry/components/field/MyDispatchItem.tsx"],"sourcesContent":["import { Button } from '@burdenoff/fe-libs/ui';\nimport {\n type CrewDispatch,\n type DispatchStatus,\n STATUS_ACTION_LABEL,\n WORKER_NEXT_STATUS,\n} from '../../lib/fieldOps';\nimport { DispatchPriorityBadge, DispatchStatusBadge } from './FieldBadges';\nimport { formatWhen } from './fieldFormat';\n\ninterface MyDispatchItemProps {\n dispatch: CrewDispatch;\n focused: boolean;\n busy: boolean;\n onAdvance: (dispatch: CrewDispatch, next: DispatchStatus) => void;\n}\n\n/** One of the worker's own work orders with the moves they may make (BOFF-4205). */\nexport function MyDispatchItem({ dispatch, focused, busy, onAdvance }: MyDispatchItemProps) {\n return (\n <li\n data-focused={focused ? 'true' : undefined}\n className={`space-y-2 rounded-[var(--radius-card)] border bg-bg-surface p-4 ${\n focused ? 'border-border-strong' : 'border-border-subtle'\n }`}\n >\n <div className=\"flex flex-wrap items-center justify-between gap-2\">\n <p className=\"font-medium text-text-primary\">{dispatch.title}</p>\n <div className=\"flex gap-1.5\">\n <DispatchPriorityBadge priority={dispatch.priority} />\n <DispatchStatusBadge status={dispatch.status} />\n </div>\n </div>\n {dispatch.description ? (\n <p className=\"text-sm text-text-secondary\">{dispatch.description}</p>\n ) : null}\n <p className=\"text-xs text-text-muted\">\n {[dispatch.siteName, dispatch.siteAddress].filter(Boolean).join(' · ') || 'No site given'}\n {dispatch.dueAt ? ` · due ${formatWhen(dispatch.dueAt)}` : ''}\n </p>\n <div className=\"flex flex-wrap gap-2\">\n {WORKER_NEXT_STATUS[dispatch.status].map((next) => (\n <Button\n key={next}\n size=\"sm\"\n variant={next === 'COMPLETED' ? 'default' : 'outline'}\n disabled={busy}\n onClick={() => onAdvance(dispatch, next)}\n >\n {STATUS_ACTION_LABEL[next]}\n </Button>\n ))}\n </div>\n </li>\n );\n}\n"],"mappings":";;;;;;AAkBA,SAAgB,EAAe,EAAE,aAAU,YAAS,SAAM,gBAAkC;AAC1F,QACE,kBAAC,MAAD;EACE,gBAAc,IAAU,SAAS,KAAA;EACjC,WAAW,mEACT,IAAU,yBAAyB;YAHvC;GAME,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,KAAD;KAAG,WAAU;eAAiC,EAAS;KAAU,CAAA,EACjE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD,EAAuB,UAAU,EAAS,UAAY,CAAA,EACtD,kBAAC,GAAD,EAAqB,QAAQ,EAAS,QAAU,CAAA,CAC5C;OACF;;GACL,EAAS,cACR,kBAAC,KAAD;IAAG,WAAU;cAA+B,EAAS;IAAgB,CAAA,GACnE;GACJ,kBAAC,KAAD;IAAG,WAAU;cAAb,CACG,CAAC,EAAS,UAAU,EAAS,YAAY,CAAC,OAAO,QAAQ,CAAC,KAAK,MAAM,IAAI,iBACzE,EAAS,QAAQ,UAAU,EAAW,EAAS,MAAM,KAAK,GACzD;;GACJ,kBAAC,OAAD;IAAK,WAAU;cACZ,EAAmB,EAAS,QAAQ,KAAK,MACxC,kBAAC,GAAD;KAEE,MAAK;KACL,SAAS,MAAS,cAAc,YAAY;KAC5C,UAAU;KACV,eAAe,EAAU,GAAU,EAAK;eAEvC,EAAoB;KACd,EAPF,EAOE,CACT;IACE,CAAA;GACH"}
@@ -0,0 +1,14 @@
1
+ import { CrewShift } from '../../lib/fieldOps';
2
+
3
+ interface MyShiftItemProps {
4
+ shift: CrewShift;
5
+ now: Date;
6
+ focused: boolean;
7
+ busy: boolean;
8
+ onCheckIn: (shift: CrewShift) => void;
9
+ onCheckOut: (shift: CrewShift) => void;
10
+ }
11
+ /** One of the worker's own shifts with its check-in / check-out action (BOFF-4205). */
12
+ export declare function MyShiftItem({ shift, now, focused, busy, onCheckIn, onCheckOut, }: MyShiftItemProps): import("react").JSX.Element;
13
+ export {};
14
+ //# sourceMappingURL=MyShiftItem.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MyShiftItem.d.ts","sourceRoot":"","sources":["../../../../src/crewfoundry/components/field/MyShiftItem.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,SAAS,EAAuC,MAAM,oBAAoB,CAAC;AAIzF,UAAU,gBAAgB;IACxB,KAAK,EAAE,SAAS,CAAC;IACjB,GAAG,EAAE,IAAI,CAAC;IACV,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,OAAO,CAAC;IACd,SAAS,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,CAAC;IACtC,UAAU,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,CAAC;CACxC;AAED,uFAAuF;AACvF,wBAAgB,WAAW,CAAC,EAC1B,KAAK,EACL,GAAG,EACH,OAAO,EACP,IAAI,EACJ,SAAS,EACT,UAAU,GACX,EAAE,gBAAgB,+BA0ElB"}
@@ -0,0 +1,84 @@
1
+ import { ShiftStatusBadge as e } from "./FieldBadges.js";
2
+ import { checkInAvailability as t, formatDistance as n } from "../../lib/fieldOps.js";
3
+ import { formatTime as r, formatWhen as i, mapsLink as a } from "./fieldFormat.js";
4
+ import { Clock as o, LocateFixed as s, LogIn as c, LogOut as l, MapPin as u, Navigation as d } from "lucide-react";
5
+ import { jsx as f, jsxs as p } from "react/jsx-runtime";
6
+ import { Button as m } from "@burdenoff/fe-libs/ui";
7
+ //#region src/crewfoundry/components/field/MyShiftItem.tsx
8
+ function h({ shift: h, now: g, focused: _, busy: v, onCheckIn: y, onCheckOut: b }) {
9
+ let x = t(h, g), S = a(h.siteLatitude, h.siteLongitude, h.siteAddress);
10
+ return /* @__PURE__ */ p("li", {
11
+ "data-focused": _ ? "true" : void 0,
12
+ className: `space-y-3 rounded-[var(--radius-card)] border bg-bg-surface p-4 ${_ ? "border-border-strong" : "border-border-subtle"}`,
13
+ children: [
14
+ /* @__PURE__ */ p("div", {
15
+ className: "flex flex-wrap items-center justify-between gap-2",
16
+ children: [/* @__PURE__ */ f("p", {
17
+ className: "font-medium text-text-primary",
18
+ children: h.title
19
+ }), /* @__PURE__ */ f(e, { status: h.status })]
20
+ }),
21
+ /* @__PURE__ */ p("div", {
22
+ className: "space-y-1 text-sm text-text-secondary",
23
+ children: [
24
+ /* @__PURE__ */ p("p", {
25
+ className: "flex items-center gap-1.5",
26
+ children: [
27
+ /* @__PURE__ */ f(o, { className: "h-4 w-4" }),
28
+ i(h.startsAt),
29
+ " – ",
30
+ r(h.endsAt)
31
+ ]
32
+ }),
33
+ h.siteName || h.siteAddress ? /* @__PURE__ */ p("p", {
34
+ className: "flex flex-wrap items-center gap-1.5",
35
+ children: [
36
+ /* @__PURE__ */ f(u, { className: "h-4 w-4" }),
37
+ [h.siteName, h.siteAddress].filter(Boolean).join(" · "),
38
+ S ? /* @__PURE__ */ p("a", {
39
+ href: S,
40
+ target: "_blank",
41
+ rel: "noreferrer",
42
+ className: "inline-flex items-center gap-0.5 text-text-link underline",
43
+ children: [/* @__PURE__ */ f(d, { className: "h-3.5 w-3.5" }), "Directions"]
44
+ }) : null
45
+ ]
46
+ }) : null,
47
+ h.checkedInAt ? /* @__PURE__ */ p("p", {
48
+ className: "text-xs text-text-muted",
49
+ children: [
50
+ "Checked in at ",
51
+ r(h.checkedInAt),
52
+ h.checkInDistanceMeters === null ? "" : ` · ${n(h.checkInDistanceMeters)} from the site`
53
+ ]
54
+ }) : null,
55
+ h.notes ? /* @__PURE__ */ f("p", {
56
+ className: "text-xs text-text-muted",
57
+ children: h.notes
58
+ }) : null
59
+ ]
60
+ }),
61
+ x.kind === "check-in" ? /* @__PURE__ */ p(m, {
62
+ className: "w-full sm:w-auto",
63
+ disabled: v,
64
+ onClick: () => y(h),
65
+ children: [v ? /* @__PURE__ */ f(s, { className: "mr-1 h-4 w-4 animate-pulse" }) : /* @__PURE__ */ f(c, { className: "mr-1 h-4 w-4" }), "Check in here"]
66
+ }) : null,
67
+ x.kind === "check-out" ? /* @__PURE__ */ p(m, {
68
+ className: "w-full sm:w-auto",
69
+ variant: "outline",
70
+ disabled: v,
71
+ onClick: () => b(h),
72
+ children: [/* @__PURE__ */ f(l, { className: "mr-1 h-4 w-4" }), "Check out"]
73
+ }) : null,
74
+ x.kind === "too-early" ? /* @__PURE__ */ p("p", {
75
+ className: "text-xs text-text-muted",
76
+ children: ["Check-in opens at ", r(x.opensAt)]
77
+ }) : null
78
+ ]
79
+ });
80
+ }
81
+ //#endregion
82
+ export { h as MyShiftItem };
83
+
84
+ //# sourceMappingURL=MyShiftItem.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MyShiftItem.js","names":[],"sources":["../../../../src/crewfoundry/components/field/MyShiftItem.tsx"],"sourcesContent":["import { Button } from '@burdenoff/fe-libs/ui';\nimport { Clock, LocateFixed, LogIn, LogOut, MapPin, Navigation } from 'lucide-react';\nimport { type CrewShift, checkInAvailability, formatDistance } from '../../lib/fieldOps';\nimport { ShiftStatusBadge } from './FieldBadges';\nimport { formatTime, formatWhen, mapsLink } from './fieldFormat';\n\ninterface MyShiftItemProps {\n shift: CrewShift;\n now: Date;\n focused: boolean;\n busy: boolean;\n onCheckIn: (shift: CrewShift) => void;\n onCheckOut: (shift: CrewShift) => void;\n}\n\n/** One of the worker's own shifts with its check-in / check-out action (BOFF-4205). */\nexport function MyShiftItem({\n shift,\n now,\n focused,\n busy,\n onCheckIn,\n onCheckOut,\n}: MyShiftItemProps) {\n const availability = checkInAvailability(shift, now);\n const link = mapsLink(shift.siteLatitude, shift.siteLongitude, shift.siteAddress);\n return (\n <li\n data-focused={focused ? 'true' : undefined}\n className={`space-y-3 rounded-[var(--radius-card)] border bg-bg-surface p-4 ${\n focused ? 'border-border-strong' : 'border-border-subtle'\n }`}\n >\n <div className=\"flex flex-wrap items-center justify-between gap-2\">\n <p className=\"font-medium text-text-primary\">{shift.title}</p>\n <ShiftStatusBadge status={shift.status} />\n </div>\n <div className=\"space-y-1 text-sm text-text-secondary\">\n <p className=\"flex items-center gap-1.5\">\n <Clock className=\"h-4 w-4\" />\n {formatWhen(shift.startsAt)} – {formatTime(shift.endsAt)}\n </p>\n {shift.siteName || shift.siteAddress ? (\n <p className=\"flex flex-wrap items-center gap-1.5\">\n <MapPin className=\"h-4 w-4\" />\n {[shift.siteName, shift.siteAddress].filter(Boolean).join(' · ')}\n {link ? (\n <a\n href={link}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"inline-flex items-center gap-0.5 text-text-link underline\"\n >\n <Navigation className=\"h-3.5 w-3.5\" />\n Directions\n </a>\n ) : null}\n </p>\n ) : null}\n {shift.checkedInAt ? (\n <p className=\"text-xs text-text-muted\">\n Checked in at {formatTime(shift.checkedInAt)}\n {shift.checkInDistanceMeters !== null\n ? ` · ${formatDistance(shift.checkInDistanceMeters)} from the site`\n : ''}\n </p>\n ) : null}\n {shift.notes ? <p className=\"text-xs text-text-muted\">{shift.notes}</p> : null}\n </div>\n {availability.kind === 'check-in' ? (\n <Button className=\"w-full sm:w-auto\" disabled={busy} onClick={() => onCheckIn(shift)}>\n {busy ? (\n <LocateFixed className=\"mr-1 h-4 w-4 animate-pulse\" />\n ) : (\n <LogIn className=\"mr-1 h-4 w-4\" />\n )}\n Check in here\n </Button>\n ) : null}\n {availability.kind === 'check-out' ? (\n <Button\n className=\"w-full sm:w-auto\"\n variant=\"outline\"\n disabled={busy}\n onClick={() => onCheckOut(shift)}\n >\n <LogOut className=\"mr-1 h-4 w-4\" />\n Check out\n </Button>\n ) : null}\n {availability.kind === 'too-early' ? (\n <p className=\"text-xs text-text-muted\">\n Check-in opens at {formatTime(availability.opensAt)}\n </p>\n ) : null}\n </li>\n );\n}\n"],"mappings":";;;;;;;AAgBA,SAAgB,EAAY,EAC1B,UACA,QACA,YACA,SACA,cACA,iBACmB;CACnB,IAAM,IAAe,EAAoB,GAAO,EAAI,EAC9C,IAAO,EAAS,EAAM,cAAc,EAAM,eAAe,EAAM,YAAY;AACjF,QACE,kBAAC,MAAD;EACE,gBAAc,IAAU,SAAS,KAAA;EACjC,WAAW,mEACT,IAAU,yBAAyB;YAHvC;GAME,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,KAAD;KAAG,WAAU;eAAiC,EAAM;KAAU,CAAA,EAC9D,kBAAC,GAAD,EAAkB,QAAQ,EAAM,QAAU,CAAA,CACtC;;GACN,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,KAAD;MAAG,WAAU;gBAAb;OACE,kBAAC,GAAD,EAAO,WAAU,WAAY,CAAA;OAC5B,EAAW,EAAM,SAAS;OAAC;OAAI,EAAW,EAAM,OAAO;OACtD;;KACH,EAAM,YAAY,EAAM,cACvB,kBAAC,KAAD;MAAG,WAAU;gBAAb;OACE,kBAAC,GAAD,EAAQ,WAAU,WAAY,CAAA;OAC7B,CAAC,EAAM,UAAU,EAAM,YAAY,CAAC,OAAO,QAAQ,CAAC,KAAK,MAAM;OAC/D,IACC,kBAAC,KAAD;QACE,MAAM;QACN,QAAO;QACP,KAAI;QACJ,WAAU;kBAJZ,CAME,kBAAC,GAAD,EAAY,WAAU,eAAgB,CAAA,EAAA,aAEpC;YACF;OACF;UACF;KACH,EAAM,cACL,kBAAC,KAAD;MAAG,WAAU;gBAAb;OAAuC;OACtB,EAAW,EAAM,YAAY;OAC3C,EAAM,0BAA0B,OAE7B,KADA,MAAM,EAAe,EAAM,sBAAsB,CAAC;OAEpD;UACF;KACH,EAAM,QAAQ,kBAAC,KAAD;MAAG,WAAU;gBAA2B,EAAM;MAAU,CAAA,GAAG;KACtE;;GACL,EAAa,SAAS,aACrB,kBAAC,GAAD;IAAQ,WAAU;IAAmB,UAAU;IAAM,eAAe,EAAU,EAAM;cAApF,CACG,IACC,kBAAC,GAAD,EAAa,WAAU,8BAA+B,CAAA,GAEtD,kBAAC,GAAD,EAAO,WAAU,gBAAiB,CAAA,EAClC,gBAEK;QACP;GACH,EAAa,SAAS,cACrB,kBAAC,GAAD;IACE,WAAU;IACV,SAAQ;IACR,UAAU;IACV,eAAe,EAAW,EAAM;cAJlC,CAME,kBAAC,GAAD,EAAQ,WAAU,gBAAiB,CAAA,EAAA,YAE5B;QACP;GACH,EAAa,SAAS,cACrB,kBAAC,KAAD;IAAG,WAAU;cAAb,CAAuC,sBAClB,EAAW,EAAa,QAAQ,CACjD;QACF;GACD"}
@@ -0,0 +1,12 @@
1
+ import { CrewShift } from '../../lib/fieldOps';
2
+
3
+ interface ShiftsCardProps {
4
+ shifts: CrewShift[];
5
+ onRemind: (shift: CrewShift) => void;
6
+ onCancel: (shift: CrewShift) => void;
7
+ onRemove: (shift: CrewShift) => void;
8
+ }
9
+ /** Dispatcher list of shifts with reminder / cancel / remove actions (BOFF-4205). */
10
+ export declare function ShiftsCard({ shifts, onRemind, onCancel, onRemove }: ShiftsCardProps): import("react").JSX.Element;
11
+ export {};
12
+ //# sourceMappingURL=ShiftsCard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ShiftsCard.d.ts","sourceRoot":"","sources":["../../../../src/crewfoundry/components/field/ShiftsCard.tsx"],"names":[],"mappings":"AAUA,OAAO,EAAE,KAAK,SAAS,EAAkB,MAAM,oBAAoB,CAAC;AAIpE,UAAU,eAAe;IACvB,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,QAAQ,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,CAAC;IACrC,QAAQ,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,CAAC;IACrC,QAAQ,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,CAAC;CACtC;AAiBD,qFAAqF;AACrF,wBAAgB,UAAU,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,eAAe,+BA+DnF"}
@@ -0,0 +1,84 @@
1
+ import { ShiftStatusBadge as e } from "./FieldBadges.js";
2
+ import { formatDistance as t } from "../../lib/fieldOps.js";
3
+ import { formatTime as n, formatWhen as r } from "./fieldFormat.js";
4
+ import { BellRing as i, Trash2 as a, XCircle as o } from "lucide-react";
5
+ import { jsx as s, jsxs as c } from "react/jsx-runtime";
6
+ import { Button as l, Card as u, CardContent as d, CardDescription as f, CardHeader as p, CardTitle as m, IllustratedEmptyState as h } from "@burdenoff/fe-libs/ui";
7
+ //#region src/crewfoundry/components/field/ShiftsCard.tsx
8
+ function g(e) {
9
+ let r = [e.siteName ?? "No site"];
10
+ return e.siteLatitude !== null && r.push(`${e.geofenceRadiusMeters} m check-in radius`), e.checkedInAt && r.push(`checked in ${n(e.checkedInAt)} (${t(e.checkInDistanceMeters)} from site)`), e.checkedOutAt && r.push(`out ${n(e.checkedOutAt)}`), e.timeEntry && e.status === "COMPLETED" && r.push(`${e.timeEntry.totalHours} h`), e.assigneeUserId || r.push("no worker login linked"), r.join(" · ");
11
+ }
12
+ function _({ shifts: t, onRemind: _, onCancel: v, onRemove: y }) {
13
+ return /* @__PURE__ */ c(u, {
14
+ "data-testid": "field-shifts",
15
+ children: [/* @__PURE__ */ c(p, { children: [/* @__PURE__ */ s(m, {
16
+ className: "text-base",
17
+ children: "Shifts"
18
+ }), /* @__PURE__ */ s(f, { children: "The past week through the next four weeks." })] }), /* @__PURE__ */ s(d, { children: t.length > 0 ? /* @__PURE__ */ s("ul", {
19
+ className: "space-y-2",
20
+ "aria-label": "Shifts",
21
+ children: t.map((t) => /* @__PURE__ */ c("li", {
22
+ className: "flex flex-col gap-3 rounded-[var(--radius-card)] border border-border-subtle bg-bg-surface p-3 md:flex-row md:items-center md:justify-between",
23
+ children: [/* @__PURE__ */ c("div", {
24
+ className: "min-w-0 space-y-1",
25
+ children: [
26
+ /* @__PURE__ */ c("div", {
27
+ className: "flex flex-wrap items-center gap-2",
28
+ children: [/* @__PURE__ */ s("p", {
29
+ className: "font-medium text-text-primary",
30
+ children: t.title
31
+ }), /* @__PURE__ */ s(e, { status: t.status })]
32
+ }),
33
+ /* @__PURE__ */ c("p", {
34
+ className: "text-sm text-text-secondary",
35
+ children: [
36
+ t.employeeName,
37
+ " · ",
38
+ r(t.startsAt),
39
+ " – ",
40
+ n(t.endsAt)
41
+ ]
42
+ }),
43
+ /* @__PURE__ */ s("p", {
44
+ className: "text-xs text-text-muted",
45
+ children: g(t)
46
+ })
47
+ ]
48
+ }), t.status === "SCHEDULED" ? /* @__PURE__ */ c("div", {
49
+ className: "flex flex-wrap gap-2",
50
+ children: [
51
+ /* @__PURE__ */ c(l, {
52
+ size: "sm",
53
+ variant: "outline",
54
+ disabled: !t.assigneeUserId,
55
+ onClick: () => _(t),
56
+ children: [/* @__PURE__ */ s(i, { className: "mr-1 h-3.5 w-3.5" }), "Remind"]
57
+ }),
58
+ /* @__PURE__ */ c(l, {
59
+ size: "sm",
60
+ variant: "outline",
61
+ onClick: () => v(t),
62
+ children: [/* @__PURE__ */ s(o, { className: "mr-1 h-3.5 w-3.5" }), "Cancel"]
63
+ }),
64
+ /* @__PURE__ */ s(l, {
65
+ size: "sm",
66
+ variant: "ghost",
67
+ "aria-label": `Remove ${t.title}`,
68
+ onClick: () => y(t),
69
+ children: /* @__PURE__ */ s(a, { className: "h-3.5 w-3.5 text-status-error-fg" })
70
+ })
71
+ ]
72
+ }) : null]
73
+ }, t.id))
74
+ }) : /* @__PURE__ */ s(h, {
75
+ illustration: "empty-data",
76
+ title: "No shifts scheduled",
77
+ description: "Schedule a shift to give a worker a site, a time window and a check-in geofence."
78
+ }) })]
79
+ });
80
+ }
81
+ //#endregion
82
+ export { _ as ShiftsCard };
83
+
84
+ //# sourceMappingURL=ShiftsCard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ShiftsCard.js","names":[],"sources":["../../../../src/crewfoundry/components/field/ShiftsCard.tsx"],"sourcesContent":["import {\n Button,\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n IllustratedEmptyState,\n} from '@burdenoff/fe-libs/ui';\nimport { BellRing, Trash2, XCircle } from 'lucide-react';\nimport { type CrewShift, formatDistance } from '../../lib/fieldOps';\nimport { ShiftStatusBadge } from './FieldBadges';\nimport { formatTime, formatWhen } from './fieldFormat';\n\ninterface ShiftsCardProps {\n shifts: CrewShift[];\n onRemind: (shift: CrewShift) => void;\n onCancel: (shift: CrewShift) => void;\n onRemove: (shift: CrewShift) => void;\n}\n\nfunction shiftDetail(shift: CrewShift): string {\n const parts = [shift.siteName ?? 'No site'];\n if (shift.siteLatitude !== null) parts.push(`${shift.geofenceRadiusMeters} m check-in radius`);\n if (shift.checkedInAt) {\n parts.push(\n `checked in ${formatTime(shift.checkedInAt)} (${formatDistance(shift.checkInDistanceMeters)} from site)`\n );\n }\n if (shift.checkedOutAt) parts.push(`out ${formatTime(shift.checkedOutAt)}`);\n if (shift.timeEntry && shift.status === 'COMPLETED')\n parts.push(`${shift.timeEntry.totalHours} h`);\n if (!shift.assigneeUserId) parts.push('no worker login linked');\n return parts.join(' · ');\n}\n\n/** Dispatcher list of shifts with reminder / cancel / remove actions (BOFF-4205). */\nexport function ShiftsCard({ shifts, onRemind, onCancel, onRemove }: ShiftsCardProps) {\n return (\n <Card data-testid=\"field-shifts\">\n <CardHeader>\n <CardTitle className=\"text-base\">Shifts</CardTitle>\n <CardDescription>The past week through the next four weeks.</CardDescription>\n </CardHeader>\n <CardContent>\n {shifts.length > 0 ? (\n <ul className=\"space-y-2\" aria-label=\"Shifts\">\n {shifts.map((shift) => (\n <li\n key={shift.id}\n className=\"flex flex-col gap-3 rounded-[var(--radius-card)] border border-border-subtle bg-bg-surface p-3 md:flex-row md:items-center md:justify-between\"\n >\n <div className=\"min-w-0 space-y-1\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <p className=\"font-medium text-text-primary\">{shift.title}</p>\n <ShiftStatusBadge status={shift.status} />\n </div>\n <p className=\"text-sm text-text-secondary\">\n {shift.employeeName} · {formatWhen(shift.startsAt)} – {formatTime(shift.endsAt)}\n </p>\n <p className=\"text-xs text-text-muted\">{shiftDetail(shift)}</p>\n </div>\n {shift.status === 'SCHEDULED' ? (\n <div className=\"flex flex-wrap gap-2\">\n <Button\n size=\"sm\"\n variant=\"outline\"\n disabled={!shift.assigneeUserId}\n onClick={() => onRemind(shift)}\n >\n <BellRing className=\"mr-1 h-3.5 w-3.5\" />\n Remind\n </Button>\n <Button size=\"sm\" variant=\"outline\" onClick={() => onCancel(shift)}>\n <XCircle className=\"mr-1 h-3.5 w-3.5\" />\n Cancel\n </Button>\n <Button\n size=\"sm\"\n variant=\"ghost\"\n aria-label={`Remove ${shift.title}`}\n onClick={() => onRemove(shift)}\n >\n <Trash2 className=\"h-3.5 w-3.5 text-status-error-fg\" />\n </Button>\n </div>\n ) : null}\n </li>\n ))}\n </ul>\n ) : (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"No shifts scheduled\"\n description=\"Schedule a shift to give a worker a site, a time window and a check-in geofence.\"\n />\n )}\n </CardContent>\n </Card>\n );\n}\n"],"mappings":";;;;;;;AAqBA,SAAS,EAAY,GAA0B;CAC7C,IAAM,IAAQ,CAAC,EAAM,YAAY,UAAU;AAW3C,QAVI,EAAM,iBAAiB,QAAM,EAAM,KAAK,GAAG,EAAM,qBAAqB,oBAAoB,EAC1F,EAAM,eACR,EAAM,KACJ,cAAc,EAAW,EAAM,YAAY,CAAC,IAAI,EAAe,EAAM,sBAAsB,CAAC,aAC7F,EAEC,EAAM,gBAAc,EAAM,KAAK,OAAO,EAAW,EAAM,aAAa,GAAG,EACvE,EAAM,aAAa,EAAM,WAAW,eACtC,EAAM,KAAK,GAAG,EAAM,UAAU,WAAW,IAAI,EAC1C,EAAM,kBAAgB,EAAM,KAAK,yBAAyB,EACxD,EAAM,KAAK,MAAM;;AAI1B,SAAgB,EAAW,EAAE,WAAQ,aAAU,aAAU,eAA6B;AACpF,QACE,kBAAC,GAAD;EAAM,eAAY;YAAlB,CACE,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD;GAAW,WAAU;aAAY;GAAkB,CAAA,EACnD,kBAAC,GAAD,EAAA,UAAiB,8CAA4D,CAAA,CAClE,EAAA,CAAA,EACb,kBAAC,GAAD,EAAA,UACG,EAAO,SAAS,IACf,kBAAC,MAAD;GAAI,WAAU;GAAY,cAAW;aAClC,EAAO,KAAK,MACX,kBAAC,MAAD;IAEE,WAAU;cAFZ,CAIE,kBAAC,OAAD;KAAK,WAAU;eAAf;MACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,KAAD;QAAG,WAAU;kBAAiC,EAAM;QAAU,CAAA,EAC9D,kBAAC,GAAD,EAAkB,QAAQ,EAAM,QAAU,CAAA,CACtC;;MACN,kBAAC,KAAD;OAAG,WAAU;iBAAb;QACG,EAAM;QAAa;QAAI,EAAW,EAAM,SAAS;QAAC;QAAI,EAAW,EAAM,OAAO;QAC7E;;MACJ,kBAAC,KAAD;OAAG,WAAU;iBAA2B,EAAY,EAAM;OAAK,CAAA;MAC3D;QACL,EAAM,WAAW,cAChB,kBAAC,OAAD;KAAK,WAAU;eAAf;MACE,kBAAC,GAAD;OACE,MAAK;OACL,SAAQ;OACR,UAAU,CAAC,EAAM;OACjB,eAAe,EAAS,EAAM;iBAJhC,CAME,kBAAC,GAAD,EAAU,WAAU,oBAAqB,CAAA,EAAA,SAElC;;MACT,kBAAC,GAAD;OAAQ,MAAK;OAAK,SAAQ;OAAU,eAAe,EAAS,EAAM;iBAAlE,CACE,kBAAC,GAAD,EAAS,WAAU,oBAAqB,CAAA,EAAA,SAEjC;;MACT,kBAAC,GAAD;OACE,MAAK;OACL,SAAQ;OACR,cAAY,UAAU,EAAM;OAC5B,eAAe,EAAS,EAAM;iBAE9B,kBAAC,GAAD,EAAQ,WAAU,oCAAqC,CAAA;OAChD,CAAA;MACL;SACJ,KACD;MAtCE,EAAM,GAsCR,CACL;GACC,CAAA,GAEL,kBAAC,GAAD;GACE,cAAa;GACb,OAAM;GACN,aAAY;GACZ,CAAA,EAEQ,CAAA,CACT"}
@@ -0,0 +1,8 @@
1
+ import { CrewShift } from '../../lib/fieldOps';
2
+
3
+ export declare const formatWhen: (iso: string | null | undefined) => string;
4
+ export declare const formatTime: (iso: string | Date) => string;
5
+ export declare const shiftOptionLabel: (shift: CrewShift) => string;
6
+ /** Directions link: exact coordinates when the site has them, else the address. */
7
+ export declare function mapsLink(latitude: number | null, longitude: number | null, address: string | null): string | null;
8
+ //# sourceMappingURL=fieldFormat.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fieldFormat.d.ts","sourceRoot":"","sources":["../../../../src/crewfoundry/components/field/fieldFormat.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAEpD,eAAO,MAAM,UAAU,GAAI,KAAK,MAAM,GAAG,IAAI,GAAG,SAAS,KAAG,MACsC,CAAC;AAEnG,eAAO,MAAM,UAAU,GAAI,KAAK,MAAM,GAAG,IAAI,KAAG,MACqC,CAAC;AAEtF,eAAO,MAAM,gBAAgB,GAAI,OAAO,SAAS,KAAG,MACsB,CAAC;AAE3E,mFAAmF;AACnF,wBAAgB,QAAQ,CACtB,QAAQ,EAAE,MAAM,GAAG,IAAI,EACvB,SAAS,EAAE,MAAM,GAAG,IAAI,EACxB,OAAO,EAAE,MAAM,GAAG,IAAI,GACrB,MAAM,GAAG,IAAI,CAOf"}
@@ -0,0 +1,15 @@
1
+ //#region src/crewfoundry/components/field/fieldFormat.ts
2
+ var e = (e) => e ? new Date(e).toLocaleString(void 0, {
3
+ dateStyle: "medium",
4
+ timeStyle: "short"
5
+ }) : "—", t = (e) => new Date(e).toLocaleTimeString(void 0, {
6
+ hour: "2-digit",
7
+ minute: "2-digit"
8
+ }), n = (t) => `${t.employeeName} · ${t.title} · ${e(t.startsAt)}`;
9
+ function r(e, t, n) {
10
+ return e !== null && t !== null ? `https://www.google.com/maps/search/?api=1&query=${e},${t}` : n ? `https://www.google.com/maps/search/?api=1&query=${encodeURIComponent(n)}` : null;
11
+ }
12
+ //#endregion
13
+ export { t as formatTime, e as formatWhen, r as mapsLink, n as shiftOptionLabel };
14
+
15
+ //# sourceMappingURL=fieldFormat.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fieldFormat.js","names":[],"sources":["../../../../src/crewfoundry/components/field/fieldFormat.ts"],"sourcesContent":["import type { CrewShift } from '../../lib/fieldOps';\n\nexport const formatWhen = (iso: string | null | undefined): string =>\n iso ? new Date(iso).toLocaleString(undefined, { dateStyle: 'medium', timeStyle: 'short' }) : '—';\n\nexport const formatTime = (iso: string | Date): string =>\n new Date(iso).toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit' });\n\nexport const shiftOptionLabel = (shift: CrewShift): string =>\n `${shift.employeeName} · ${shift.title} · ${formatWhen(shift.startsAt)}`;\n\n/** Directions link: exact coordinates when the site has them, else the address. */\nexport function mapsLink(\n latitude: number | null,\n longitude: number | null,\n address: string | null\n): string | null {\n if (latitude !== null && longitude !== null) {\n return `https://www.google.com/maps/search/?api=1&query=${latitude},${longitude}`;\n }\n return address\n ? `https://www.google.com/maps/search/?api=1&query=${encodeURIComponent(address)}`\n : null;\n}\n"],"mappings":";AAEA,IAAa,KAAc,MACzB,IAAM,IAAI,KAAK,EAAI,CAAC,eAAe,KAAA,GAAW;CAAE,WAAW;CAAU,WAAW;CAAS,CAAC,GAAG,KAElF,KAAc,MACzB,IAAI,KAAK,EAAI,CAAC,mBAAmB,KAAA,GAAW;CAAE,MAAM;CAAW,QAAQ;CAAW,CAAC,EAExE,KAAoB,MAC/B,GAAG,EAAM,aAAa,KAAK,EAAM,MAAM,KAAK,EAAW,EAAM,SAAS;AAGxE,SAAgB,EACd,GACA,GACA,GACe;AAIf,QAHI,MAAa,QAAQ,MAAc,OAC9B,mDAAmD,EAAS,GAAG,MAEjE,IACH,mDAAmD,mBAAmB,EAAQ,KAC9E"}
@@ -0,0 +1,19 @@
1
+ import { FieldConfig, FieldOption, FormValues } from '../forms/FormModal';
2
+ import { CrewShift } from '../../lib/fieldOps';
3
+ import { DispatchInput, ShiftInput } from '../../store/fieldOpsStore';
4
+
5
+ /** Select value meaning "none" (FormModal selects cannot hold an empty value). */
6
+ export declare const NO_SELECTION = "none";
7
+ export declare function buildShiftFields(employees: FieldOption[], members: FieldOption[]): FieldConfig[];
8
+ export declare function buildDispatchFields(upcoming: CrewShift[]): FieldConfig[];
9
+ export declare function buildAssignFields(upcoming: CrewShift[]): FieldConfig[];
10
+ /** Optional site coordinates from the form: both or neither, as numbers. */
11
+ export declare function readSite(values: FormValues): {
12
+ siteLatitude?: number;
13
+ siteLongitude?: number;
14
+ } | string;
15
+ /** Map the schedule-shift form to the mutation input, or a validation message. */
16
+ export declare function toShiftInput(values: FormValues): ShiftInput | string;
17
+ /** Map the new-work-order form to the mutation input, or a validation message. */
18
+ export declare function toDispatchInput(values: FormValues): DispatchInput | string;
19
+ //# sourceMappingURL=fieldForms.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fieldForms.d.ts","sourceRoot":"","sources":["../../../../src/crewfoundry/components/field/fieldForms.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAE/E,OAAO,EACL,KAAK,SAAS,EAIf,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAI3E,kFAAkF;AAClF,eAAO,MAAM,YAAY,SAAS,CAAC;AAInC,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,WAAW,EAAE,EAAE,OAAO,EAAE,WAAW,EAAE,GAAG,WAAW,EAAE,CA2ChG;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,SAAS,EAAE,GAAG,WAAW,EAAE,CAgCxE;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,SAAS,EAAE,GAAG,WAAW,EAAE,CAUtE;AAED,4EAA4E;AAC5E,wBAAgB,QAAQ,CACtB,MAAM,EAAE,UAAU,GACjB;IAAE,YAAY,CAAC,EAAE,MAAM,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAQ5D;AAQD,kFAAkF;AAClF,wBAAgB,YAAY,CAAC,MAAM,EAAE,UAAU,GAAG,UAAU,GAAG,MAAM,CAsBpE;AAED,kFAAkF;AAClF,wBAAgB,eAAe,CAAC,MAAM,EAAE,UAAU,GAAG,aAAa,GAAG,MAAM,CAa1E"}
@@ -0,0 +1,223 @@
1
+ import { formatEnumLabel as e } from "../../utils/formatEnumLabel.js";
2
+ import { localInputToIso as t, parseCoordinate as n } from "../../lib/fieldOps.js";
3
+ import { shiftOptionLabel as r } from "./fieldFormat.js";
4
+ import { getNumber as i, getText as a } from "../forms/formValues.js";
5
+ //#region src/crewfoundry/components/field/fieldForms.ts
6
+ var o = "none", s = [
7
+ "LOW",
8
+ "NORMAL",
9
+ "HIGH",
10
+ "URGENT"
11
+ ];
12
+ function c(e, t) {
13
+ return [
14
+ {
15
+ name: "employeeId",
16
+ label: "Employee",
17
+ type: "select",
18
+ required: !0,
19
+ options: e
20
+ },
21
+ {
22
+ name: "assigneeUserId",
23
+ label: "Worker login",
24
+ type: "select",
25
+ required: !0,
26
+ options: [{
27
+ label: "No login linked (no check-in or push)",
28
+ value: o
29
+ }, ...t]
30
+ },
31
+ {
32
+ name: "title",
33
+ label: "Shift title",
34
+ type: "text",
35
+ required: !0,
36
+ placeholder: "Morning install crew"
37
+ },
38
+ {
39
+ name: "role",
40
+ label: "Role",
41
+ type: "text",
42
+ placeholder: "Lead technician"
43
+ },
44
+ {
45
+ name: "startsAt",
46
+ label: "Starts",
47
+ type: "datetime",
48
+ required: !0
49
+ },
50
+ {
51
+ name: "endsAt",
52
+ label: "Ends",
53
+ type: "datetime",
54
+ required: !0
55
+ },
56
+ {
57
+ name: "siteName",
58
+ label: "Site name",
59
+ type: "text",
60
+ placeholder: "Depot 4"
61
+ },
62
+ {
63
+ name: "siteAddress",
64
+ label: "Site address",
65
+ type: "text"
66
+ },
67
+ {
68
+ name: "siteLatitude",
69
+ label: "Site latitude",
70
+ type: "text",
71
+ placeholder: "13.0827"
72
+ },
73
+ {
74
+ name: "siteLongitude",
75
+ label: "Site longitude",
76
+ type: "text",
77
+ placeholder: "80.2707"
78
+ },
79
+ {
80
+ name: "geofenceRadiusMeters",
81
+ label: "Check-in radius (m)",
82
+ type: "number",
83
+ min: 25,
84
+ max: 5e3
85
+ },
86
+ {
87
+ name: "reminderMinutesBefore",
88
+ label: "Reminder (minutes before)",
89
+ type: "number",
90
+ min: 0,
91
+ max: 1440
92
+ },
93
+ {
94
+ name: "notes",
95
+ label: "Notes",
96
+ type: "textarea"
97
+ }
98
+ ];
99
+ }
100
+ function l(t) {
101
+ return [
102
+ {
103
+ name: "title",
104
+ label: "Work order",
105
+ type: "text",
106
+ required: !0,
107
+ placeholder: "Replace pump seal"
108
+ },
109
+ {
110
+ name: "priority",
111
+ label: "Priority",
112
+ type: "select",
113
+ required: !0,
114
+ options: s.map((t) => ({
115
+ label: e(t),
116
+ value: t
117
+ }))
118
+ },
119
+ {
120
+ name: "dueAt",
121
+ label: "Due",
122
+ type: "datetime"
123
+ },
124
+ {
125
+ name: "shiftId",
126
+ label: "Assign to shift",
127
+ type: "select",
128
+ options: [{
129
+ label: "Leave unassigned",
130
+ value: o
131
+ }, ...t.map((e) => ({
132
+ label: r(e),
133
+ value: e.id
134
+ }))]
135
+ },
136
+ {
137
+ name: "siteName",
138
+ label: "Site name",
139
+ type: "text"
140
+ },
141
+ {
142
+ name: "siteAddress",
143
+ label: "Site address",
144
+ type: "text"
145
+ },
146
+ {
147
+ name: "siteLatitude",
148
+ label: "Site latitude",
149
+ type: "text"
150
+ },
151
+ {
152
+ name: "siteLongitude",
153
+ label: "Site longitude",
154
+ type: "text"
155
+ },
156
+ {
157
+ name: "description",
158
+ label: "Details",
159
+ type: "textarea"
160
+ }
161
+ ];
162
+ }
163
+ function u(e) {
164
+ return [{
165
+ name: "shiftId",
166
+ label: "Shift",
167
+ type: "select",
168
+ required: !0,
169
+ options: e.map((e) => ({
170
+ label: r(e),
171
+ value: e.id
172
+ }))
173
+ }];
174
+ }
175
+ function d(e) {
176
+ let t = n(a(e, "siteLatitude")), r = n(a(e, "siteLongitude"));
177
+ return t === null && r === null ? {} : t === null || r === null || Number.isNaN(t) || Number.isNaN(r) ? "Enter both site latitude and longitude as numbers, or leave both empty." : {
178
+ siteLatitude: t,
179
+ siteLongitude: r
180
+ };
181
+ }
182
+ var f = (e, t) => a(e, t) || null, p = (e, t) => {
183
+ let n = a(e, t);
184
+ return n && n !== "none" ? n : null;
185
+ };
186
+ function m(e) {
187
+ let n = d(e);
188
+ if (typeof n == "string") return n;
189
+ let r = t(a(e, "startsAt")), o = t(a(e, "endsAt"));
190
+ if (!r || !o) return "Enter a valid start and end.";
191
+ let s = i(e, "geofenceRadiusMeters"), c = e.reminderMinutesBefore;
192
+ return {
193
+ employeeId: a(e, "employeeId"),
194
+ assigneeUserId: p(e, "assigneeUserId"),
195
+ title: a(e, "title"),
196
+ role: f(e, "role"),
197
+ siteName: f(e, "siteName"),
198
+ siteAddress: f(e, "siteAddress"),
199
+ ...n,
200
+ geofenceRadiusMeters: s > 0 ? s : void 0,
201
+ reminderMinutesBefore: typeof c == "number" ? c : void 0,
202
+ startsAt: r,
203
+ endsAt: o,
204
+ notes: f(e, "notes")
205
+ };
206
+ }
207
+ function h(e) {
208
+ let n = d(e);
209
+ return typeof n == "string" ? n : {
210
+ title: a(e, "title"),
211
+ priority: a(e, "priority") || "NORMAL",
212
+ dueAt: t(a(e, "dueAt")),
213
+ shiftId: p(e, "shiftId"),
214
+ siteName: f(e, "siteName"),
215
+ siteAddress: f(e, "siteAddress"),
216
+ ...n,
217
+ description: f(e, "description")
218
+ };
219
+ }
220
+ //#endregion
221
+ export { o as NO_SELECTION, u as buildAssignFields, l as buildDispatchFields, c as buildShiftFields, h as toDispatchInput, m as toShiftInput };
222
+
223
+ //# sourceMappingURL=fieldForms.js.map