@burdenoff/microfe-movethewheels 2026.1101.4 → 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.
- package/dist/components/CustomerDeliveryUpdatesFields.js +57 -0
- package/dist/components/CustomerNotificationSettingsCard.js +368 -0
- package/dist/generated/tracking-quality-operations.d.ts +275 -0
- package/dist/hooks/useCustomers.js +9 -3
- package/dist/movethewheels/components/CustomerDeliveryUpdatesFields.d.ts +12 -0
- package/dist/movethewheels/components/CustomerNotificationSettingsCard.d.ts +3 -0
- package/dist/movethewheels/types/index.d.ts +4 -0
- package/dist/movethewheels/utils/customerNotifications.d.ts +66 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/bell-ring.js +22 -0
- package/dist/pages/CustomerDetailsPage.js +279 -231
- package/dist/pages/SettingsPage.js +242 -238
- package/dist/utils/customerNotifications.js +83 -0
- package/package.json +3 -2
- package/src/generated/tracking-quality-operations.ts +304 -0
- package/src/movethewheels/components/CustomerDeliveryUpdatesFields.tsx +67 -0
- package/src/movethewheels/components/CustomerNotificationSettingsCard.tsx +465 -0
- package/src/movethewheels/hooks/useCustomers.ts +17 -0
- package/src/movethewheels/pages/CustomerDetailsPage.tsx +39 -0
- package/src/movethewheels/pages/SettingsPage.tsx +221 -208
- package/src/movethewheels/types/index.ts +4 -0
- package/src/movethewheels/utils/customerNotifications.ts +209 -0
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
//#region src/movethewheels/utils/customerNotifications.ts
|
|
2
|
+
var e = [
|
|
3
|
+
{
|
|
4
|
+
value: "BOOKED",
|
|
5
|
+
label: "Booked",
|
|
6
|
+
description: "A shipment is created for the customer"
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
value: "PICKED_UP",
|
|
10
|
+
label: "Picked up",
|
|
11
|
+
description: "The shipment is collected"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
value: "OUT_FOR_DELIVERY",
|
|
15
|
+
label: "Out for delivery",
|
|
16
|
+
description: "Tracking says the shipment is on its last leg"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
value: "DELIVERED",
|
|
20
|
+
label: "Delivered",
|
|
21
|
+
description: "The shipment is delivered"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
value: "DELAYED",
|
|
25
|
+
label: "Running late",
|
|
26
|
+
description: "The risk monitor expects it to miss the promised delivery (once per promise)"
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
value: "FAILED",
|
|
30
|
+
label: "Delivery failed",
|
|
31
|
+
description: "Delivery could not be completed"
|
|
32
|
+
}
|
|
33
|
+
];
|
|
34
|
+
function t(t) {
|
|
35
|
+
return e.find((e) => e.value === t)?.label ?? t;
|
|
36
|
+
}
|
|
37
|
+
var n = {
|
|
38
|
+
PENDING: "Sending",
|
|
39
|
+
SENT: "Sent",
|
|
40
|
+
FAILED: "Failed",
|
|
41
|
+
SKIPPED: "Not sent"
|
|
42
|
+
};
|
|
43
|
+
function r(t = "") {
|
|
44
|
+
return {
|
|
45
|
+
workspaceId: t,
|
|
46
|
+
enabled: !1,
|
|
47
|
+
enabledAt: null,
|
|
48
|
+
emailEnabled: !0,
|
|
49
|
+
smsEnabled: !1,
|
|
50
|
+
events: e.map((e) => e.value),
|
|
51
|
+
isCustomized: !1,
|
|
52
|
+
updatedAt: null,
|
|
53
|
+
updatedBy: null
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
function i(t) {
|
|
57
|
+
let n = new Set(t);
|
|
58
|
+
return e.map((e) => e.value).filter((e) => n.has(e));
|
|
59
|
+
}
|
|
60
|
+
function a(e, t, n) {
|
|
61
|
+
let r = new Set(e);
|
|
62
|
+
return n ? r.add(t) : r.delete(t), i([...r]);
|
|
63
|
+
}
|
|
64
|
+
function o(e, t) {
|
|
65
|
+
let n = {};
|
|
66
|
+
t.enabled !== e.enabled && (n.enabled = t.enabled), t.emailEnabled !== e.emailEnabled && (n.emailEnabled = t.emailEnabled), t.smsEnabled !== e.smsEnabled && (n.smsEnabled = t.smsEnabled);
|
|
67
|
+
let r = i(t.events), a = i(e.events);
|
|
68
|
+
return r.join(",") !== a.join(",") && (n.events = r), n;
|
|
69
|
+
}
|
|
70
|
+
function s(e) {
|
|
71
|
+
return e.enabled ? !e.emailEnabled && !e.smsEnabled ? "Choose email, SMS or both." : e.events.length === 0 ? "Choose at least one event to notify customers about." : null : null;
|
|
72
|
+
}
|
|
73
|
+
var c = "\n workspaceId\n enabled\n enabledAt\n emailEnabled\n smsEnabled\n events\n isCustomized\n updatedAt\n updatedBy\n", l = `
|
|
74
|
+
query MtwCustomerNotificationSettings {
|
|
75
|
+
mtwCustomerNotificationSettings {${c}}
|
|
76
|
+
}
|
|
77
|
+
`, u = `
|
|
78
|
+
mutation UpdateMtwCustomerNotificationSettings($input: UpdateMtwCustomerNotificationSettingsInput!) {
|
|
79
|
+
updateMtwCustomerNotificationSettings(input: $input) {${c}}
|
|
80
|
+
}
|
|
81
|
+
`, d = "\n query MtwCustomerNotifications(\n $filter: MtwCustomerNotificationFilterInput\n $pagination: PaginationInput\n ) {\n mtwCustomerNotifications(filter: $filter, pagination: $pagination) {\n total\n hasMore\n items {\n id\n shipmentId\n shipmentNumber\n customerId\n event\n channel\n status\n recipient\n subject\n attempts\n lastError\n sentAt\n createdAt\n }\n }\n }\n", f = "\n query MtwCustomerNotificationPreviews {\n mtwCustomerNotificationPreviews {\n event\n subject\n emailText\n smsText\n }\n }\n";
|
|
82
|
+
//#endregion
|
|
83
|
+
export { e as CUSTOMER_NOTIFICATION_EVENTS, d as MTW_CUSTOMER_NOTIFICATIONS_QUERY, f as MTW_CUSTOMER_NOTIFICATION_PREVIEWS_QUERY, l as MTW_CUSTOMER_NOTIFICATION_SETTINGS_QUERY, n as STATUS_LABELS, u as UPDATE_MTW_CUSTOMER_NOTIFICATION_SETTINGS_MUTATION, o as changedNotificationSettings, r as defaultNotificationSettings, t as eventLabel, s as notificationDraftError, a as toggleEvent };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@burdenoff/microfe-movethewheels",
|
|
3
|
-
"version": "2026.
|
|
3
|
+
"version": "2026.1102.1",
|
|
4
4
|
"description": "Burdenoff MoveTheWheels Microfrontend - Logistics & Supply Chain Management Platform",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"format": "prettier --write \"src/**/*.{ts,tsx}\"",
|
|
38
38
|
"type:check": "bash scripts/build-limits.sh tsc --noEmit",
|
|
39
39
|
"validate:schema-drift": "graphql-schema-drift",
|
|
40
|
-
"sanity": "bash scripts/build-limits.sh --gate bash -c 'bun run codegen && bun run validate:schema-drift && bun run lint:sanity && bun run format && bun run type:check && bun run verify:live-logistics-contract && bun run verify:empty-reuse-retry && bun run verify:empty-reuse-recovery && bun run verify:trip-utilization-input && bun run verify:trip-draft-context && bun run verify:stock-binding-input && bun run verify:stock-observation-input && bun run verify:pending-pick-input && bun run verify:pick-review-ack && bun run verify:driver-license-expiry && bun run verify:tracking-alerts && bun run verify:freight-input && bun run verify:freight-recovery && bun run verify:freight-commercial && bun run verify:freight-invoice && bun run verify:procedure-input && bun run verify:consolidation && bun run verify:multimodal-single-attempt && bun run verify:workspace-predispatch && bun run verify:tracking-quality-outcomes && bun run verify:shipment-status-authority && bun run verify:free-time-permissions && bun run verify:core-codegen && bun run verify:order-vehicle-hold && bun run verify:pallet-preview && bun run verify:entity-export && bun run verify:entity-import && bun run verify:module-settings && bun run verify:carrier-integrations && bun run verify:driver-day && bun run verify:consumed-fuel-preview && bun run build && bun run build-storybook'",
|
|
40
|
+
"sanity": "bash scripts/build-limits.sh --gate bash -c 'bun run codegen && bun run validate:schema-drift && bun run lint:sanity && bun run format && bun run type:check && bun run verify:live-logistics-contract && bun run verify:empty-reuse-retry && bun run verify:empty-reuse-recovery && bun run verify:trip-utilization-input && bun run verify:trip-draft-context && bun run verify:stock-binding-input && bun run verify:stock-observation-input && bun run verify:pending-pick-input && bun run verify:pick-review-ack && bun run verify:driver-license-expiry && bun run verify:tracking-alerts && bun run verify:freight-input && bun run verify:freight-recovery && bun run verify:freight-commercial && bun run verify:freight-invoice && bun run verify:procedure-input && bun run verify:consolidation && bun run verify:multimodal-single-attempt && bun run verify:workspace-predispatch && bun run verify:tracking-quality-outcomes && bun run verify:shipment-status-authority && bun run verify:free-time-permissions && bun run verify:core-codegen && bun run verify:order-vehicle-hold && bun run verify:pallet-preview && bun run verify:entity-export && bun run verify:entity-import && bun run verify:module-settings && bun run verify:carrier-integrations && bun run verify:driver-day && bun run verify:customer-notifications && bun run verify:consumed-fuel-preview && bun run build && bun run build-storybook'",
|
|
41
41
|
"storybook": "storybook dev -p 6006",
|
|
42
42
|
"build-storybook": "storybook build",
|
|
43
43
|
"test:storybook": "vitest run --project=storybook",
|
|
@@ -77,6 +77,7 @@
|
|
|
77
77
|
"verify:module-settings": "bun test scripts/check-module-settings.test.ts",
|
|
78
78
|
"verify:driver-day": "bun test scripts/verify-driver-day.test.ts && bun scripts/verify-acknowledged-pending-delivery.mjs",
|
|
79
79
|
"verify:carrier-integrations": "bun test scripts/check-carrier-integrations.test.ts",
|
|
80
|
+
"verify:customer-notifications": "bun test scripts/check-customer-notifications.test.ts",
|
|
80
81
|
"verify:pallet-preview": "bun test scripts/check-pallet-preview.test.ts && bun scripts/verify-pallet-preview-hook.mjs",
|
|
81
82
|
"verify:consumed-fuel-preview": "bun test scripts/check-consumed-fuel-preview.test.ts && bun scripts/verify-consumed-fuel-preview-hook.mjs && bun scripts/verify-consumed-fuel-preview-component.mjs"
|
|
82
83
|
},
|
|
@@ -128,6 +128,8 @@ export type CreateCustomerInput = {
|
|
|
128
128
|
context?: InputMaybe<ContextInput>;
|
|
129
129
|
email?: InputMaybe<Scalars['String']['input']>;
|
|
130
130
|
name: Scalars['String']['input'];
|
|
131
|
+
notifyByEmail?: InputMaybe<Scalars['Boolean']['input']>;
|
|
132
|
+
notifyBySms?: InputMaybe<Scalars['Boolean']['input']>;
|
|
131
133
|
phone?: InputMaybe<Scalars['String']['input']>;
|
|
132
134
|
rating?: InputMaybe<Scalars['Float']['input']>;
|
|
133
135
|
taxId?: InputMaybe<Scalars['String']['input']>;
|
|
@@ -1115,6 +1117,10 @@ export type MtwCustomer = {
|
|
|
1115
1117
|
email?: Maybe<Scalars['String']['output']>;
|
|
1116
1118
|
id: Scalars['ID']['output'];
|
|
1117
1119
|
name: Scalars['String']['output'];
|
|
1120
|
+
/** Send this customer delivery notifications by email (BOFF-4402). The workspace must also switch customer notifications on. */
|
|
1121
|
+
notifyByEmail: Scalars['Boolean']['output'];
|
|
1122
|
+
/** Send this customer delivery notifications by SMS. Needs a phone number with its country code. */
|
|
1123
|
+
notifyBySms: Scalars['Boolean']['output'];
|
|
1118
1124
|
onBehalfOf: Scalars['String']['output'];
|
|
1119
1125
|
phone?: Maybe<Scalars['String']['output']>;
|
|
1120
1126
|
rating?: Maybe<Scalars['Float']['output']>;
|
|
@@ -1125,6 +1131,101 @@ export type MtwCustomer = {
|
|
|
1125
1131
|
workspaceId: Scalars['ID']['output'];
|
|
1126
1132
|
};
|
|
1127
1133
|
|
|
1134
|
+
/** One notification sent (or attempted) to a shipment's customer. */
|
|
1135
|
+
export type MtwCustomerNotification = {
|
|
1136
|
+
__typename?: 'MtwCustomerNotification';
|
|
1137
|
+
attempts: Scalars['Int']['output'];
|
|
1138
|
+
channel: MtwCustomerNotificationChannel;
|
|
1139
|
+
createdAt: Scalars['DateTime']['output'];
|
|
1140
|
+
customerId?: Maybe<Scalars['ID']['output']>;
|
|
1141
|
+
event: MtwCustomerNotificationEvent;
|
|
1142
|
+
id: Scalars['ID']['output'];
|
|
1143
|
+
lastError?: Maybe<Scalars['String']['output']>;
|
|
1144
|
+
/** Masked address, e.g. j***@example.com. */
|
|
1145
|
+
recipient?: Maybe<Scalars['String']['output']>;
|
|
1146
|
+
sentAt?: Maybe<Scalars['DateTime']['output']>;
|
|
1147
|
+
shipmentId: Scalars['ID']['output'];
|
|
1148
|
+
shipmentNumber?: Maybe<Scalars['String']['output']>;
|
|
1149
|
+
status: MtwCustomerNotificationStatus;
|
|
1150
|
+
subject?: Maybe<Scalars['String']['output']>;
|
|
1151
|
+
updatedAt: Scalars['DateTime']['output'];
|
|
1152
|
+
};
|
|
1153
|
+
|
|
1154
|
+
/** How a customer is reached. */
|
|
1155
|
+
export type MtwCustomerNotificationChannel =
|
|
1156
|
+
| 'EMAIL'
|
|
1157
|
+
| 'SMS';
|
|
1158
|
+
|
|
1159
|
+
/** A shipment lifecycle moment a customer can be told about (BOFF-4402). */
|
|
1160
|
+
export type MtwCustomerNotificationEvent =
|
|
1161
|
+
/** The shipment was created for the customer. */
|
|
1162
|
+
| 'BOOKED'
|
|
1163
|
+
/** The risk monitor expects the shipment to miss its promised delivery. Sent once per promise. */
|
|
1164
|
+
| 'DELAYED'
|
|
1165
|
+
/** The shipment was delivered. */
|
|
1166
|
+
| 'DELIVERED'
|
|
1167
|
+
/** Delivery could not be completed. */
|
|
1168
|
+
| 'FAILED'
|
|
1169
|
+
/** The latest tracking event says the shipment is out for delivery. */
|
|
1170
|
+
| 'OUT_FOR_DELIVERY'
|
|
1171
|
+
/** The shipment was collected. */
|
|
1172
|
+
| 'PICKED_UP';
|
|
1173
|
+
|
|
1174
|
+
export type MtwCustomerNotificationFilterInput = {
|
|
1175
|
+
event?: InputMaybe<MtwCustomerNotificationEvent>;
|
|
1176
|
+
shipmentId?: InputMaybe<Scalars['ID']['input']>;
|
|
1177
|
+
status?: InputMaybe<MtwCustomerNotificationStatus>;
|
|
1178
|
+
};
|
|
1179
|
+
|
|
1180
|
+
/** A page of customer notifications, newest first. */
|
|
1181
|
+
export type MtwCustomerNotificationPage = {
|
|
1182
|
+
__typename?: 'MtwCustomerNotificationPage';
|
|
1183
|
+
hasMore: Scalars['Boolean']['output'];
|
|
1184
|
+
items: Array<MtwCustomerNotification>;
|
|
1185
|
+
total: Scalars['Int']['output'];
|
|
1186
|
+
};
|
|
1187
|
+
|
|
1188
|
+
/** What a customer notification for an event looks like, rendered with sample data. */
|
|
1189
|
+
export type MtwCustomerNotificationPreview = {
|
|
1190
|
+
__typename?: 'MtwCustomerNotificationPreview';
|
|
1191
|
+
emailText: Scalars['String']['output'];
|
|
1192
|
+
event: MtwCustomerNotificationEvent;
|
|
1193
|
+
smsText: Scalars['String']['output'];
|
|
1194
|
+
subject: Scalars['String']['output'];
|
|
1195
|
+
};
|
|
1196
|
+
|
|
1197
|
+
/**
|
|
1198
|
+
* Whether and how this workspace tells its customers about their shipments.
|
|
1199
|
+
* Off until a workspace admin switches it on; only shipment changes made after
|
|
1200
|
+
* that moment notify, so switching on never mails customers about old shipments.
|
|
1201
|
+
*/
|
|
1202
|
+
export type MtwCustomerNotificationSettings = {
|
|
1203
|
+
__typename?: 'MtwCustomerNotificationSettings';
|
|
1204
|
+
emailEnabled: Scalars['Boolean']['output'];
|
|
1205
|
+
enabled: Scalars['Boolean']['output'];
|
|
1206
|
+
/** When notifications were last switched on. */
|
|
1207
|
+
enabledAt?: Maybe<Scalars['DateTime']['output']>;
|
|
1208
|
+
/** Events that notify customers. */
|
|
1209
|
+
events: Array<MtwCustomerNotificationEvent>;
|
|
1210
|
+
/** False until the workspace saves these settings. */
|
|
1211
|
+
isCustomized: Scalars['Boolean']['output'];
|
|
1212
|
+
smsEnabled: Scalars['Boolean']['output'];
|
|
1213
|
+
updatedAt?: Maybe<Scalars['DateTime']['output']>;
|
|
1214
|
+
updatedBy?: Maybe<Scalars['ID']['output']>;
|
|
1215
|
+
workspaceId: Scalars['ID']['output'];
|
|
1216
|
+
};
|
|
1217
|
+
|
|
1218
|
+
/** Where a customer notification stands. */
|
|
1219
|
+
export type MtwCustomerNotificationStatus =
|
|
1220
|
+
/** Not accepted; retried by a later evaluation up to three times. */
|
|
1221
|
+
| 'FAILED'
|
|
1222
|
+
/** Claimed and being sent. */
|
|
1223
|
+
| 'PENDING'
|
|
1224
|
+
/** Accepted by the platform notification service. */
|
|
1225
|
+
| 'SENT'
|
|
1226
|
+
/** Not sent because the customer has no usable address for the channel. */
|
|
1227
|
+
| 'SKIPPED';
|
|
1228
|
+
|
|
1128
1229
|
export type MtwCustomerStats = {
|
|
1129
1230
|
__typename?: 'MtwCustomerStats';
|
|
1130
1231
|
/** Unavailable because customers have no lifecycle status field. */
|
|
@@ -3562,6 +3663,9 @@ export type MtwRiskForecast = {
|
|
|
3562
3663
|
evaluatedAt: Scalars['DateTime']['output'];
|
|
3563
3664
|
/** Forecasting method, e.g. DETERMINISTIC_V1. */
|
|
3564
3665
|
method: Scalars['String']['output'];
|
|
3666
|
+
/** AI narration of this forecast. Null when AI is disabled, credits are spent, or none was generated yet. */
|
|
3667
|
+
narration?: Maybe<MtwRiskNarration>;
|
|
3668
|
+
narrationStatus: MtwRiskNarrationStatus;
|
|
3565
3669
|
predictedDeliveryEarliest?: Maybe<Scalars['DateTime']['output']>;
|
|
3566
3670
|
predictedDeliveryLatest?: Maybe<Scalars['DateTime']['output']>;
|
|
3567
3671
|
predictedSlipMinutes: Scalars['Int']['output'];
|
|
@@ -3583,6 +3687,42 @@ export type MtwRiskLevel =
|
|
|
3583
3687
|
| 'MEDIUM'
|
|
3584
3688
|
| 'NONE';
|
|
3585
3689
|
|
|
3690
|
+
/**
|
|
3691
|
+
* Plain-language explanation of a risk forecast, written by a model from the
|
|
3692
|
+
* forecast's computed features. It never changes the forecast's numbers.
|
|
3693
|
+
*/
|
|
3694
|
+
export type MtwRiskNarration = {
|
|
3695
|
+
__typename?: 'MtwRiskNarration';
|
|
3696
|
+
/** Suggested message to the end customer re-promising delivery, when one is warranted. */
|
|
3697
|
+
customerMessage?: Maybe<Scalars['String']['output']>;
|
|
3698
|
+
/** Why the shipment is predicted to slip, in two or three sentences. */
|
|
3699
|
+
explanation: Scalars['String']['output'];
|
|
3700
|
+
generatedAt: Scalars['DateTime']['output'];
|
|
3701
|
+
id: Scalars['ID']['output'];
|
|
3702
|
+
/** Language the narration was written in. */
|
|
3703
|
+
locale: Scalars['String']['output'];
|
|
3704
|
+
/** Provider-qualified model that wrote it, e.g. openai/gpt-4o-mini. */
|
|
3705
|
+
model: Scalars['String']['output'];
|
|
3706
|
+
/** interactive, scheduled or event. */
|
|
3707
|
+
trigger: Scalars['String']['output'];
|
|
3708
|
+
};
|
|
3709
|
+
|
|
3710
|
+
export type MtwRiskNarrationStatus =
|
|
3711
|
+
/** AI narration is switched off for this environment. */
|
|
3712
|
+
| 'AI_DISABLED'
|
|
3713
|
+
/** A narration for the forecast as it stands now is attached. */
|
|
3714
|
+
| 'AVAILABLE'
|
|
3715
|
+
/** The workspace has spent its MoveTheWheels AI credits; no model call was made. */
|
|
3716
|
+
| 'CREDITS_EXHAUSTED'
|
|
3717
|
+
/** The workspace reached its daily narration cap; no model call was made. */
|
|
3718
|
+
| 'DAILY_CAP_REACHED'
|
|
3719
|
+
/** The forecast has no risk signals, so there is nothing to explain. */
|
|
3720
|
+
| 'NOT_NEEDED'
|
|
3721
|
+
/** No narration has been generated for this forecast yet; call mtwNarrateShipmentRiskForecast. */
|
|
3722
|
+
| 'NOT_REQUESTED'
|
|
3723
|
+
/** The model could not produce a narration this time; the forecast is unchanged. */
|
|
3724
|
+
| 'UNAVAILABLE';
|
|
3725
|
+
|
|
3586
3726
|
export type MtwRiskRecommendedAction =
|
|
3587
3727
|
| 'MONITOR'
|
|
3588
3728
|
| 'NONE'
|
|
@@ -3612,6 +3752,51 @@ export type MtwRiskSignalCode =
|
|
|
3612
3752
|
| 'TRACKING_STALE'
|
|
3613
3753
|
| 'VEHICLE_UNAVAILABLE';
|
|
3614
3754
|
|
|
3755
|
+
export type MtwRiskSweep = {
|
|
3756
|
+
__typename?: 'MtwRiskSweep';
|
|
3757
|
+
atRisk: Scalars['Int']['output'];
|
|
3758
|
+
/**
|
|
3759
|
+
* True when this call was a redelivery of an earlier scheduler fire with the
|
|
3760
|
+
* same idempotency key; the original sweep is returned and nothing ran again.
|
|
3761
|
+
*/
|
|
3762
|
+
duplicate: Scalars['Boolean']['output'];
|
|
3763
|
+
durationMs?: Maybe<Scalars['Int']['output']>;
|
|
3764
|
+
episodesClosed: Scalars['Int']['output'];
|
|
3765
|
+
episodesOpened: Scalars['Int']['output'];
|
|
3766
|
+
error?: Maybe<Scalars['String']['output']>;
|
|
3767
|
+
finishedAt?: Maybe<Scalars['DateTime']['output']>;
|
|
3768
|
+
id: Scalars['ID']['output'];
|
|
3769
|
+
notificationsSent: Scalars['Int']['output'];
|
|
3770
|
+
scheduledFor?: Maybe<Scalars['DateTime']['output']>;
|
|
3771
|
+
shipmentsEvaluated: Scalars['Int']['output'];
|
|
3772
|
+
/** KILL_SWITCH when the monitor is switched off. */
|
|
3773
|
+
skippedReason?: Maybe<Scalars['String']['output']>;
|
|
3774
|
+
startedAt: Scalars['DateTime']['output'];
|
|
3775
|
+
/** RUNNING, COMPLETED, SKIPPED or FAILED. */
|
|
3776
|
+
status: Scalars['String']['output'];
|
|
3777
|
+
/** SCHEDULED (fired by wspace-scheduler-svc) or MANUAL. */
|
|
3778
|
+
trigger: Scalars['String']['output'];
|
|
3779
|
+
workspaceId: Scalars['ID']['output'];
|
|
3780
|
+
};
|
|
3781
|
+
|
|
3782
|
+
/**
|
|
3783
|
+
* The workspace's cadence job in wspace-scheduler-svc. A workspace admin can pause
|
|
3784
|
+
* it on the shared Schedules screen; the monitor leaves a paused job alone.
|
|
3785
|
+
*/
|
|
3786
|
+
export type MtwRiskSweepSchedule = {
|
|
3787
|
+
__typename?: 'MtwRiskSweepSchedule';
|
|
3788
|
+
cronExpression: Scalars['String']['output'];
|
|
3789
|
+
id: Scalars['ID']['output'];
|
|
3790
|
+
lastError?: Maybe<Scalars['String']['output']>;
|
|
3791
|
+
lastSweepAt?: Maybe<Scalars['DateTime']['output']>;
|
|
3792
|
+
schedulerJobId?: Maybe<Scalars['ID']['output']>;
|
|
3793
|
+
/** PENDING, ACTIVE or FAILED. */
|
|
3794
|
+
status: Scalars['String']['output'];
|
|
3795
|
+
timezone: Scalars['String']['output'];
|
|
3796
|
+
updatedAt: Scalars['DateTime']['output'];
|
|
3797
|
+
workspaceId: Scalars['ID']['output'];
|
|
3798
|
+
};
|
|
3799
|
+
|
|
3615
3800
|
export type MtwRoute = {
|
|
3616
3801
|
__typename?: 'MtwRoute';
|
|
3617
3802
|
actualDistance?: Maybe<Scalars['Float']['output']>;
|
|
@@ -3650,6 +3835,16 @@ export type MtwRouteStats = {
|
|
|
3650
3835
|
totalDuration: Scalars['Float']['output'];
|
|
3651
3836
|
};
|
|
3652
3837
|
|
|
3838
|
+
/**
|
|
3839
|
+
* Set by wspace-scheduler-svc at fire time: idempotencyKey is
|
|
3840
|
+
* "<scheduleId>:<scheduledTime>" and triggerData carries scheduledTime, firedAt,
|
|
3841
|
+
* timezone, scheduleId and eventId. Ignored for on-demand runs by a person.
|
|
3842
|
+
*/
|
|
3843
|
+
export type MtwRunRiskSweepInput = {
|
|
3844
|
+
idempotencyKey?: InputMaybe<Scalars['String']['input']>;
|
|
3845
|
+
triggerData?: InputMaybe<Scalars['JSON']['input']>;
|
|
3846
|
+
};
|
|
3847
|
+
|
|
3653
3848
|
/** Whether the provider currently has capacity for an offering. */
|
|
3654
3849
|
export type MtwServiceAvailability =
|
|
3655
3850
|
| 'AVAILABLE'
|
|
@@ -3871,6 +4066,40 @@ export type MtwShipmentLeg = {
|
|
|
3871
4066
|
workspaceId: Scalars['ID']['output'];
|
|
3872
4067
|
};
|
|
3873
4068
|
|
|
4069
|
+
/**
|
|
4070
|
+
* The current (or last) risk episode of one shipment. An episode opens when the
|
|
4071
|
+
* forecast first reports the shipment at risk, notifies once, and closes when the
|
|
4072
|
+
* forecast recovers, the promise passes or the shipment finishes.
|
|
4073
|
+
*/
|
|
4074
|
+
export type MtwShipmentRiskEpisode = {
|
|
4075
|
+
__typename?: 'MtwShipmentRiskEpisode';
|
|
4076
|
+
/** RECOVERED, BREACHED, COMPLETED or REMOVED. */
|
|
4077
|
+
closeReason?: Maybe<Scalars['String']['output']>;
|
|
4078
|
+
closedAt?: Maybe<Scalars['DateTime']['output']>;
|
|
4079
|
+
/** How many episodes this shipment has had. */
|
|
4080
|
+
episodeCount: Scalars['Int']['output'];
|
|
4081
|
+
id: Scalars['ID']['output'];
|
|
4082
|
+
lastEvaluatedAt: Scalars['DateTime']['output'];
|
|
4083
|
+
lastNotificationError?: Maybe<Scalars['String']['output']>;
|
|
4084
|
+
/** EVENT or SWEEP: what evaluated the shipment last. */
|
|
4085
|
+
lastTrigger: Scalars['String']['output'];
|
|
4086
|
+
notificationAttempts: Scalars['Int']['output'];
|
|
4087
|
+
notificationsSent: Scalars['Int']['output'];
|
|
4088
|
+
/** When the episode's notification reached at least one recipient. */
|
|
4089
|
+
notifiedAt?: Maybe<Scalars['DateTime']['output']>;
|
|
4090
|
+
openedAt: Scalars['DateTime']['output'];
|
|
4091
|
+
predictedSlipMinutes: Scalars['Int']['output'];
|
|
4092
|
+
/** The promised delivery the episode was raised against. */
|
|
4093
|
+
promisedDelivery?: Maybe<Scalars['DateTime']['output']>;
|
|
4094
|
+
recommendedAction?: Maybe<Scalars['String']['output']>;
|
|
4095
|
+
riskLevel: Scalars['String']['output'];
|
|
4096
|
+
riskScore: Scalars['Int']['output'];
|
|
4097
|
+
shipmentId: Scalars['ID']['output'];
|
|
4098
|
+
signals: Array<Scalars['String']['output']>;
|
|
4099
|
+
/** OPEN or CLOSED. */
|
|
4100
|
+
state: Scalars['String']['output'];
|
|
4101
|
+
};
|
|
4102
|
+
|
|
3874
4103
|
export type MtwShipmentStatusDecision = {
|
|
3875
4104
|
__typename?: 'MtwShipmentStatusDecision';
|
|
3876
4105
|
authorityEpoch: Scalars['Int']['output'];
|
|
@@ -4254,6 +4483,8 @@ export type MtwTrackingAlert = {
|
|
|
4254
4483
|
/** Stable alert id, `<shipmentId>:<alertType>`. */
|
|
4255
4484
|
id: Scalars['ID']['output'];
|
|
4256
4485
|
message: Scalars['String']['output'];
|
|
4486
|
+
/** AI narration of the forecast behind an AT_RISK alert, when one was generated for its current signals. */
|
|
4487
|
+
narration?: Maybe<MtwRiskNarration>;
|
|
4257
4488
|
predictedDelivery?: Maybe<Scalars['DateTime']['output']>;
|
|
4258
4489
|
/** The shipment's promised delivery (estimatedDelivery) the alert was raised against. */
|
|
4259
4490
|
promisedDelivery?: Maybe<Scalars['DateTime']['output']>;
|
|
@@ -4652,6 +4883,24 @@ export type Mutation = {
|
|
|
4652
4883
|
importMtwDrivers: MtwImportResult;
|
|
4653
4884
|
importMtwVehicles: MtwImportResult;
|
|
4654
4885
|
importMtwWarehouses: MtwImportResult;
|
|
4886
|
+
/**
|
|
4887
|
+
* Register, verify or repair the workspace's risk sweep with the platform
|
|
4888
|
+
* scheduler. Idempotent; leaves a job an operator paused alone.
|
|
4889
|
+
*/
|
|
4890
|
+
mtwEnsureRiskSweepSchedule?: Maybe<MtwRiskSweepSchedule>;
|
|
4891
|
+
/**
|
|
4892
|
+
* Generate (or reuse) the AI narration for a shipment's current risk forecast
|
|
4893
|
+
* and return the forecast with it attached. With AI disabled, credits spent or
|
|
4894
|
+
* the daily cap reached, this returns the deterministic forecast unchanged and
|
|
4895
|
+
* makes no model call; `narrationStatus` says why.
|
|
4896
|
+
*/
|
|
4897
|
+
mtwNarrateShipmentRiskForecast: MtwRiskForecast;
|
|
4898
|
+
/**
|
|
4899
|
+
* Re-forecast every in-flight shipment of the workspace and notify for any that
|
|
4900
|
+
* started slipping. Fired by wspace-scheduler-svc as this service's own service
|
|
4901
|
+
* actor; a workspace user may also run it on demand.
|
|
4902
|
+
*/
|
|
4903
|
+
mtwRunRiskSweep: MtwRiskSweep;
|
|
4655
4904
|
openMtwContainerCycle: MtwContainerCycle;
|
|
4656
4905
|
openMtwFreeTimeClock: MtwFreeTimeClock;
|
|
4657
4906
|
optimizeRoute: MtwRoute;
|
|
@@ -4697,6 +4946,8 @@ export type Mutation = {
|
|
|
4697
4946
|
updateDriverStatus: MtwDriver;
|
|
4698
4947
|
updateIntegration: MtwIntegration;
|
|
4699
4948
|
updateInventoryItem: MtwInventoryItem;
|
|
4949
|
+
/** Switch customer notifications on or off and choose channels and events. */
|
|
4950
|
+
updateMtwCustomerNotificationSettings: MtwCustomerNotificationSettings;
|
|
4700
4951
|
/** Save the workspace's MoveTheWheels operational defaults. Every field is validated. */
|
|
4701
4952
|
updateMtwModuleSettings: MtwModuleSettings;
|
|
4702
4953
|
updateRoute: MtwRoute;
|
|
@@ -4947,6 +5198,16 @@ export type MutationImportMtwWarehousesArgs = {
|
|
|
4947
5198
|
};
|
|
4948
5199
|
|
|
4949
5200
|
|
|
5201
|
+
export type MutationMtwNarrateShipmentRiskForecastArgs = {
|
|
5202
|
+
shipmentId: Scalars['ID']['input'];
|
|
5203
|
+
};
|
|
5204
|
+
|
|
5205
|
+
|
|
5206
|
+
export type MutationMtwRunRiskSweepArgs = {
|
|
5207
|
+
input?: InputMaybe<MtwRunRiskSweepInput>;
|
|
5208
|
+
};
|
|
5209
|
+
|
|
5210
|
+
|
|
4950
5211
|
export type MutationOpenMtwContainerCycleArgs = {
|
|
4951
5212
|
input: OpenMtwContainerCycleInput;
|
|
4952
5213
|
};
|
|
@@ -5182,6 +5443,11 @@ export type MutationUpdateInventoryItemArgs = {
|
|
|
5182
5443
|
};
|
|
5183
5444
|
|
|
5184
5445
|
|
|
5446
|
+
export type MutationUpdateMtwCustomerNotificationSettingsArgs = {
|
|
5447
|
+
input: UpdateMtwCustomerNotificationSettingsInput;
|
|
5448
|
+
};
|
|
5449
|
+
|
|
5450
|
+
|
|
5185
5451
|
export type MutationUpdateMtwModuleSettingsArgs = {
|
|
5186
5452
|
input: UpdateMtwModuleSettingsInput;
|
|
5187
5453
|
};
|
|
@@ -5400,6 +5666,12 @@ export type Query = {
|
|
|
5400
5666
|
mtwContainerReleaseDecisionPage: MtwContainerReleaseDecisionPage;
|
|
5401
5667
|
mtwContainerRepairPage: MtwContainerRepairPage;
|
|
5402
5668
|
mtwContainers: Array<MtwContainer>;
|
|
5669
|
+
/** Sample messages for each event, signed with this workspace's name. */
|
|
5670
|
+
mtwCustomerNotificationPreviews: Array<MtwCustomerNotificationPreview>;
|
|
5671
|
+
/** This workspace's customer notification settings; off when none were saved. */
|
|
5672
|
+
mtwCustomerNotificationSettings: MtwCustomerNotificationSettings;
|
|
5673
|
+
/** Customer notifications sent or attempted in this workspace, newest first. */
|
|
5674
|
+
mtwCustomerNotifications: MtwCustomerNotificationPage;
|
|
5403
5675
|
/** Exact immutable instruction, including a proposal's historical owner; not a current-eligibility claim. */
|
|
5404
5676
|
mtwEmptyReturnInstruction: MtwEmptyReturnInstruction;
|
|
5405
5677
|
mtwEmptyReturnInstructionPage: MtwEmptyReturnInstructionPage;
|
|
@@ -5439,6 +5711,12 @@ export type Query = {
|
|
|
5439
5711
|
mtwReuseProposalPage: MtwReuseProposalPage;
|
|
5440
5712
|
mtwReuseReservationPage: MtwReuseReservationPage;
|
|
5441
5713
|
mtwReuseReservationTransitionPage: MtwReuseReservationTransitionPage;
|
|
5714
|
+
/** The workspace's risk-sweep registration with the platform scheduler, if any. */
|
|
5715
|
+
mtwRiskSweepSchedule?: Maybe<MtwRiskSweepSchedule>;
|
|
5716
|
+
/** Recent risk sweeps of the workspace, newest first. */
|
|
5717
|
+
mtwRiskSweeps: Array<MtwRiskSweep>;
|
|
5718
|
+
/** The shipment's current or last risk episode, or null if it has never been at risk. */
|
|
5719
|
+
mtwShipmentRiskEpisode?: Maybe<MtwShipmentRiskEpisode>;
|
|
5442
5720
|
mtwShipmentRiskForecast: MtwRiskForecast;
|
|
5443
5721
|
mtwStockBindingAssessment: MtwStockBindingAssessment;
|
|
5444
5722
|
mtwStockBindingAssessmentPage: MtwStockBindingAssessmentPage;
|
|
@@ -5773,6 +6051,12 @@ export type QueryMtwContainersArgs = {
|
|
|
5773
6051
|
};
|
|
5774
6052
|
|
|
5775
6053
|
|
|
6054
|
+
export type QueryMtwCustomerNotificationsArgs = {
|
|
6055
|
+
filter?: InputMaybe<MtwCustomerNotificationFilterInput>;
|
|
6056
|
+
pagination?: InputMaybe<PaginationInput>;
|
|
6057
|
+
};
|
|
6058
|
+
|
|
6059
|
+
|
|
5776
6060
|
export type QueryMtwEmptyReturnInstructionArgs = {
|
|
5777
6061
|
id: Scalars['ID']['input'];
|
|
5778
6062
|
};
|
|
@@ -5940,6 +6224,16 @@ export type QueryMtwReuseReservationTransitionPageArgs = {
|
|
|
5940
6224
|
};
|
|
5941
6225
|
|
|
5942
6226
|
|
|
6227
|
+
export type QueryMtwRiskSweepsArgs = {
|
|
6228
|
+
pagination?: InputMaybe<PaginationInput>;
|
|
6229
|
+
};
|
|
6230
|
+
|
|
6231
|
+
|
|
6232
|
+
export type QueryMtwShipmentRiskEpisodeArgs = {
|
|
6233
|
+
shipmentId: Scalars['ID']['input'];
|
|
6234
|
+
};
|
|
6235
|
+
|
|
6236
|
+
|
|
5943
6237
|
export type QueryMtwShipmentRiskForecastArgs = {
|
|
5944
6238
|
shipmentId: Scalars['ID']['input'];
|
|
5945
6239
|
};
|
|
@@ -6617,6 +6911,8 @@ export type UpdateCustomerInput = {
|
|
|
6617
6911
|
context?: InputMaybe<ContextInput>;
|
|
6618
6912
|
email?: InputMaybe<Scalars['String']['input']>;
|
|
6619
6913
|
name?: InputMaybe<Scalars['String']['input']>;
|
|
6914
|
+
notifyByEmail?: InputMaybe<Scalars['Boolean']['input']>;
|
|
6915
|
+
notifyBySms?: InputMaybe<Scalars['Boolean']['input']>;
|
|
6620
6916
|
phone?: InputMaybe<Scalars['String']['input']>;
|
|
6621
6917
|
rating?: InputMaybe<Scalars['Float']['input']>;
|
|
6622
6918
|
taxId?: InputMaybe<Scalars['String']['input']>;
|
|
@@ -6695,6 +6991,14 @@ export type UpdateInventoryItemInput = {
|
|
|
6695
6991
|
unitCost?: InputMaybe<Scalars['Float']['input']>;
|
|
6696
6992
|
};
|
|
6697
6993
|
|
|
6994
|
+
/** Changes to the customer notification settings. Omitted fields keep their value. */
|
|
6995
|
+
export type UpdateMtwCustomerNotificationSettingsInput = {
|
|
6996
|
+
emailEnabled?: InputMaybe<Scalars['Boolean']['input']>;
|
|
6997
|
+
enabled?: InputMaybe<Scalars['Boolean']['input']>;
|
|
6998
|
+
events?: InputMaybe<Array<MtwCustomerNotificationEvent>>;
|
|
6999
|
+
smsEnabled?: InputMaybe<Scalars['Boolean']['input']>;
|
|
7000
|
+
};
|
|
7001
|
+
|
|
6698
7002
|
/**
|
|
6699
7003
|
* Changes to the workspace's MoveTheWheels defaults. Omitted fields keep their
|
|
6700
7004
|
* current value. `timezone: null` (or an empty string) clears the time zone so
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A customer's delivery notification preferences (BOFF-4402): whether they
|
|
3
|
+
* get shipment updates by email and by SMS. Used by the new and edit customer
|
|
4
|
+
* forms. The workspace must also switch customer notifications on in Settings.
|
|
5
|
+
*/
|
|
6
|
+
import { Checkbox, Label } from './ui';
|
|
7
|
+
|
|
8
|
+
export interface DeliveryUpdatesValue {
|
|
9
|
+
notifyByEmail: boolean;
|
|
10
|
+
notifyBySms: boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function CustomerDeliveryUpdatesFields({
|
|
14
|
+
idPrefix,
|
|
15
|
+
value,
|
|
16
|
+
onChange,
|
|
17
|
+
disabled,
|
|
18
|
+
}: {
|
|
19
|
+
idPrefix: string;
|
|
20
|
+
value: DeliveryUpdatesValue;
|
|
21
|
+
onChange: (next: DeliveryUpdatesValue) => void;
|
|
22
|
+
disabled?: boolean;
|
|
23
|
+
}) {
|
|
24
|
+
return (
|
|
25
|
+
<fieldset
|
|
26
|
+
className="space-y-3"
|
|
27
|
+
disabled={disabled}
|
|
28
|
+
data-testid={`${idPrefix}-delivery-updates`}
|
|
29
|
+
>
|
|
30
|
+
<legend className="text-sm font-medium text-text-primary">Delivery updates</legend>
|
|
31
|
+
<div className="flex items-start gap-2">
|
|
32
|
+
<Checkbox
|
|
33
|
+
id={`${idPrefix}-notify-email`}
|
|
34
|
+
checked={value.notifyByEmail}
|
|
35
|
+
disabled={disabled}
|
|
36
|
+
onCheckedChange={(checked) => onChange({ ...value, notifyByEmail: checked === true })}
|
|
37
|
+
/>
|
|
38
|
+
<Label htmlFor={`${idPrefix}-notify-email`} className="text-sm font-normal leading-snug">
|
|
39
|
+
Email this customer about their shipments
|
|
40
|
+
</Label>
|
|
41
|
+
</div>
|
|
42
|
+
<div className="flex items-start gap-2">
|
|
43
|
+
<Checkbox
|
|
44
|
+
id={`${idPrefix}-notify-sms`}
|
|
45
|
+
checked={value.notifyBySms}
|
|
46
|
+
disabled={disabled}
|
|
47
|
+
onCheckedChange={(checked) => onChange({ ...value, notifyBySms: checked === true })}
|
|
48
|
+
/>
|
|
49
|
+
<Label htmlFor={`${idPrefix}-notify-sms`} className="text-sm font-normal leading-snug">
|
|
50
|
+
Text this customer about their shipments (only with their consent; the phone number needs
|
|
51
|
+
its country code, e.g. +91…)
|
|
52
|
+
</Label>
|
|
53
|
+
</div>
|
|
54
|
+
<p className="text-xs text-text-secondary">
|
|
55
|
+
Sent only while customer delivery notifications are on in Settings.
|
|
56
|
+
</p>
|
|
57
|
+
</fieldset>
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** "Email and SMS", "Email", "SMS" or "Off". */
|
|
62
|
+
export function deliveryUpdatesSummary(value: DeliveryUpdatesValue): string {
|
|
63
|
+
if (value.notifyByEmail && value.notifyBySms) return 'Email and SMS';
|
|
64
|
+
if (value.notifyByEmail) return 'Email';
|
|
65
|
+
if (value.notifyBySms) return 'SMS';
|
|
66
|
+
return 'Off';
|
|
67
|
+
}
|