@burdenoff/microfe-movethewheels 2026.828.1 → 2026.830.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.
@@ -30,6 +30,7 @@ import { MoveTheWheelsProvider } from './providers/MoveTheWheelsProvider';
30
30
  import { FeatureFlagProvider, useFeatureFlag } from '@burdenoff/fe-libs/shared/feature-flags';
31
31
  import type { NavItem, MoveTheWheelsRootProps } from './types';
32
32
  import { MoveTheWheelsRoutes } from './MoveTheWheelsRoutes';
33
+ import { useTr } from './hooks';
33
34
 
34
35
  /**
35
36
  * Registers the MoveTheWheels sidebar nav tree with the host shell.
@@ -43,6 +44,8 @@ const NavRegistrar: FC<Pick<MoveTheWheelsRootProps, 'registerNavItems' | 'basePa
43
44
  registerNavItems,
44
45
  basePath = '/',
45
46
  }) => {
47
+ const tr = useTr();
48
+
46
49
  // The backend has no ServiceProvider/ServiceOffering model (dropped by
47
50
  // migration 20260707000001_movethewheels_reuse_cleanup) — hide the
48
51
  // Marketplace nav entry until a serviceProviders/serviceOfferings resolver
@@ -62,7 +65,7 @@ const NavRegistrar: FC<Pick<MoveTheWheelsRootProps, 'registerNavItems' | 'basePa
62
65
 
63
66
  const movethewheelsNavItem: NavItem = {
64
67
  id: 'movethewheels',
65
- label: 'MoveTheWheels',
68
+ label: tr('movethewheels.page.title', 'MoveTheWheels'),
66
69
  path: basePath,
67
70
  icon: <Truck size={20} />,
68
71
  order: 25,
@@ -70,49 +73,49 @@ const NavRegistrar: FC<Pick<MoveTheWheelsRootProps, 'registerNavItems' | 'basePa
70
73
  children: [
71
74
  {
72
75
  id: 'mtw-dashboard',
73
- label: 'Dashboard',
76
+ label: tr('movethewheels.root.nav.dashboard', 'Dashboard'),
74
77
  path: basePath,
75
78
  icon: <LayoutDashboard size={16} />,
76
79
  order: 1,
77
80
  },
78
81
  {
79
82
  id: 'mtw-orders',
80
- label: 'Orders',
83
+ label: tr('movethewheels.root.nav.orders', 'Orders'),
81
84
  path: joinPath(basePath, 'orders'),
82
85
  icon: <Package size={16} />,
83
86
  order: 2,
84
87
  },
85
88
  {
86
89
  id: 'mtw-tracking',
87
- label: 'Tracking',
90
+ label: tr('movethewheels.root.nav.tracking', 'Tracking'),
88
91
  path: joinPath(basePath, 'tracking'),
89
92
  icon: <Map size={16} />,
90
93
  order: 3,
91
94
  },
92
95
  {
93
96
  id: 'mtw-fleet',
94
- label: 'Fleet',
97
+ label: tr('movethewheels.root.nav.fleet', 'Fleet'),
95
98
  path: joinPath(basePath, 'fleet'),
96
99
  icon: <Truck size={16} />,
97
100
  order: 4,
98
101
  children: [
99
102
  {
100
103
  id: 'mtw-fleet-overview',
101
- label: 'Overview',
104
+ label: tr('movethewheels.root.nav.overview', 'Overview'),
102
105
  path: joinPath(basePath, 'fleet'),
103
106
  icon: <LayoutDashboard size={14} />,
104
107
  order: 1,
105
108
  },
106
109
  {
107
110
  id: 'mtw-vehicles',
108
- label: 'Vehicles',
111
+ label: tr('movethewheels.root.nav.vehicles', 'Vehicles'),
109
112
  path: joinPath(basePath, 'fleet/vehicles'),
110
113
  icon: <Car size={14} />,
111
114
  order: 2,
112
115
  },
113
116
  {
114
117
  id: 'mtw-drivers',
115
- label: 'Drivers',
118
+ label: tr('movethewheels.root.nav.drivers', 'Drivers'),
116
119
  path: joinPath(basePath, 'fleet/drivers'),
117
120
  icon: <UserCheck size={14} />,
118
121
  order: 3,
@@ -121,28 +124,28 @@ const NavRegistrar: FC<Pick<MoveTheWheelsRootProps, 'registerNavItems' | 'basePa
121
124
  },
122
125
  {
123
126
  id: 'mtw-inventory',
124
- label: 'Inventory',
127
+ label: tr('movethewheels.root.nav.inventory', 'Inventory'),
125
128
  path: joinPath(basePath, 'inventory'),
126
129
  icon: <Warehouse size={16} />,
127
130
  order: 5,
128
131
  children: [
129
132
  {
130
133
  id: 'mtw-inventory-overview',
131
- label: 'Overview',
134
+ label: tr('movethewheels.root.nav.overview', 'Overview'),
132
135
  path: joinPath(basePath, 'inventory'),
133
136
  icon: <LayoutDashboard size={14} />,
134
137
  order: 1,
135
138
  },
136
139
  {
137
140
  id: 'mtw-products',
138
- label: 'Products',
141
+ label: tr('movethewheels.root.nav.products', 'Products'),
139
142
  path: joinPath(basePath, 'inventory/products'),
140
143
  icon: <Boxes size={14} />,
141
144
  order: 2,
142
145
  },
143
146
  {
144
147
  id: 'mtw-warehouses',
145
- label: 'Warehouses',
148
+ label: tr('movethewheels.root.nav.warehouses', 'Warehouses'),
146
149
  path: joinPath(basePath, 'inventory/warehouses'),
147
150
  icon: <Warehouse size={14} />,
148
151
  order: 3,
@@ -151,28 +154,28 @@ const NavRegistrar: FC<Pick<MoveTheWheelsRootProps, 'registerNavItems' | 'basePa
151
154
  },
152
155
  {
153
156
  id: 'mtw-customers',
154
- label: 'Customers',
157
+ label: tr('movethewheels.root.nav.customers', 'Customers'),
155
158
  path: joinPath(basePath, 'customers'),
156
159
  icon: <Users size={16} />,
157
160
  order: 6,
158
161
  },
159
162
  {
160
163
  id: 'mtw-routes',
161
- label: 'Routes',
164
+ label: tr('movethewheels.root.nav.routes', 'Routes'),
162
165
  path: joinPath(basePath, 'routes'),
163
166
  icon: <Route size={16} />,
164
167
  order: 7,
165
168
  },
166
169
  {
167
170
  id: 'mtw-analytics',
168
- label: 'Analytics',
171
+ label: tr('movethewheels.root.nav.analytics', 'Analytics'),
169
172
  path: joinPath(basePath, 'analytics'),
170
173
  icon: <BarChart3 size={16} />,
171
174
  order: 8,
172
175
  },
173
176
  {
174
177
  id: 'mtw-finance',
175
- label: 'Finance',
178
+ label: tr('movethewheels.root.nav.finance', 'Finance'),
176
179
  path: joinPath(basePath, 'finance'),
177
180
  icon: <DollarSign size={16} />,
178
181
  order: 9,
@@ -183,7 +186,7 @@ const NavRegistrar: FC<Pick<MoveTheWheelsRootProps, 'registerNavItems' | 'basePa
183
186
  ? [
184
187
  {
185
188
  id: 'mtw-marketplace',
186
- label: 'Marketplace',
189
+ label: tr('movethewheels.root.nav.marketplace', 'Marketplace'),
187
190
  path: joinPath(basePath, 'marketplace'),
188
191
  icon: <Store size={16} />,
189
192
  order: 10,
@@ -192,28 +195,28 @@ const NavRegistrar: FC<Pick<MoveTheWheelsRootProps, 'registerNavItems' | 'basePa
192
195
  : []),
193
196
  {
194
197
  id: 'mtw-import-export',
195
- label: 'Import/Export',
198
+ label: tr('movethewheels.root.nav.importExport', 'Import/Export'),
196
199
  path: joinPath(basePath, 'import-export'),
197
200
  icon: <Globe size={16} />,
198
201
  order: 11,
199
202
  },
200
203
  {
201
204
  id: 'mtw-reports',
202
- label: 'Reports',
205
+ label: tr('movethewheels.root.nav.reports', 'Reports'),
203
206
  path: joinPath(basePath, 'reports'),
204
207
  icon: <FileText size={16} />,
205
208
  order: 12,
206
209
  },
207
210
  {
208
211
  id: 'mtw-ai-assistant',
209
- label: 'AI Assistant',
212
+ label: tr('movethewheels.root.nav.aiAssistant', 'AI Assistant'),
210
213
  path: joinPath(basePath, 'ai-assistant'),
211
214
  icon: <Bot size={16} />,
212
215
  order: 13,
213
216
  },
214
217
  {
215
218
  id: 'mtw-settings',
216
- label: 'Settings',
219
+ label: tr('movethewheels.root.nav.settings', 'Settings'),
217
220
  path: joinPath(basePath, 'settings'),
218
221
  icon: <Settings size={16} />,
219
222
  order: 99,
@@ -226,7 +229,7 @@ const NavRegistrar: FC<Pick<MoveTheWheelsRootProps, 'registerNavItems' | 'basePa
226
229
 
227
230
  // Return cleanup function to unregister on unmount
228
231
  return cleanup;
229
- }, [registerNavItems, basePath, marketplaceEnabled]);
232
+ }, [registerNavItems, basePath, marketplaceEnabled, tr]);
230
233
 
231
234
  return null;
232
235
  };
@@ -254,6 +257,7 @@ const NavRegistrar: FC<Pick<MoveTheWheelsRootProps, 'registerNavItems' | 'basePa
254
257
  */
