@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.
Files changed (42) hide show
  1. package/dist/MoveTheWheelsRoot.js +126 -159
  2. package/dist/MoveTheWheelsRoutes.js +16 -32
  3. package/dist/hooks/index.js +0 -3
  4. package/dist/index.js +27 -30
  5. package/dist/movethewheels/hooks/index.d.ts +0 -3
  6. package/package.json +1 -1
  7. package/src/movethewheels/MoveTheWheelsRoot.tsx +2 -46
  8. package/src/movethewheels/MoveTheWheelsRoutes.tsx +0 -16
  9. package/src/movethewheels/hooks/index.ts +0 -9
  10. package/dist/hooks/useImportExport.js +0 -27
  11. package/dist/hooks/useReports.js +0 -75
  12. package/dist/hooks/useSettings.js +0 -67
  13. package/dist/movethewheels/hooks/useImportExport.d.ts +0 -23
  14. package/dist/movethewheels/hooks/useReports.d.ts +0 -39
  15. package/dist/movethewheels/hooks/useSettings.d.ts +0 -17
  16. package/dist/movethewheels/pages/ImportExportPage.d.ts +0 -8
  17. package/dist/movethewheels/pages/MarketplacePage.d.ts +0 -12
  18. package/dist/movethewheels/pages/ReportsPage.d.ts +0 -8
  19. package/dist/movethewheels/pages/SettingsPage.d.ts +0 -8
  20. package/dist/node_modules/lucide-react/dist/esm/icons/bell.js +0 -11
  21. package/dist/node_modules/lucide-react/dist/esm/icons/file-chart-column-increasing.js +0 -26
  22. package/dist/node_modules/lucide-react/dist/esm/icons/file-spreadsheet.js +0 -30
  23. package/dist/node_modules/lucide-react/dist/esm/icons/globe.js +0 -20
  24. package/dist/node_modules/lucide-react/dist/esm/icons/settings.js +0 -13
  25. package/dist/node_modules/lucide-react/dist/esm/icons/shield.js +0 -8
  26. package/dist/node_modules/lucide-react/dist/esm/icons/store.js +0 -26
  27. package/dist/node_modules/lucide-react/dist/esm/icons/webhook.js +0 -18
  28. package/dist/pages/ImportExportPage.js +0 -245
  29. package/dist/pages/MarketplacePage.js +0 -23
  30. package/dist/pages/ReportsPage.js +0 -328
  31. package/dist/pages/SettingsPage.js +0 -404
  32. package/dist/utils/download.js +0 -22
  33. package/src/movethewheels/hooks/useImportExport.ts +0 -65
  34. package/src/movethewheels/hooks/useReports.ts +0 -154
  35. package/src/movethewheels/hooks/useSettings.ts +0 -124
  36. package/src/movethewheels/pages/ImportExportPage.tsx +0 -288
  37. package/src/movethewheels/pages/MarketplacePage.tsx +0 -36
  38. package/src/movethewheels/pages/ReportsPage.tsx +0 -379
  39. package/src/movethewheels/pages/SettingsPage.tsx +0 -548
  40. package/src/operations/wspace/movethewheels/fragments/core.withdrawn.graphql +0 -59
  41. package/src/operations/wspace/movethewheels/mutations/marketplace-reports.withdrawn.graphql +0 -93
  42. package/src/operations/wspace/movethewheels/queries/marketplace-reports.withdrawn.graphql +0 -58
