@burdenoff/microfe-movethewheels 2026.1101.3 → 2026.1102.1

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 (29) hide show
  1. package/dist/components/CustomerDeliveryUpdatesFields.js +57 -0
  2. package/dist/components/CustomerNotificationSettingsCard.js +368 -0
  3. package/dist/components/UpcomingDemandPanel.js +75 -77
  4. package/dist/generated/tracking-quality-operations.d.ts +275 -0
  5. package/dist/generated/wspace-operations.d.ts +3 -0
  6. package/dist/hooks/useCustomers.js +9 -3
  7. package/dist/hooks/useDemandForecast.js +1 -1
  8. package/dist/movethewheels/components/CustomerDeliveryUpdatesFields.d.ts +12 -0
  9. package/dist/movethewheels/components/CustomerNotificationSettingsCard.d.ts +3 -0
  10. package/dist/movethewheels/hooks/useDemandForecast.d.ts +3 -0
  11. package/dist/movethewheels/types/index.d.ts +4 -0
  12. package/dist/movethewheels/utils/customerNotifications.d.ts +66 -0
  13. package/dist/node_modules/lucide-react/dist/esm/icons/bell-ring.js +22 -0
  14. package/dist/pages/CustomerDetailsPage.js +279 -231
  15. package/dist/pages/SettingsPage.js +242 -238
  16. package/dist/utils/customerNotifications.js +83 -0
  17. package/package.json +3 -2
  18. package/src/generated/tracking-quality-operations.ts +304 -0
  19. package/src/generated/wspace-operations.ts +6 -6
  20. package/src/movethewheels/components/CustomerDeliveryUpdatesFields.tsx +67 -0
  21. package/src/movethewheels/components/CustomerNotificationSettingsCard.tsx +465 -0
  22. package/src/movethewheels/components/UpcomingDemandPanel.tsx +71 -29
  23. package/src/movethewheels/hooks/useCustomers.ts +17 -0
  24. package/src/movethewheels/hooks/useDemandForecast.ts +7 -0
  25. package/src/movethewheels/pages/CustomerDetailsPage.tsx +39 -0
  26. package/src/movethewheels/pages/SettingsPage.tsx +221 -208
  27. package/src/movethewheels/types/index.ts +4 -0
  28. package/src/movethewheels/utils/customerNotifications.ts +209 -0
  29. package/src/operations/wspace/movethewheels/queries/forecast.graphql +3 -0
@@ -2,178 +2,176 @@ import { Calendar as e } from "../node_modules/lucide-react/dist/esm/icons/calen
2
2
  import { CircleAlert as t } from "../node_modules/lucide-react/dist/esm/icons/circle-alert.js";
3
3
  import { TrendingDown as n } from "../node_modules/lucide-react/dist/esm/icons/trending-down.js";
4
4
  import { TrendingUp as r } from "../node_modules/lucide-react/dist/esm/icons/trending-up.js";
5
- import { Card as i, CardContent as a, CardHeader as o, CardTitle as s, Skeleton as c } from "./ui.js";
6
- import { jsx as l, jsxs as u } from "react/jsx-runtime";
5
+ import { formatCurrency as i } from "../utils/formatters.js";
6
+ import { Card as a, CardContent as o, CardHeader as s, CardTitle as c, Skeleton as l } from "./ui.js";
7
+ import { jsx as u, jsxs as d } from "react/jsx-runtime";
7
8
  //#region src/movethewheels/components/UpcomingDemandPanel.tsx
