@burdenoff/microfe-movethewheels 2026.1026.2 → 2026.1026.3
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/MoveTheWheelsRoot.js +126 -159
- package/dist/MoveTheWheelsRoutes.js +16 -32
- package/dist/hooks/index.js +0 -3
- package/dist/index.js +27 -30
- package/dist/movethewheels/hooks/index.d.ts +0 -3
- package/package.json +1 -1
- package/src/movethewheels/MoveTheWheelsRoot.tsx +2 -46
- package/src/movethewheels/MoveTheWheelsRoutes.tsx +0 -16
- package/src/movethewheels/hooks/index.ts +0 -9
- package/dist/hooks/useImportExport.js +0 -27
- package/dist/hooks/useReports.js +0 -75
- package/dist/hooks/useSettings.js +0 -67
- package/dist/movethewheels/hooks/useImportExport.d.ts +0 -23
- package/dist/movethewheels/hooks/useReports.d.ts +0 -39
- package/dist/movethewheels/hooks/useSettings.d.ts +0 -17
- package/dist/movethewheels/pages/ImportExportPage.d.ts +0 -8
- package/dist/movethewheels/pages/MarketplacePage.d.ts +0 -12
- package/dist/movethewheels/pages/ReportsPage.d.ts +0 -8
- package/dist/movethewheels/pages/SettingsPage.d.ts +0 -8
- package/dist/node_modules/lucide-react/dist/esm/icons/bell.js +0 -11
- package/dist/node_modules/lucide-react/dist/esm/icons/file-chart-column-increasing.js +0 -26
- package/dist/node_modules/lucide-react/dist/esm/icons/file-spreadsheet.js +0 -30
- package/dist/node_modules/lucide-react/dist/esm/icons/globe.js +0 -20
- package/dist/node_modules/lucide-react/dist/esm/icons/settings.js +0 -13
- package/dist/node_modules/lucide-react/dist/esm/icons/shield.js +0 -8
- package/dist/node_modules/lucide-react/dist/esm/icons/store.js +0 -26
- package/dist/node_modules/lucide-react/dist/esm/icons/webhook.js +0 -18
- package/dist/pages/ImportExportPage.js +0 -245
- package/dist/pages/MarketplacePage.js +0 -23
- package/dist/pages/ReportsPage.js +0 -328
- package/dist/pages/SettingsPage.js +0 -404
- package/dist/utils/download.js +0 -22
- package/src/movethewheels/hooks/useImportExport.ts +0 -65
- package/src/movethewheels/hooks/useReports.ts +0 -154
- package/src/movethewheels/hooks/useSettings.ts +0 -124
- package/src/movethewheels/pages/ImportExportPage.tsx +0 -288
- package/src/movethewheels/pages/MarketplacePage.tsx +0 -36
- package/src/movethewheels/pages/ReportsPage.tsx +0 -379
- package/src/movethewheels/pages/SettingsPage.tsx +0 -548
- package/src/operations/wspace/movethewheels/fragments/core.withdrawn.graphql +0 -59
- package/src/operations/wspace/movethewheels/mutations/marketplace-reports.withdrawn.graphql +0 -93
- package/src/operations/wspace/movethewheels/queries/marketplace-reports.withdrawn.graphql +0 -58
|
@@ -1,548 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Settings Page
|
|
3
|
-
*
|
|
4
|
-
* Loads persisted module settings (Query.moduleSettings.preferences) and saves
|
|
5
|
-
* changes via updateModuleSettings. Integrations read "Not configured" until a
|
|
6
|
-
* real connection is recorded — no fabricated "Connected" statuses.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import { useEffect, useMemo, useState } from 'react';
|
|
10
|
-
import { Settings, User, Bell, Shield, Globe, Webhook, Save } from 'lucide-react';
|
|
11
|
-
import { PageLayout } from '../components/PageLayout';
|
|
12
|
-
import {
|
|
13
|
-
Card,
|
|
14
|
-
CardContent,
|
|
15
|
-
CardHeader,
|
|
16
|
-
CardTitle,
|
|
17
|
-
CardDescription,
|
|
18
|
-
Button,
|
|
19
|
-
Input,
|
|
20
|
-
Label,
|
|
21
|
-
Switch,
|
|
22
|
-
Select,
|
|
23
|
-
SelectContent,
|
|
24
|
-
SelectItem,
|
|
25
|
-
SelectTrigger,
|
|
26
|
-
SelectValue,
|
|
27
|
-
Tabs,
|
|
28
|
-
TabsList,
|
|
29
|
-
TabsTrigger,
|
|
30
|
-
TabsContent,
|
|
31
|
-
} from '../components/ui';
|
|
32
|
-
import { EmphasisPanel, PagePurpose, NextSteps } from '@burdenoff/fe-libs/ui';
|
|
33
|
-
import { useModuleSettings, type ModulePreferences } from '../hooks/useSettings';
|
|
34
|
-
import { useTr } from '../hooks';
|
|
35
|
-
|
|
36
|
-
interface CompanyPrefs {
|
|
37
|
-
name: string;
|
|
38
|
-
email: string;
|
|
39
|
-
phone: string;
|
|
40
|
-
website: string;
|
|
41
|
-
}
|
|
42
|
-
interface LocalizationPrefs {
|
|
43
|
-
timezone: string;
|
|
44
|
-
currency: string;
|
|
45
|
-
language: string;
|
|
46
|
-
}
|
|
47
|
-
interface NotificationPrefs {
|
|
48
|
-
orderUpdates: boolean;
|
|
49
|
-
deliveryAlerts: boolean;
|
|
50
|
-
systemNotifications: boolean;
|
|
51
|
-
weeklyReports: boolean;
|
|
52
|
-
}
|
|
53
|
-
interface SettingsForm {
|
|
54
|
-
company: CompanyPrefs;
|
|
55
|
-
localization: LocalizationPrefs;
|
|
56
|
-
notifications: NotificationPrefs;
|
|
57
|
-
twoFactorEnabled: boolean;
|
|
58
|
-
integrations: Record<string, boolean>;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
function toForm(preferences: ModulePreferences): SettingsForm {
|
|
62
|
-
const company = (preferences.company as Partial<CompanyPrefs> | undefined) ?? {};
|
|
63
|
-
const localization = (preferences.localization as Partial<LocalizationPrefs> | undefined) ?? {};
|
|
64
|
-
const notifications = (preferences.notifications as Partial<NotificationPrefs> | undefined) ?? {};
|
|
65
|
-
const security = (preferences.security as { twoFactorEnabled?: boolean } | undefined) ?? {};
|
|
66
|
-
const integrations = (preferences.integrations as Record<string, boolean> | undefined) ?? {};
|
|
67
|
-
return {
|
|
68
|
-
company: {
|
|
69
|
-
name: company.name ?? '',
|
|
70
|
-
email: company.email ?? '',
|
|
71
|
-
phone: company.phone ?? '',
|
|
72
|
-
website: company.website ?? '',
|
|
73
|
-
},
|
|
74
|
-
localization: {
|
|
75
|
-
timezone: localization.timezone ?? 'utc',
|
|
76
|
-
currency: localization.currency ?? 'usd',
|
|
77
|
-
language: localization.language ?? 'en',
|
|
78
|
-
},
|
|
79
|
-
notifications: {
|
|
80
|
-
orderUpdates: notifications.orderUpdates ?? true,
|
|
81
|
-
deliveryAlerts: notifications.deliveryAlerts ?? true,
|
|
82
|
-
systemNotifications: notifications.systemNotifications ?? true,
|
|
83
|
-
weeklyReports: notifications.weeklyReports ?? false,
|
|
84
|
-
},
|
|
85
|
-
twoFactorEnabled: security.twoFactorEnabled ?? false,
|
|
86
|
-
integrations,
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
export default function SettingsPage() {
|
|
91
|
-
const tr = useTr();
|
|
92
|
-
const { preferences, isLoading, isSaving, error, savePreferences } = useModuleSettings();
|
|
93
|
-
const [tab, setTab] = useState('general');
|
|
94
|
-
const [form, setForm] = useState<SettingsForm>(() => toForm({}));
|
|
95
|
-
const [saved, setSaved] = useState(false);
|
|
96
|
-
|
|
97
|
-
const integrations = useMemo(
|
|
98
|
-
() => [
|
|
99
|
-
{
|
|
100
|
-
key: 'googleMaps',
|
|
101
|
-
name: tr('movethewheels.settings.integrations.googleMaps', 'Google Maps'),
|
|
102
|
-
},
|
|
103
|
-
{ key: 'stripe', name: tr('movethewheels.settings.integrations.stripe', 'Stripe') },
|
|
104
|
-
{ key: 'twilio', name: tr('movethewheels.settings.integrations.twilio', 'Twilio') },
|
|
105
|
-
],
|
|
106
|
-
[tr]
|
|
107
|
-
);
|
|
108
|
-
|
|
109
|
-
const notificationItems: { key: keyof NotificationPrefs; label: string; desc: string }[] =
|
|
110
|
-
useMemo(
|
|
111
|
-
() => [
|
|
112
|
-
{
|
|
113
|
-
key: 'orderUpdates',
|
|
114
|
-
label: tr('movethewheels.settings.notifications.orderUpdates.label', 'Order updates'),
|
|
115
|
-
desc: tr(
|
|
116
|
-
'movethewheels.settings.notifications.orderUpdates.desc',
|
|
117
|
-
'Receive notifications for order status changes'
|
|
118
|
-
),
|
|
119
|
-
},
|
|
120
|
-
{
|
|
121
|
-
key: 'deliveryAlerts',
|
|
122
|
-
label: tr('movethewheels.settings.notifications.deliveryAlerts.label', 'Delivery alerts'),
|
|
123
|
-
desc: tr(
|
|
124
|
-
'movethewheels.settings.notifications.deliveryAlerts.desc',
|
|
125
|
-
'Get notified about delivery issues'
|
|
126
|
-
),
|
|
127
|
-
},
|
|
128
|
-
{
|
|
129
|
-
key: 'systemNotifications',
|
|
130
|
-
label: tr(
|
|
131
|
-
'movethewheels.settings.notifications.systemNotifications.label',
|
|
132
|
-
'System notifications'
|
|
133
|
-
),
|
|
134
|
-
desc: tr(
|
|
135
|
-
'movethewheels.settings.notifications.systemNotifications.desc',
|
|
136
|
-
'Important system updates and maintenance'
|
|
137
|
-
),
|
|
138
|
-
},
|
|
139
|
-
{
|
|
140
|
-
key: 'weeklyReports',
|
|
141
|
-
label: tr('movethewheels.settings.notifications.weeklyReports.label', 'Weekly reports'),
|
|
142
|
-
desc: tr(
|
|
143
|
-
'movethewheels.settings.notifications.weeklyReports.desc',
|
|
144
|
-
'Receive weekly performance summary'
|
|
145
|
-
),
|
|
146
|
-
},
|
|
147
|
-
],
|
|
148
|
-
[tr]
|
|
149
|
-
);
|
|
150
|
-
|
|
151
|
-
const loadedForm = useMemo(() => toForm(preferences), [preferences]);
|
|
152
|
-
useEffect(() => {
|
|
153
|
-
setForm(loadedForm);
|
|
154
|
-
}, [loadedForm]);
|
|
155
|
-
|
|
156
|
-
const patchCompany = (patch: Partial<CompanyPrefs>) =>
|
|
157
|
-
setForm((prev) => ({ ...prev, company: { ...prev.company, ...patch } }));
|
|
158
|
-
const patchLocalization = (patch: Partial<LocalizationPrefs>) =>
|
|
159
|
-
setForm((prev) => ({ ...prev, localization: { ...prev.localization, ...patch } }));
|
|
160
|
-
const toggleNotification = (key: keyof NotificationPrefs, value: boolean) =>
|
|
161
|
-
setForm((prev) => ({ ...prev, notifications: { ...prev.notifications, [key]: value } }));
|
|
162
|
-
|
|
163
|
-
const handleSave = async () => {
|
|
164
|
-
setSaved(false);
|
|
165
|
-
try {
|
|
166
|
-
await savePreferences({
|
|
167
|
-
company: form.company,
|
|
168
|
-
localization: form.localization,
|
|
169
|
-
notifications: form.notifications,
|
|
170
|
-
security: { twoFactorEnabled: form.twoFactorEnabled },
|
|
171
|
-
integrations: form.integrations,
|
|
172
|
-
});
|
|
173
|
-
setSaved(true);
|
|
174
|
-
} catch {
|
|
175
|
-
// error surfaced via the hook's `error`
|
|
176
|
-
}
|
|
177
|
-
};
|
|
178
|
-
|
|
179
|
-
return (
|
|
180
|
-
<PageLayout
|
|
181
|
-
title={tr('movethewheels.settings.title', 'Settings')}
|
|
182
|
-
subtitle={tr('movethewheels.settings.subtitle', 'Manage your account and preferences')}
|
|
183
|
-
icon={<Settings size={24} />}
|
|
184
|
-
>
|
|
185
|
-
<PagePurpose icon={<Settings size={18} />}>
|
|
186
|
-
{tr(
|
|
187
|
-
'movethewheels.settings.purpose',
|
|
188
|
-
'Configure how MoveTheWheels works for your business — company details and localization, which notifications you receive, account security, and the integrations (maps, payments, messaging) that power deliveries. Set these once so the rest of the app behaves the way you expect.'
|
|
189
|
-
)}
|
|
190
|
-
</PagePurpose>
|
|
191
|
-
|
|
192
|
-
{(saved || error) && (
|
|
193
|
-
<div
|
|
194
|
-
role="status"
|
|
195
|
-
className={`rounded-lg p-3 text-sm ${
|
|
196
|
-
error
|
|
197
|
-
? 'bg-status-error-bg-subtle text-status-error-text'
|
|
198
|
-
: 'bg-status-success-bg-subtle text-status-success-text'
|
|
199
|
-
}`}
|
|
200
|
-
>
|
|
201
|
-
{error ? error.message : tr('movethewheels.settings.saved', 'Settings saved.')}
|
|
202
|
-
</div>
|
|
203
|
-
)}
|
|
204
|
-
|
|
205
|
-
<NextSteps
|
|
206
|
-
storageKey="movethewheels-settings"
|
|
207
|
-
steps={[
|
|
208
|
-
{
|
|
209
|
-
id: 'company',
|
|
210
|
-
label: tr(
|
|
211
|
-
'movethewheels.settings.nextSteps.company.label',
|
|
212
|
-
'Confirm company details & localization'
|
|
213
|
-
),
|
|
214
|
-
description: tr(
|
|
215
|
-
'movethewheels.settings.nextSteps.company.description',
|
|
216
|
-
'Set your name, contact info, timezone, currency and language.'
|
|
217
|
-
),
|
|
218
|
-
icon: <User size={16} />,
|
|
219
|
-
onClick: () => setTab('general'),
|
|
220
|
-
},
|
|
221
|
-
{
|
|
222
|
-
id: 'notifications',
|
|
223
|
-
label: tr(
|
|
224
|
-
'movethewheels.settings.nextSteps.notifications.label',
|
|
225
|
-
'Choose your notifications'
|
|
226
|
-
),
|
|
227
|
-
description: tr(
|
|
228
|
-
'movethewheels.settings.nextSteps.notifications.description',
|
|
229
|
-
'Decide which order, delivery and report emails you receive.'
|
|
230
|
-
),
|
|
231
|
-
icon: <Bell size={16} />,
|
|
232
|
-
onClick: () => setTab('notifications'),
|
|
233
|
-
},
|
|
234
|
-
{
|
|
235
|
-
id: 'security',
|
|
236
|
-
label: tr('movethewheels.settings.nextSteps.security.label', 'Secure your account'),
|
|
237
|
-
description: tr(
|
|
238
|
-
'movethewheels.settings.nextSteps.security.description',
|
|
239
|
-
'Enable two-factor authentication for an extra layer of security.'
|
|
240
|
-
),
|
|
241
|
-
icon: <Shield size={16} />,
|
|
242
|
-
onClick: () => setTab('security'),
|
|
243
|
-
},
|
|
244
|
-
{
|
|
245
|
-
id: 'integrations',
|
|
246
|
-
label: tr('movethewheels.settings.nextSteps.integrations.label', 'Connect your tools'),
|
|
247
|
-
description: tr(
|
|
248
|
-
'movethewheels.settings.nextSteps.integrations.description',
|
|
249
|
-
'Link maps, payments and messaging providers.'
|
|
250
|
-
),
|
|
251
|
-
icon: <Webhook size={16} />,
|
|
252
|
-
onClick: () => setTab('integrations'),
|
|
253
|
-
},
|
|
254
|
-
]}
|
|
255
|
-
/>
|
|
256
|
-
|
|
257
|
-
<Tabs value={tab} onValueChange={setTab}>
|
|
258
|
-
<TabsList className="mb-6">
|
|
259
|
-
<TabsTrigger value="general">
|
|
260
|
-
<User size={16} /> {tr('movethewheels.settings.tabs.general', 'General')}
|
|
261
|
-
</TabsTrigger>
|
|
262
|
-
<TabsTrigger value="notifications">
|
|
263
|
-
<Bell size={16} /> {tr('movethewheels.settings.tabs.notifications', 'Notifications')}
|
|
264
|
-
</TabsTrigger>
|
|
265
|
-
<TabsTrigger value="security">
|
|
266
|
-
<Shield size={16} /> {tr('movethewheels.settings.tabs.security', 'Security')}
|
|
267
|
-
</TabsTrigger>
|
|
268
|
-
<TabsTrigger value="integrations">
|
|
269
|
-
<Webhook size={16} /> {tr('movethewheels.settings.tabs.integrations', 'Integrations')}
|
|
270
|
-
</TabsTrigger>
|
|
271
|
-
</TabsList>
|
|
272
|
-
|
|
273
|
-
<TabsContent value="general" className="space-y-6">
|
|
274
|
-
{/* Company Information — the page's single emphasis zone */}
|
|
275
|
-
<EmphasisPanel>
|
|
276
|
-
<h2 className="text-base font-semibold text-text-primary">
|
|
277
|
-
{tr('movethewheels.settings.company.title', 'Company Information')}
|
|
278
|
-
</h2>
|
|
279
|
-
<p className="text-sm text-text-secondary mb-4">
|
|
280
|
-
{tr('movethewheels.settings.company.basicDetails', 'Basic company details')}
|
|
281
|
-
</p>
|
|
282
|
-
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
|
283
|
-
<div>
|
|
284
|
-
<Label>{tr('movethewheels.settings.company.name', 'Company Name')}</Label>
|
|
285
|
-
<Input
|
|
286
|
-
value={form.company.name}
|
|
287
|
-
placeholder={tr(
|
|
288
|
-
'movethewheels.settings.company.placeholders.name',
|
|
289
|
-
'Your company name'
|
|
290
|
-
)}
|
|
291
|
-
disabled={isLoading}
|
|
292
|
-
onChange={(e) => patchCompany({ name: e.target.value })}
|
|
293
|
-
/>
|
|
294
|
-
</div>
|
|
295
|
-
<div>
|
|
296
|
-
<Label>{tr('movethewheels.settings.company.email', 'Contact Email')}</Label>
|
|
297
|
-
<Input
|
|
298
|
-
type="email"
|
|
299
|
-
value={form.company.email}
|
|
300
|
-
placeholder={tr(
|
|
301
|
-
'movethewheels.settings.company.placeholders.email',
|
|
302
|
-
'contact@example.com'
|
|
303
|
-
)}
|
|
304
|
-
disabled={isLoading}
|
|
305
|
-
onChange={(e) => patchCompany({ email: e.target.value })}
|
|
306
|
-
/>
|
|
307
|
-
</div>
|
|
308
|
-
<div>
|
|
309
|
-
<Label>{tr('movethewheels.settings.company.phone', 'Phone')}</Label>
|
|
310
|
-
<Input
|
|
311
|
-
value={form.company.phone}
|
|
312
|
-
placeholder={tr(
|
|
313
|
-
'movethewheels.settings.company.placeholders.phone',
|
|
314
|
-
'+1-555-0100'
|
|
315
|
-
)}
|
|
316
|
-
disabled={isLoading}
|
|
317
|
-
onChange={(e) => patchCompany({ phone: e.target.value })}
|
|
318
|
-
/>
|
|
319
|
-
</div>
|
|
320
|
-
<div>
|
|
321
|
-
<Label>{tr('movethewheels.settings.company.website', 'Website')}</Label>
|
|
322
|
-
<Input
|
|
323
|
-
value={form.company.website}
|
|
324
|
-
placeholder={tr(
|
|
325
|
-
'movethewheels.settings.company.placeholders.website',
|
|
326
|
-
'https://example.com'
|
|
327
|
-
)}
|
|
328
|
-
disabled={isLoading}
|
|
329
|
-
onChange={(e) => patchCompany({ website: e.target.value })}
|
|
330
|
-
/>
|
|
331
|
-
</div>
|
|
332
|
-
</div>
|
|
333
|
-
</EmphasisPanel>
|
|
334
|
-
|
|
335
|
-
<Card>
|
|
336
|
-
<CardHeader>
|
|
337
|
-
<CardTitle className="flex items-center gap-2">
|
|
338
|
-
<Globe size={18} />{' '}
|
|
339
|
-
{tr('movethewheels.settings.localization.title', 'Localization')}
|
|
340
|
-
</CardTitle>
|
|
341
|
-
</CardHeader>
|
|
342
|
-
<CardContent className="space-y-4">
|
|
343
|
-
<div className="grid grid-cols-1 sm:grid-cols-3 gap-4">
|
|
344
|
-
<div>
|
|
345
|
-
<Label>{tr('movethewheels.settings.localization.timezone', 'Timezone')}</Label>
|
|
346
|
-
<Select
|
|
347
|
-
value={form.localization.timezone}
|
|
348
|
-
onValueChange={(value) => patchLocalization({ timezone: value })}
|
|
349
|
-
>
|
|
350
|
-
<SelectTrigger>
|
|
351
|
-
<SelectValue />
|
|
352
|
-
</SelectTrigger>
|
|
353
|
-
<SelectContent>
|
|
354
|
-
<SelectItem value="pst">Pacific Time (PST)</SelectItem>
|
|
355
|
-
<SelectItem value="est">Eastern Time (EST)</SelectItem>
|
|
356
|
-
<SelectItem value="utc">UTC</SelectItem>
|
|
357
|
-
</SelectContent>
|
|
358
|
-
</Select>
|
|
359
|
-
</div>
|
|
360
|
-
<div>
|
|
361
|
-
<Label>{tr('movethewheels.settings.localization.currency', 'Currency')}</Label>
|
|
362
|
-
<Select
|
|
363
|
-
value={form.localization.currency}
|
|
364
|
-
onValueChange={(value) => patchLocalization({ currency: value })}
|
|
365
|
-
>
|
|
366
|
-
<SelectTrigger>
|
|
367
|
-
<SelectValue />
|
|
368
|
-
</SelectTrigger>
|
|
369
|
-
<SelectContent>
|
|
370
|
-
<SelectItem value="usd">USD ($)</SelectItem>
|
|
371
|
-
<SelectItem value="eur">EUR (€)</SelectItem>
|
|
372
|
-
<SelectItem value="gbp">GBP (£)</SelectItem>
|
|
373
|
-
</SelectContent>
|
|
374
|
-
</Select>
|
|
375
|
-
</div>
|
|
376
|
-
<div>
|
|
377
|
-
<Label>{tr('movethewheels.settings.localization.language', 'Language')}</Label>
|
|
378
|
-
<Select
|
|
379
|
-
value={form.localization.language}
|
|
380
|
-
onValueChange={(value) => patchLocalization({ language: value })}
|
|
381
|
-
>
|
|
382
|
-
<SelectTrigger>
|
|
383
|
-
<SelectValue />
|
|
384
|
-
</SelectTrigger>
|
|
385
|
-
<SelectContent>
|
|
386
|
-
<SelectItem value="en">English</SelectItem>
|
|
387
|
-
<SelectItem value="es">Spanish</SelectItem>
|
|
388
|
-
<SelectItem value="fr">French</SelectItem>
|
|
389
|
-
</SelectContent>
|
|
390
|
-
</Select>
|
|
391
|
-
</div>
|
|
392
|
-
</div>
|
|
393
|
-
</CardContent>
|
|
394
|
-
</Card>
|
|
395
|
-
</TabsContent>
|
|
396
|
-
|
|
397
|
-
<TabsContent value="notifications" className="space-y-6">
|
|
398
|
-
<Card>
|
|
399
|
-
<CardHeader>
|
|
400
|
-
<CardTitle>
|
|
401
|
-
{tr('movethewheels.settings.notifications.title', 'Email Notifications')}
|
|
402
|
-
</CardTitle>
|
|
403
|
-
</CardHeader>
|
|
404
|
-
<CardContent className="space-y-4">
|
|
405
|
-
{notificationItems.map((item) => (
|
|
406
|
-
<div key={item.key} className="flex items-center justify-between">
|
|
407
|
-
<div>
|
|
408
|
-
<p className="font-medium">{item.label}</p>
|
|
409
|
-
<p className="text-sm text-text-secondary">{item.desc}</p>
|
|
410
|
-
</div>
|
|
411
|
-
<Switch
|
|
412
|
-
checked={form.notifications[item.key]}
|
|
413
|
-
disabled={isLoading}
|
|
414
|
-
onCheckedChange={(value) => toggleNotification(item.key, value)}
|
|
415
|
-
/>
|
|
416
|
-
</div>
|
|
417
|
-
))}
|
|
418
|
-
</CardContent>
|
|
419
|
-
</Card>
|
|
420
|
-
</TabsContent>
|
|
421
|
-
|
|
422
|
-
<TabsContent value="security" className="space-y-6">
|
|
423
|
-
<Card>
|
|
424
|
-
<CardHeader>
|
|
425
|
-
<CardTitle>
|
|
426
|
-
{tr('movethewheels.settings.security.password.title', 'Password')}
|
|
427
|
-
</CardTitle>
|
|
428
|
-
<CardDescription>
|
|
429
|
-
{tr(
|
|
430
|
-
'movethewheels.settings.security.password.description',
|
|
431
|
-
'Your password and sign-in credentials are managed centrally by your workspace identity provider — update them from your account security settings, not here.'
|
|
432
|
-
)}
|
|
433
|
-
</CardDescription>
|
|
434
|
-
</CardHeader>
|
|
435
|
-
</Card>
|
|
436
|
-
<Card>
|
|
437
|
-
<CardHeader>
|
|
438
|
-
<CardTitle>
|
|
439
|
-
{tr('movethewheels.settings.security.twoFactor.title', 'Two-Factor Authentication')}
|
|
440
|
-
</CardTitle>
|
|
441
|
-
<CardDescription>
|
|
442
|
-
{tr(
|
|
443
|
-
'movethewheels.settings.security.twoFactor.description',
|
|
444
|
-
'Add an extra layer of security'
|
|
445
|
-
)}
|
|
446
|
-
</CardDescription>
|
|
447
|
-
</CardHeader>
|
|
448
|
-
<CardContent>
|
|
449
|
-
<div className="flex items-center justify-between">
|
|
450
|
-
<p>
|
|
451
|
-
{tr('movethewheels.settings.security.twoFactor.status', 'Status:')}{' '}
|
|
452
|
-
<span
|
|
453
|
-
className={`font-medium ${
|
|
454
|
-
form.twoFactorEnabled
|
|
455
|
-
? 'text-status-success-text'
|
|
456
|
-
: 'text-status-warning-text'
|
|
457
|
-
}`}
|
|
458
|
-
>
|
|
459
|
-
{form.twoFactorEnabled
|
|
460
|
-
? tr('movethewheels.settings.security.twoFactor.enabled', 'Enabled')
|
|
461
|
-
: tr('movethewheels.settings.security.twoFactor.disabled', 'Disabled')}
|
|
462
|
-
</span>
|
|
463
|
-
</p>
|
|
464
|
-
<Button
|
|
465
|
-
variant="outline"
|
|
466
|
-
disabled={isSaving}
|
|
467
|
-
onClick={() =>
|
|
468
|
-
setForm((prev) => ({ ...prev, twoFactorEnabled: !prev.twoFactorEnabled }))
|
|
469
|
-
}
|
|
470
|
-
>
|
|
471
|
-
{form.twoFactorEnabled
|
|
472
|
-
? tr('movethewheels.settings.security.twoFactor.disable', 'Disable 2FA')
|
|
473
|
-
: tr('movethewheels.settings.security.twoFactor.enable', 'Enable 2FA')}
|
|
474
|
-
</Button>
|
|
475
|
-
</div>
|
|
476
|
-
</CardContent>
|
|
477
|
-
</Card>
|
|
478
|
-
</TabsContent>
|
|
479
|
-
|
|
480
|
-
<TabsContent value="integrations" className="space-y-6">
|
|
481
|
-
<Card>
|
|
482
|
-
<CardHeader>
|
|
483
|
-
<CardTitle>
|
|
484
|
-
{tr('movethewheels.settings.integrations.title', 'Connected Services')}
|
|
485
|
-
</CardTitle>
|
|
486
|
-
<CardDescription>
|
|
487
|
-
{tr(
|
|
488
|
-
'movethewheels.settings.integrations.description',
|
|
489
|
-
'Connect the providers that power maps, payments and messaging.'
|
|
490
|
-
)}
|
|
491
|
-
</CardDescription>
|
|
492
|
-
</CardHeader>
|
|
493
|
-
<CardContent className="space-y-3">
|
|
494
|
-
{integrations.map((service) => {
|
|
495
|
-
const connected = form.integrations[service.key] === true;
|
|
496
|
-
return (
|
|
497
|
-
<div
|
|
498
|
-
key={service.key}
|
|
499
|
-
className="flex items-center justify-between p-3 border rounded-lg"
|
|
500
|
-
>
|
|
501
|
-
<div>
|
|
502
|
-
<span className="font-medium">{service.name}</span>
|
|
503
|
-
<p className="text-sm text-text-secondary">
|
|
504
|
-
{connected
|
|
505
|
-
? tr('movethewheels.settings.integrations.connected', 'Connected')
|
|
506
|
-
: tr(
|
|
507
|
-
'movethewheels.settings.integrations.notConfigured',
|
|
508
|
-
'Not configured'
|
|
509
|
-
)}
|
|
510
|
-
</p>
|
|
511
|
-
</div>
|
|
512
|
-
<Button
|
|
513
|
-
variant={connected ? 'outline' : 'default'}
|
|
514
|
-
size="sm"
|
|
515
|
-
disabled={isSaving}
|
|
516
|
-
onClick={() =>
|
|
517
|
-
setForm((prev) => ({
|
|
518
|
-
...prev,
|
|
519
|
-
integrations: {
|
|
520
|
-
...prev.integrations,
|
|
521
|
-
[service.key]: !connected,
|
|
522
|
-
},
|
|
523
|
-
}))
|
|
524
|
-
}
|
|
525
|
-
>
|
|
526
|
-
{connected
|
|
527
|
-
? tr('movethewheels.settings.integrations.disconnect', 'Disconnect')
|
|
528
|
-
: tr('movethewheels.settings.integrations.connect', 'Connect')}
|
|
529
|
-
</Button>
|
|
530
|
-
</div>
|
|
531
|
-
);
|
|
532
|
-
})}
|
|
533
|
-
</CardContent>
|
|
534
|
-
</Card>
|
|
535
|
-
</TabsContent>
|
|
536
|
-
</Tabs>
|
|
537
|
-
|
|
538
|
-
<div className="flex justify-end">
|
|
539
|
-
<Button onClick={() => void handleSave()} disabled={isSaving || isLoading}>
|
|
540
|
-
<Save size={16} />{' '}
|
|
541
|
-
{isSaving
|
|
542
|
-
? tr('movethewheels.settings.saving', 'Saving…')
|
|
543
|
-
: tr('movethewheels.settings.saveChanges', 'Save Changes')}
|
|
544
|
-
</Button>
|
|
545
|
-
</div>
|
|
546
|
-
</PageLayout>
|
|
547
|
-
);
|
|
548
|
-
}
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
# ─── Withdrawn service surface — preserved, not deleted ──────────────────────
|
|
2
|
-
#
|
|
3
|
-
# `ServiceProvider`, `ServiceOffering` and `MovethewheelsReport` were dropped
|
|
4
|
-
# from wspace-movethewheels-svc by migration
|
|
5
|
-
# `20260707000001_movethewheels_reuse_cleanup`. The live supergraph carries no
|
|
6
|
-
# replacement for any of them:
|
|
7
|
-
#
|
|
8
|
-
# * no Mtw* provider or offering type exists — `MtwIntegration` is a
|
|
9
|
-
# TMS/visibility connector (Project44 / FourKites / Descartes), a different
|
|
10
|
-
# domain, not a marketplace listing;
|
|
11
|
-
# * the platform-wide `Report` type belongs to the analytics-report module and
|
|
12
|
-
# has a different shape (sections / parameters / runs, and no
|
|
13
|
-
# type / schedule / lastGenerated / configuration), so it is not a drop-in.
|
|
14
|
-
#
|
|
15
|
-
# These fragments are kept verbatim so they can be restored unchanged the day the
|
|
16
|
-
# service re-publishes the surface. Files matching `*.withdrawn.graphql` are
|
|
17
|
-
# excluded from the codegen `documents` globs in `.graphqlrc.yml`, because
|
|
18
|
-
# codegen validates every document it loads and an unresolvable type condition
|
|
19
|
-
# fails the whole run.
|
|
20
|
-
|
|
21
|
-
fragment ServiceProviderCore on ServiceProvider {
|
|
22
|
-
id
|
|
23
|
-
name
|
|
24
|
-
type
|
|
25
|
-
description
|
|
26
|
-
rating
|
|
27
|
-
contactInfo
|
|
28
|
-
services
|
|
29
|
-
isVerified
|
|
30
|
-
isActive
|
|
31
|
-
createdAt
|
|
32
|
-
updatedAt
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
fragment ServiceOfferingCore on ServiceOffering {
|
|
36
|
-
id
|
|
37
|
-
providerId
|
|
38
|
-
name
|
|
39
|
-
description
|
|
40
|
-
category
|
|
41
|
-
price
|
|
42
|
-
currency
|
|
43
|
-
availability
|
|
44
|
-
createdAt
|
|
45
|
-
updatedAt
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
fragment MovethewheelsReportCore on MovethewheelsReport {
|
|
49
|
-
id
|
|
50
|
-
name
|
|
51
|
-
type
|
|
52
|
-
description
|
|
53
|
-
schedule
|
|
54
|
-
lastGenerated
|
|
55
|
-
configuration
|
|
56
|
-
status
|
|
57
|
-
createdAt
|
|
58
|
-
updatedAt
|
|
59
|
-
}
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
# ─── Withdrawn service surface — preserved, not deleted ──────────────────────
|
|
2
|
-
#
|
|
3
|
-
# Every write below targets a surface that migration
|
|
4
|
-
# `20260707000001_movethewheels_reuse_cleanup` removed from
|
|
5
|
-
# wspace-movethewheels-svc, with no replacement in the live supergraph:
|
|
6
|
-
#
|
|
7
|
-
# * service-provider / service-offering marketplace CRUD — no Mtw* provider or
|
|
8
|
-
# offering type exists (`MtwIntegration` is a TMS/visibility connector for
|
|
9
|
-
# Project44 / FourKites / Descartes, a different domain).
|
|
10
|
-
# * MovethewheelsReport CRUD + generation — the platform-wide `Report` type is
|
|
11
|
-
# the analytics-report module's, a different shape, not a drop-in.
|
|
12
|
-
# * `importData` — the service exposes an export job (`exportMtwEntities`, see
|
|
13
|
-
# mutations/marketplace-reports.graphql) but no import counterpart.
|
|
14
|
-
# * `updateModuleSettings` — no per-module settings surface remains.
|
|
15
|
-
#
|
|
16
|
-
# Kept verbatim so they can be restored unchanged if the surface returns. Files
|
|
17
|
-
# matching `*.withdrawn.graphql` are excluded from the codegen `documents` globs
|
|
18
|
-
# in `.graphqlrc.yml`; codegen validates every document it loads, and an
|
|
19
|
-
# unresolvable field fails the whole run.
|
|
20
|
-
|
|
21
|
-
mutation CreateServiceProvider($input: CreateServiceProviderInput!) {
|
|
22
|
-
createServiceProvider(input: $input) {
|
|
23
|
-
...ServiceProviderCore
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
mutation UpdateServiceProvider($id: ID!, $input: UpdateServiceProviderInput!) {
|
|
28
|
-
updateServiceProvider(id: $id, input: $input) {
|
|
29
|
-
...ServiceProviderCore
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
mutation DeleteServiceProvider($id: ID!) {
|
|
34
|
-
deleteServiceProvider(id: $id)
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
mutation CreateServiceOffering($input: CreateServiceOfferingInput!) {
|
|
38
|
-
createServiceOffering(input: $input) {
|
|
39
|
-
...ServiceOfferingCore
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
mutation UpdateServiceOffering($id: ID!, $input: UpdateServiceOfferingInput!) {
|
|
44
|
-
updateServiceOffering(id: $id, input: $input) {
|
|
45
|
-
...ServiceOfferingCore
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
mutation DeleteServiceOffering($id: ID!) {
|
|
50
|
-
deleteServiceOffering(id: $id)
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
mutation CreateMovethewheelsReport($input: CreateMovethewheelsReportInput!) {
|
|
54
|
-
createMovethewheelsReport(input: $input) {
|
|
55
|
-
...MovethewheelsReportCore
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
mutation UpdateMovethewheelsReport($id: ID!, $input: UpdateMovethewheelsReportInput!) {
|
|
60
|
-
updateMovethewheelsReport(id: $id, input: $input) {
|
|
61
|
-
...MovethewheelsReportCore
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
mutation DeleteMovethewheelsReport($id: ID!) {
|
|
66
|
-
deleteMovethewheelsReport(id: $id)
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
mutation GenerateMovethewheelsReport($input: GenerateMovethewheelsReportInput!) {
|
|
70
|
-
generateMovethewheelsReport(input: $input) {
|
|
71
|
-
generatedAt
|
|
72
|
-
result
|
|
73
|
-
report {
|
|
74
|
-
...MovethewheelsReportCore
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
mutation ImportMovethewheelsData($input: MovethewheelsImportDataInput!) {
|
|
80
|
-
importData(input: $input) {
|
|
81
|
-
success
|
|
82
|
-
message
|
|
83
|
-
payload
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
mutation UpdateMovethewheelsModuleSettings($input: UpdateMovethewheelsModuleSettingsInput!) {
|
|
88
|
-
updateModuleSettings(input: $input) {
|
|
89
|
-
workspaceId
|
|
90
|
-
preferences
|
|
91
|
-
updatedAt
|
|
92
|
-
}
|
|
93
|
-
}
|