@@ -1,124 +0,0 @@
1
- import { useCallback, useEffect, useMemo, useState } from 'react';
2
- import { useMoveTheWheels } from '../providers/MoveTheWheelsProvider';
3
-
4
- export type ModulePreferences = Record<string, unknown>;
5
-
6
- export interface ModuleSettings {
7
- preferences: ModulePreferences;
8
- updatedAt: string;
9
- workspaceId: string;
10
- }
11
-
12
- interface UseModuleSettingsResult {
13
- settings: ModuleSettings | null;
14
- preferences: ModulePreferences;
15
- isLoading: boolean;
16
- isSaving: boolean;
17
- error: Error | null;
18
- refetch: () => void;
19
- savePreferences: (preferences: ModulePreferences) => Promise<ModuleSettings>;
20
- }
21
-
22
- function readSettings(workspaceId: string): ModuleSettings | null {
23
- if (typeof window === 'undefined') return null;
24
- try {
25
- const raw = window.localStorage.getItem(`movethewheels:moduleSettings:${workspaceId}`);
26
- if (!raw) return null;
27
- const parsed = JSON.parse(raw) as ModuleSettings;
28
- if (parsed && typeof parsed === 'object' && 'preferences' in parsed) {
29
- return parsed;
30
- }
31
- return null;
32
- } catch {
33
- return null;
34
- }
35
- }
36
-
37
- function writeSettings(settings: ModuleSettings): void {
38
- if (typeof window === 'undefined') return;
39
- try {
40
- window.localStorage.setItem(
41
- `movethewheels:moduleSettings:${settings.workspaceId}`,
42
- JSON.stringify(settings)
43
- );
44
- } catch {
45
- // Ignore storage errors (e.g. private mode quota).
46
- }
47
- }
48
-
49
- export function useModuleSettings(): UseModuleSettingsResult {
50
- const { workspaceId } = useMoveTheWheels();
51
- const [settings, setSettings] = useState<ModuleSettings | null>(null);
52
- const [isLoading, setIsLoading] = useState(false);
53
- const [isSaving, setIsSaving] = useState(false);
54
- const [error, setError] = useState<Error | null>(null);
55
-
56
- const load = useCallback(() => {
57
- setIsLoading(true);
58
- setError(null);
59
- try {
60
- const stored = workspaceId ? readSettings(workspaceId) : null;
61
- setSettings(
62
- stored ?? {
63
- preferences: {},
64
- updatedAt: new Date().toISOString(),
65
- workspaceId: workspaceId ?? '',
66
- }
67
- );
68
- } catch (loadError) {
69
- setError(loadError instanceof Error ? loadError : new Error('Failed to load settings'));
70
- } finally {
71
- setIsLoading(false);
72
- }
73
- }, [workspaceId]);
74
-
75
- useEffect(() => {
76
- void load();
77
- }, [load]);
78
-
79
- const refetch = useCallback(() => {
80
- void load();
81
- }, [load]);
82
-
83
- const savePreferences = useCallback(
84
- async (preferences: ModulePreferences): Promise<ModuleSettings> => {
85
- setIsSaving(true);
86
- setError(null);
87
- try {
88
- const next: ModuleSettings = {
89
- preferences,
90
- updatedAt: new Date().toISOString(),
91
- workspaceId: workspaceId ?? '',
92
- };
93
- writeSettings(next);
94
- setSettings(next);
95
- return next;
96
- } catch (saveError) {
97
- const normalized =
98
- saveError instanceof Error ? saveError : new Error('Failed to save settings');
99
- setError(normalized);
100
- throw normalized;
101
- } finally {
102
- setIsSaving(false);
103
- }
104
- },
105
- [workspaceId]
106
- );
107
-
108
- // Stabilize the preferences reference. Returning `settings?.preferences ?? {}`
109
- // inline minted a fresh `{}` on every render while settings was null, which
110
- // made SettingsPage's `useMemo(toForm, [preferences])` recompute every render
111
- // and its `useEffect(setForm, [loadedForm])` fire in a loop → "Maximum update
112
- // depth exceeded" → the page rendered blank behind the shell's error boundary.
113
- const preferences = useMemo<ModulePreferences>(() => settings?.preferences ?? {}, [settings]);
114
-
115
- return {
116
- settings,
117
- preferences,
118
- isLoading,
119
- isSaving,
120
- error,
121
- refetch,
122
- savePreferences,
123
- };
124
- }
@@ -1,288 +0,0 @@
1
- /**
2
- * Import/Export Page
3
- *
4
- * Bulk data in/out wired to the backend exportData / importData mutations.
5
- * Activity is session-local (reflects actions the operator actually ran) — no
6
- * fabricated history is shown; the empty state renders until something happens.
7
- */
8
-
9
- import { useRef, useState } from 'react';
10
- import { Upload, Download, FileText, FileSpreadsheet, Check, X } from 'lucide-react';
11
- import { PageLayout } from '../components/PageLayout';
12
- import { Card, CardContent, CardHeader, CardTitle, Button, Badge } from '../components/ui';
13
- import { EmphasisPanel, IllustratedEmptyState, PagePurpose } from '@burdenoff/fe-libs/ui';
14
- import { useImportExport } from '../hooks/useImportExport';
15
-
16
- interface ImportOption {
17
- name: string;
18
- description: string;
19
- resource: string;
20
- }
21
-
22
- interface ExportOption {
23
- name: string;
24
- description: string;
25
- resource: string;
26
- formats: string[];
27
- }
28
-
29
- interface ActivityEntry {
30
- type: 'import' | 'export';
31
- name: string;
32
- at: Date;
33
- success: boolean;
34
- message: string;
35
- }
36
-
37
- const importOptions: ImportOption[] = [
38
- { name: 'Orders', description: 'Import orders from CSV or JSON', resource: 'orders' },
39
- { name: 'Customers', description: 'Import customer database', resource: 'customers' },
40
- { name: 'Products', description: 'Import product catalog', resource: 'products' },
41
- { name: 'Inventory', description: 'Import inventory levels', resource: 'inventory' },
42
- ];
43
-
44
- const exportOptions: ExportOption[] = [
45
- {
46
- name: 'Orders Report',
47
- description: 'Export all orders data',
48
- resource: 'orders',
49
- formats: ['CSV', 'JSON'],
50
- },
51
- {
52
- name: 'Financial Report',
53
- description: 'Export revenue and payments',
54
- resource: 'finance',
55
- formats: ['CSV', 'JSON'],
56
- },
57
- {
58
- name: 'Fleet Report',
59
- description: 'Export vehicle and driver data',
60
- resource: 'fleet',
61
- formats: ['CSV', 'JSON'],
62
- },
63
- {
64
- name: 'Analytics Report',
65
- description: 'Export performance metrics',
66
- resource: 'analytics',
67
- formats: ['CSV', 'JSON'],
68
- },
69
- ];
70
-
71
- export default function ImportExportPage() {
72
- const { exportData, importData, isBusy } = useImportExport();
73
- const [activity, setActivity] = useState<ActivityEntry[]>([]);
74
- const [pendingResource, setPendingResource] = useState<string | null>(null);
75
- const fileInputRef = useRef<HTMLInputElement | null>(null);
76
- const importTargetRef = useRef<ImportOption | null>(null);
77
-
78
- const record = (entry: ActivityEntry) => setActivity((previous) => [entry, ...previous]);
79
-
80
- const handleExport = async (option: ExportOption, format: string) => {
81
- setPendingResource(`${option.resource}:${format}`);
82
- try {
83
- const result = await exportData(option.resource, format);
84
- if (result.success && result.payload) {
85
- const contents = JSON.stringify(result.payload, null, 2);
86
- const blob = new Blob([contents], { type: 'application/json' });
87
- const url = URL.createObjectURL(blob);
88
- const link = document.createElement('a');
89
- link.href = url;
90
- link.download = `${option.resource}-export.${format.toLowerCase() === 'csv' ? 'csv' : 'json'}`;
91
- document.body.appendChild(link);
92
- link.click();
93
- link.remove();
94
- URL.revokeObjectURL(url);
95
- }
96
- record({
97
- type: 'export',
98
- name: `${option.name} (${format})`,
99
- at: new Date(),
100
- success: result.success,
101
- message: result.message,
102
- });
103
- } catch (exportError) {
104
- record({
105
- type: 'export',
106
- name: `${option.name} (${format})`,
107
- at: new Date(),
108
- success: false,
109
- message: exportError instanceof Error ? exportError.message : 'Export failed',
110
- });
111
- } finally {
112
- setPendingResource(null);
113
- }
114
- };
115
-
116
- const triggerImport = (option: ImportOption) => {
117
- importTargetRef.current = option;
118
- fileInputRef.current?.click();
119
- };
120
-
121
- const handleFileSelected = async (event: React.ChangeEvent<HTMLInputElement>) => {
122
- const file = event.target.files?.[0];
123
- const option = importTargetRef.current;
124
- event.target.value = '';
125
- if (!file || !option) return;
126
- setPendingResource(`import:${option.resource}`);
127
- try {
128
- const content = await file.text();
129
- const result = await importData(option.resource, { filename: file.name, content });
130
- record({
131
- type: 'import',
132
- name: `${option.name} — ${file.name}`,
133
- at: new Date(),
134
- success: result.success,
135
- message: result.message,
136
- });
137
- } catch (importError) {
138
- record({
139
- type: 'import',
140
- name: `${option.name} — ${file.name}`,
141
- at: new Date(),
142
- success: false,
143
- message: importError instanceof Error ? importError.message : 'Import failed',
144
- });
145
- } finally {
146
- setPendingResource(null);
147
- }
148
- };
149
-
150
- return (
151
- <PageLayout
152
- title="Import / Export"
153
- subtitle="Import and export your data"
154
- icon={<FileText size={24} />}
155
- >
156
- <PagePurpose icon={<FileText size={18} />}>
157
- Move data in and out in bulk. Import orders, customers, products or inventory from CSV/JSON
158
- to onboard or migrate without re-keying, and export any dataset for accounting, BI tools or
159
- backups — no manual copy-paste required.
160
- </PagePurpose>
161
-
162
- <input
163
- ref={fileInputRef}
164
- type="file"
165
- accept=".csv,.json,application/json,text/csv"
166
- className="hidden"
167
- onChange={handleFileSelected}
168
- />
169
-
170
- <div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
171
- {/* Import Data — the page's single emphasis zone */}
172
- <EmphasisPanel className="space-y-4">
173
- <h2 className="flex items-center gap-2 text-base font-semibold text-text-primary">
174
- <Upload size={18} /> Import Data
175
- </h2>
176
- <div className="space-y-4">
177
- {importOptions.map((opt) => (
178
- <div
179
- key={opt.name}
180
- className="flex items-center justify-between p-4 border rounded-lg hover:border-primary/50 transition-colors"
181
- >
182
- <div className="flex items-center gap-3">
183
- <div className="w-10 h-10 rounded-lg bg-action-primary-bg/10 flex items-center justify-center">
184
- <FileSpreadsheet size={20} className="text-primary" />
185
- </div>
186
- <div>
187
- <p className="font-medium">{opt.name}</p>
188
- <p className="text-sm text-text-secondary">{opt.description}</p>
189
- </div>
190
- </div>
191
- <div className="text-right">
192
- <Badge variant="outline">CSV, JSON</Badge>
193
- <Button
194
- variant="outline"
195
- size="sm"
196
- className="ml-2"
197
- aria-label={`Import ${opt.name}`}
198
- disabled={isBusy}
199
- onClick={() => triggerImport(opt)}
200
- >
201
- <Upload size={14} />
202
- </Button>
203
- </div>
204
- </div>
205
- ))}
206
- </div>
207
- </EmphasisPanel>
208
-
209
- <Card>
210
- <CardHeader>
211
- <CardTitle className="flex items-center gap-2">
212
- <Download size={18} /> Export Data
213
- </CardTitle>
214
- </CardHeader>
215
- <CardContent className="space-y-4">
216
- {exportOptions.map((opt) => (
217
- <div
218
- key={opt.name}
219
- className="flex items-center justify-between p-4 border rounded-lg hover:border-primary/50 transition-colors"
220
- >
221
- <div>
222
- <p className="font-medium">{opt.name}</p>
223
- <p className="text-sm text-text-secondary">{opt.description}</p>
224
- </div>
225
- <div className="flex gap-1">
226
- {opt.formats.map((f) => (
227
- <Button
228
- key={f}
229
- variant="outline"
230
- size="sm"
231
- disabled={pendingResource === `${opt.resource}:${f}`}
232
- onClick={() => void handleExport(opt, f)}
233
- >
234
- {f}
235
- </Button>
236
- ))}
237
- </div>
238
- </div>
239
- ))}
240
- </CardContent>
241
- </Card>
242
- </div>
243
-
244
- <Card>
245
- <CardHeader>
246
- <CardTitle>Recent Activity</CardTitle>
247
- </CardHeader>
248
- <CardContent>
249
- {activity.length === 0 ? (
250
- <IllustratedEmptyState
251
- illustration="empty-data"
252
- title="No import or export activity yet"
253
- description="Your recent imports and exports will show up here once you run one."
254
- />
255
- ) : (
256
- <div className="space-y-3">
257
- {activity.map((entry, i) => (
258
- <div
259
- key={i}
260
- className="flex items-center justify-between p-3 bg-bg-sunken/50 rounded-lg"
261
- >
262
- <div className="flex items-center gap-3">
263
- {entry.type === 'import' ? (
264
- <Upload size={16} className="text-primary" />
265
- ) : (
266
- <Download size={16} className="text-primary" />
267
- )}
268
- <div>
269
- <p className="font-medium">{entry.name}</p>
270
- <p className="text-sm text-text-secondary">
271
- {entry.type === 'import' ? 'Imported' : 'Exported'} at{' '}
272
- {entry.at.toLocaleTimeString()} — {entry.message}
273
- </p>
274
- </div>
275
- </div>
276
- <Badge variant={entry.success ? 'default' : 'destructive'} className="gap-1">
277
- {entry.success ? <Check size={12} /> : <X size={12} />}
278
- {entry.success ? 'done' : 'failed'}
279
- </Badge>
280
- </div>
281
- ))}
282
- </div>
283
- )}
284
- </CardContent>
285
- </Card>
286
- </PageLayout>
287
- );
288
- }
@@ -1,36 +0,0 @@
1
- /**
2
- * Marketplace Page
3
- *
4
- * The collaborative logistics marketplace (service providers / service offerings)
5
- * was withdrawn from wspace-movethewheels-svc by migration
6
- * 20260707000001_movethewheels_reuse_cleanup. The original query and mutation
7
- * documents are preserved verbatim in
8
- * src/operations/wspace/movethewheels/{queries,mutations}/marketplace-reports.withdrawn.graphql
9
- * so they can be restored if the surface returns. Until then the page renders a
10
- * static "coming soon" state.
11
- */
12
-
13
- import { Store } from 'lucide-react';
14
- import { PageLayout } from '../components/PageLayout';
15
- import { Card, CardContent } from '../components/ui';
16
- import { IllustratedEmptyState } from '@burdenoff/fe-libs/ui';
17
-
18
- export default function MarketplacePage() {
19
- return (
20
- <PageLayout
21
- title="Marketplace"
22
- subtitle="Find logistics service providers"
23
- icon={<Store size={24} />}
24
- >
25
- <Card>
26
- <CardContent className="p-0">
27
- <IllustratedEmptyState
28
- illustration="empty-people"
29
- title="Marketplace is coming soon"
30
- description="The collaborative logistics marketplace is not open yet. Check back after it launches to browse verified third-party service providers."
31
- />
32
- </CardContent>
33
- </Card>
34
- </PageLayout>
35
- );
36
- }