8
- var d = (e) => {
9
+ var f = (e) => {
9
10
  let t = new Date(e);
10
11
  return Number.isNaN(t.getTime()) ? e : t.toLocaleDateString(void 0, {
11
12
  month: "short",
12
13
  day: "numeric"
13
14
  });
14
- }, f = (e, t) => [...e.filter((e) => e.periodStart === t)].sort((e, t) => t.predictedVolume - e.predictedVolume).slice(0, 3), p = (e, t) => [...e.filter((e) => e.periodStart === t)].sort((e, t) => t.predictedRevenue - e.predictedRevenue).slice(0, 3), m = (e, t) => e.filter((e) => e.periodStart === t).reduce((e, t) => e + t.predictedVolume, 0), h = (e) => e <= 0 ? "Not enough history" : `${Math.round(e * 100)}% confidence`;
15
- function g({ laneForecast: n, customerForecast: r, laneVariance: g, customerVariance: y, isLoading: b, error: x, onRetry: S }) {
16
- if (x && !b) return /* @__PURE__ */ l(i, {
15
+ }, p = (e, t) => e.filter((e) => e.periodStart === t && e.confidence > 0), m = (e, t) => [...p(e, t)].sort((e, t) => t.predictedVolume - e.predictedVolume || t.predictedRevenue - e.predictedRevenue).slice(0, 3), h = (e, t) => [...p(e, t)].sort((e, t) => t.predictedRevenue - e.predictedRevenue).slice(0, 3), g = (e, t) => p(e, t).reduce((e, t) => e + t.predictedVolume, 0), _ = (e, t = /* @__PURE__ */ new Date()) => {
16
+ let n = [...new Set(e.map((e) => e.periodStart))].sort((e, t) => new Date(e).getTime() - new Date(t).getTime());
17
+ return n.find((e) => new Date(e).getTime() > t.getTime()) ?? n.at(-1) ?? null;
18
+ }, v = (e, t) => e === 0 && t > 0 ? "<1 job" : e === 1 ? "1 job" : `${e} jobs`, y = (e) => e <= 0 ? "Not enough history" : `${Math.round(e * 100)}% confidence`;
19
+ function b({ laneForecast: n, customerForecast: r, laneVariance: i, customerVariance: v, isLoading: b, error: C, onRetry: w }) {
20
+ if (C && !b) return /* @__PURE__ */ u(a, {
17
21
  className: "border-status-error-border",
18
- children: /* @__PURE__ */ u(a, {
22
+ children: /* @__PURE__ */ d(o, {
19
23
  className: "p-6 text-center space-y-3",
20
24
  children: [
21
- /* @__PURE__ */ l("p", {
25
+ /* @__PURE__ */ u("p", {
22
26
  className: "text-status-error-text font-medium",
23
27
  children: "Couldn't load demand forecast"
24
28
  }),
25
- /* @__PURE__ */ l("p", {
29
+ /* @__PURE__ */ u("p", {
26
30
  className: "text-sm text-text-secondary",
27
- children: x.message
31
+ children: C.message
28
32
  }),
29
- /* @__PURE__ */ l("button", {
33
+ /* @__PURE__ */ u("button", {
30
34
  type: "button",
31
- onClick: S,
35
+ onClick: w,
32
36
  className: "text-sm font-medium text-primary hover:underline",
33
37
  children: "Retry"
34
38
  })
35
39
  ]
36
40
  })
37
41
  });
38
- if (b) return /* @__PURE__ */ u(i, { children: [/* @__PURE__ */ l(o, { children: /* @__PURE__ */ l(s, { children: "Upcoming demand" }) }), /* @__PURE__ */ u(a, {
42
+ if (b) return /* @__PURE__ */ d(a, { children: [/* @__PURE__ */ u(s, { children: /* @__PURE__ */ u(c, { children: "Upcoming demand" }) }), /* @__PURE__ */ d(o, {
39
43
  className: "space-y-4",
40
44
  children: [
41
- /* @__PURE__ */ l(c, { className: "h-16 w-full" }),
42
- /* @__PURE__ */ l(c, { className: "h-16 w-full" }),
43
- /* @__PURE__ */ l(c, { className: "h-16 w-full" })
45
+ /* @__PURE__ */ u(l, { className: "h-16 w-full" }),
46
+ /* @__PURE__ */ u(l, { className: "h-16 w-full" }),
47
+ /* @__PURE__ */ u(l, { className: "h-16 w-full" })
44
48
  ]
45
49
  })] });
46
- let C = n[0]?.periodStart ?? r[0]?.periodStart ?? null;
47
- if (!C || n.length === 0) return /* @__PURE__ */ u(i, { children: [/* @__PURE__ */ l(o, { children: /* @__PURE__ */ u(s, {
50
+ let T = _([...n, ...r]), E = T !== null && (p(n, T).length > 0 || p(r, T).length > 0);
51
+ if (!T || !E) return /* @__PURE__ */ d(a, { children: [/* @__PURE__ */ u(s, { children: /* @__PURE__ */ d(c, {
48
52
  className: "flex items-center gap-2",
49
- children: [/* @__PURE__ */ l(e, {
53
+ children: [/* @__PURE__ */ u(e, {
50
54
  size: 18,
51
55
  "aria-hidden": "true"
52
56
  }), "Upcoming demand"]
53
- }) }), /* @__PURE__ */ l(a, { children: /* @__PURE__ */ u("div", {
57
+ }) }), /* @__PURE__ */ u(o, { children: /* @__PURE__ */ d("div", {
54
58
  className: "flex items-start gap-2 rounded-lg border border-border/60 bg-muted/40 p-4 text-sm text-text-secondary",
55
- children: [/* @__PURE__ */ l(t, {
59
+ children: [/* @__PURE__ */ u(t, {
56
60
  size: 16,
57
61
  "aria-hidden": "true",
58
62
  className: "mt-0.5 shrink-0"
59
- }), /* @__PURE__ */ l("p", { children: "Not enough history to forecast next week yet. Once you have at least 4 weeks of completed orders, this panel will surface demand by lane and customer." })]
63
+ }), /* @__PURE__ */ u("p", { children: "Not enough history to forecast next week yet. Once a lane or customer has at least 4 weeks of delivery jobs, this panel will surface its demand." })]
60
64
  }) })] });
61
- let w = f(n, C), T = p(n, C), E = f(r, C), D = m(n, C), O = [...g, ...y].sort((e, t) => Math.abs(t.volumeVariance) - Math.abs(e.volumeVariance)).slice(0, 3);
62
- return /* @__PURE__ */ u(i, { children: [/* @__PURE__ */ l(o, { children: /* @__PURE__ */ u(s, {
65
+ let D = m(n, T), O = h(n, T), k = m(r, T), A = p(n, T).length > 0, j = g(A ? n : r, T), M = A ? "Predicted jobs (all lanes)" : "Predicted jobs (all customers)", N = A ? D[0] : k[0], P = [...i, ...v].sort((e, t) => Math.abs(t.volumeVariance) - Math.abs(e.volumeVariance)).slice(0, 3);
66
+ return /* @__PURE__ */ d(a, { children: [/* @__PURE__ */ u(s, { children: /* @__PURE__ */ d(c, {
63
67
  className: "flex items-center gap-2",
64
68
  children: [
65
- /* @__PURE__ */ l(e, {
69
+ /* @__PURE__ */ u(e, {
66
70
  size: 18,
67
71
  "aria-hidden": "true"
68
72
  }),
69
73
  "Upcoming demand — week of ",
70
- d(C)
74
+ f(T)
71
75
  ]
72
- }) }), /* @__PURE__ */ u(a, {
76
+ }) }), /* @__PURE__ */ d(o, {
73
77
  className: "space-y-4",
74
- children: [/* @__PURE__ */ u("div", {
78
+ children: [/* @__PURE__ */ d("div", {
75
79
  className: "flex items-baseline justify-between rounded-lg border border-border/60 bg-muted/40 px-4 py-3",
76
- children: [/* @__PURE__ */ u("div", { children: [/* @__PURE__ */ l("p", {
80
+ children: [/* @__PURE__ */ d("div", { children: [/* @__PURE__ */ u("p", {
77
81
  className: "text-xs uppercase tracking-wide text-text-secondary",
78
- children: "Predicted jobs (all lanes)"
79
- }), /* @__PURE__ */ l("p", {
82
+ children: M
83
+ }), /* @__PURE__ */ u("p", {
80
84
  className: "text-2xl font-bold",
81
- children: D
82
- })] }), /* @__PURE__ */ l("p", {
85
+ children: j
86
+ })] }), /* @__PURE__ */ u("p", {
83
87
  className: "text-xs text-text-secondary",
84
- children: w[0] ? h(w[0].confidence) : ""
88
+ children: N ? y(N.confidence) : ""
85
89
  })]
86
- }), /* @__PURE__ */ u("div", {
90
+ }), /* @__PURE__ */ d("div", {
87
91
  className: "grid grid-cols-1 md:grid-cols-2 gap-4",
88
92
  children: [
89
- /* @__PURE__ */ l(_, {
93
+ /* @__PURE__ */ u(x, {
90
94
  title: "Top lanes (volume)",
91
- rows: w
95
+ rows: D
92
96
  }),
93
- /* @__PURE__ */ l(_, {
97
+ /* @__PURE__ */ u(x, {
94
98
  title: "Top lanes (revenue)",
95
- rows: T
99
+ rows: O
96
100
  }),
97
- /* @__PURE__ */ l(_, {
101
+ /* @__PURE__ */ u(x, {
98
102
  title: "Top customers (volume)",
99
- rows: E
103
+ rows: k
100
104
  }),
101
- /* @__PURE__ */ l(v, { rows: O })
105
+ /* @__PURE__ */ u(S, { rows: P })
102
106
  ]
103
107
  })]
104
108
  })] });
105
109
  }
106
- function _({ title: e, rows: t }) {
107
- return t.length === 0 ? /* @__PURE__ */ u("div", {
110
+ function x({ title: e, rows: t }) {
111
+ return t.length === 0 ? /* @__PURE__ */ d("div", {
108
112
  className: "rounded-lg border border-border/60 p-4",
109
- children: [/* @__PURE__ */ l("p", {
113
+ children: [/* @__PURE__ */ u("p", {
110
114
  className: "text-sm font-medium mb-2",
111
115
  children: e
112
- }), /* @__PURE__ */ l("p", {
116
+ }), /* @__PURE__ */ u("p", {
113
117
  className: "text-xs text-text-secondary",
114
118
  children: "No forecasts yet for this week."
115
119
  })]
116
- }) : /* @__PURE__ */ u("div", {
120
+ }) : /* @__PURE__ */ d("div", {
117
121
  className: "rounded-lg border border-border/60 p-4",
118
- children: [/* @__PURE__ */ l("p", {
122
+ children: [/* @__PURE__ */ u("p", {
119
123
  className: "text-sm font-medium mb-3",
120
124
  children: e
121
- }), /* @__PURE__ */ l("ul", {
125
+ }), /* @__PURE__ */ u("ul", {
122
126
  className: "space-y-2",
123
- children: t.map((e) => /* @__PURE__ */ u("li", {
127
+ children: t.map((e) => /* @__PURE__ */ d("li", {
124
128
  className: "flex items-center justify-between text-sm",
125
- children: [/* @__PURE__ */ l("span", {
129
+ children: [/* @__PURE__ */ u("span", {
126
130
  className: "truncate font-medium",
127
- children: e.scopeKey
128
- }), /* @__PURE__ */ u("span", {
131
+ title: e.scopeLabel,
132
+ children: e.scopeLabel
133
+ }), /* @__PURE__ */ d("span", {
129
134
  className: "ml-2 shrink-0 text-text-secondary",
130
135
  children: [
131
- e.predictedVolume,
132
- " jobs ·",
136
+ v(e.predictedVolume, e.predictedRevenue),
137
+ " ·",
133
138
  " ",
134
- new Intl.NumberFormat(void 0, {
135
- style: "currency",
136
- currency: "USD",
137
- maximumFractionDigits: 0
138
- }).format(e.predictedRevenue)
139
+ i(e.predictedRevenue)
139
140
  ]
140
141
  })]
141
142
  }, `${e.scopeType}-${e.scopeKey}`))
142
143
  })]
143
144
  });
144
145
  }
145
- function v({ rows: e }) {
146
- return /* @__PURE__ */ u("div", {
146
+ function S({ rows: e }) {
147
+ return /* @__PURE__ */ d("div", {
147
148
  className: "rounded-lg border border-border/60 p-4",
148
- children: [/* @__PURE__ */ l("p", {
149
+ children: [/* @__PURE__ */ u("p", {
149
150
  className: "text-sm font-medium mb-3",
150
151
  children: "Recent forecast variance"
151
- }), e.length === 0 ? /* @__PURE__ */ l("p", {
152
+ }), e.length === 0 ? /* @__PURE__ */ u("p", {
152
153
  className: "text-xs text-text-secondary",
153
154
  children: "No closed periods to compare yet."
154
- }) : /* @__PURE__ */ l("ul", {
155
+ }) : /* @__PURE__ */ u("ul", {
155
156
  className: "space-y-2",
156
157
  children: e.map((e) => {
157
158
  let t = e.volumeVariance > 0, i = t ? r : n, a = t ? "text-status-success-text" : "text-status-error-text";
158
- return /* @__PURE__ */ u("li", {
159
+ return /* @__PURE__ */ d("li", {
159
160
  className: "flex items-center justify-between text-sm",
160
- children: [/* @__PURE__ */ u("span", {
161
+ children: [/* @__PURE__ */ d("span", {
161
162
  className: "flex items-center gap-2 truncate",
162
- children: [/* @__PURE__ */ l(i, {
163
+ children: [/* @__PURE__ */ u(i, {
163
164
  size: 14,
164
165
  className: a,
165
166
  "aria-hidden": "true"
166
- }), /* @__PURE__ */ l("span", {
167
+ }), /* @__PURE__ */ u("span", {
167
168
  className: "truncate font-medium",
168
- children: e.scopeKey
169
+ title: e.scopeLabel,
170
+ children: e.scopeLabel
169
171
  })]
170
- }), /* @__PURE__ */ u("span", {
172
+ }), /* @__PURE__ */ d("span", {
171
173
  className: `ml-2 shrink-0 ${a}`,
172
- children: [
173
- t ? "+" : "",
174
- e.volumeVariance,
175
- " jobs"
176
- ]
174
+ children: [t ? "+" : "", Math.abs(e.volumeVariance) === 1 ? `${e.volumeVariance} job` : `${e.volumeVariance} jobs`]
177
175
  })]
178
176
  }, `${e.scopeType}-${e.scopeKey}-${e.periodStart}`);
179
177
  })
@@ -181,4 +179,4 @@ function v({ rows: e }) {
181
179
  });
182
180
  }
183
181
  //#endregion
184
- export { g as UpcomingDemandPanel };
182
+ export { b as UpcomingDemandPanel };