255
258
  export const MoveTheWheelsRoot: FC<MoveTheWheelsRootProps> = (props) => {
256
259
  const { registerNavItems, registerFooterItems, basePath = '/' } = props;
260
+ const tr = useTr();
257
261
 
258
262
  // Register footer items
259
263
  useEffect(() => {
@@ -262,7 +266,7 @@ export const MoveTheWheelsRoot: FC<MoveTheWheelsRootProps> = (props) => {
262
266
  const footerItems = [
263
267
  {
264
268
  id: 'mtw-status',
265
- label: 'Logistics Ready',
269
+ label: tr('movethewheels.root.footer.status', 'Logistics Ready'),
266
270
  type: 'status' as const,
267
271
  order: 20,
268
272
  section: 'left' as const,
@@ -271,7 +275,7 @@ export const MoveTheWheelsRoot: FC<MoveTheWheelsRootProps> = (props) => {
271
275
 
272
276
  const cleanup = registerFooterItems(footerItems);
273
277
  return cleanup;
274
- }, [registerFooterItems]);
278
+ }, [registerFooterItems, tr]);
275
279
 
276
280
  return (
277
281
  <FeatureFlagProvider workspaceId={null} gateway="global" defaultEnabled={true}>
@@ -9,6 +9,7 @@ import { Routes, Route, useNavigate } from 'react-router';
9
9
  import { lazy, Suspense } from 'react';
10
10
  import { NotFoundPage } from '@burdenoff/fe-libs/shared/pages';
11
11
  import { useMoveTheWheels } from './providers/MoveTheWheelsProvider';
12
+ import { useTr } from './hooks';
12
13
 
13
14
  /**
14
15
  * Catch-all 404 rendered inside the content area (previously a redirect to ""
@@ -18,9 +19,10 @@ import { useMoveTheWheels } from './providers/MoveTheWheelsProvider';
18
19
  function MoveTheWheelsNotFound() {
19
20
  const { navigate, basePath } = useMoveTheWheels();
20
21
  const routerNavigate = useNavigate();
22
+ const tr = useTr();
21
23
  return (
22
24
  <NotFoundPage
23
- homeLabel="Back to MoveTheWheels"
25
+ homeLabel={tr('movethewheels.root.notFound.homeLabel', 'Back to MoveTheWheels')}
24
26
  onGoHome={() => {
25
27
  if (navigate) {
26
28
  navigate(basePath || '/');
@@ -34,11 +36,12 @@ function MoveTheWheelsNotFound() {
34
36
 
35
37
  // Loading fallback
36
38
  function PageLoader() {
39
+ const tr = useTr();
37
40
  return (
38
41
  <div className="flex items-center justify-center min-h-[400px]">
39
42
  <div className="flex flex-col items-center gap-3">
40
43
  <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-primary"></div>
41
- <p className="text-sm text-text-secondary">Loading...</p>
44
+ <p className="text-sm text-text-secondary">{tr('movethewheels.root.loading', 'Loading...')}</p>
42
45
  </div>
43
46
  </div>
44
47
  );
@@ -4,6 +4,9 @@
4
4
  * All custom hooks for data access and operations.
5
5
  */
6
6
 
7
+ // Shared i18n helper
8
+ export { useTr } from '../shared/hooks/useTr';
9
+
7
10
  // Orders
8
11
  export { useOrders, useOrder, useOrderStats } from './useOrders';
9
12
 
@@ -24,38 +24,49 @@ import { Bot, MessageCircle, Activity, ShieldCheck, Wallet } from 'lucide-react'
24
24
  import { PageLayout, EmptyState } from '../components/PageLayout';
25
25
  import { Card, CardContent, CardHeader, CardTitle } from '../components/ui';
26
26
  import { GlassCard, PagePurpose } from '@burdenoff/fe-libs/ui';
27
-
28
- const roadmapItems = [
29
- {
30
- icon: Activity,
31
- title: 'Agent activity feed',
32
- description:
33
- 'A live log of what the AI decided, on which shipments, with trigger, model, latency and cost — so an autonomous run is never a black box.',
34
- },
35
- {
36
- icon: ShieldCheck,
37
- title: 'Dispatch decision cards',
38
- description:
39
- 'Proposed driver/vehicle assignments and carrier recommendations with rationale and confidence, requiring an explicit accept or reject before anything is written.',
40
- },
41
- {
42
- icon: Wallet,
43
- title: 'AI credit visibility',
44
- description: 'Per-workspace AI spend for admins, so cost is visible before the invoice.',
45
- },
46
- ];
27
+ import { useTr } from '../hooks';
47
28
 
48
29
  export default function AIAssistantPage() {
30
+ const tr = useTr();
31
+
32
+ const roadmapItems = [
33
+ {
34
+ icon: Activity,
35
+ title: tr('movethewheels.ai.roadmap.agentActivity.title', 'Agent activity feed'),
36
+ description: tr(
37
+ 'movethewheels.ai.roadmap.agentActivity.description',
38
+ 'A live log of what the AI decided, on which shipments, with trigger, model, latency and cost — so an autonomous run is never a black box.'
39
+ ),
40
+ },
41
+ {
42
+ icon: ShieldCheck,
43
+ title: tr('movethewheels.ai.roadmap.dispatchDecisionCards.title', 'Dispatch decision cards'),
44
+ description: tr(
45
+ 'movethewheels.ai.roadmap.dispatchDecisionCards.description',
46
+ 'Proposed driver/vehicle assignments and carrier recommendations with rationale and confidence, requiring an explicit accept or reject before anything is written.'
47
+ ),
48
+ },
49
+ {
50
+ icon: Wallet,
51
+ title: tr('movethewheels.ai.roadmap.aiCreditVisibility.title', 'AI credit visibility'),
52
+ description: tr(
53
+ 'movethewheels.ai.roadmap.aiCreditVisibility.description',
54
+ 'Per-workspace AI spend for admins, so cost is visible before the invoice.'
55
+ ),
56
+ },
57
+ ];
58
+
49
59
  return (
50
60
  <PageLayout
51
- title="AI Operations"
52
- subtitle="What the AI is doing on your workspace, and why"
61
+ title={tr('movethewheels.ai.title', 'AI Operations')}
62
+ subtitle={tr('movethewheels.ai.subtitle', 'What the AI is doing on your workspace, and why')}
53
63
  icon={<Bot size={24} />}
54
64
  >
55
65
  <PagePurpose icon={<Bot size={18} />}>
56
- This page will surface AI-driven dispatch decisions and their outcomes once the shared AI
57
- runtime lands. It does not host a chat box — chat with your live operational data is always
58
- available from the assistant icon anywhere in the app.
66
+ {tr(
67
+ 'movethewheels.ai.purpose',
68
+ 'This page will surface AI-driven dispatch decisions and their outcomes once the shared AI runtime lands. It does not host a chat box — chat with your live operational data is always available from the assistant icon anywhere in the app.'
69
+ )}
59
70
  </PagePurpose>
60
71
 
61
72
  <GlassCard treatment="glass" className="p-4">
@@ -63,12 +74,13 @@ export default function AIAssistantPage() {
63
74
  <MessageCircle size={20} className="text-primary flex-shrink-0 mt-0.5" />
64
75
  <div>
65
76
  <p className="text-sm font-medium text-text-primary">
66
- Looking to ask a question about your operations?
77
+ {tr('movethewheels.ai.callout.title', 'Looking to ask a question about your operations?')}
67
78
  </p>
68
79
  <p className="text-sm text-text-secondary mt-1">
69
- Open the assistant from its icon in the corner of the screen — it answers from your
70
- live orders, shipments, fleet and inventory data, and it is the only chat surface in
71
- this product.
80
+ {tr(
81
+ 'movethewheels.ai.callout.description',
82
+ 'Open the assistant from its icon in the corner of the screen — it answers from your live orders, shipments, fleet and inventory data, and it is the only chat surface in this product.'
83
+ )}
72
84
  </p>
73
85
  </div>
74
86
  </div>
@@ -76,13 +88,19 @@ export default function AIAssistantPage() {
76
88
 
77
89
  <Card>
78
90
  <CardHeader>
79
- <CardTitle>On the roadmap</CardTitle>
91
+ <CardTitle>{tr('movethewheels.ai.roadmap.title', 'On the roadmap')}</CardTitle>
80
92
  </CardHeader>
81
93
  <CardContent>
82
94
  <EmptyState
83
95
  illustration="empty-agents"
84
- title="Autonomous dispatch operations aren't live yet"
85
- description="Autonomous dispatch isn't available yet — these capabilities are still in development. Nothing below is available today."
96
+ title={tr(
97
+ 'movethewheels.ai.emptyState.title',
98
+ "Autonomous dispatch operations aren't live yet"
99
+ )}
100
+ description={tr(
101
+ 'movethewheels.ai.emptyState.description',
102
+ "Autonomous dispatch isn't available yet — these capabilities are still in development. Nothing below is available today."
103
+ )}
86
104
  />
87
105
  <ul className="mt-4 space-y-4">
88
106
  {roadmapItems.map((item) => (