jac-client 0.2.13__py3-none-any.whl → 0.2.14__py3-none-any.whl
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.
- jac_client/examples/all-in-one/components/Header.jac +1 -1
- jac_client/examples/all-in-one/components/ProfitOverview.jac +1 -1
- jac_client/examples/all-in-one/components/Summary.jac +1 -1
- jac_client/examples/all-in-one/components/TransactionList.jac +2 -2
- jac_client/examples/all-in-one/components/navigation.jac +3 -9
- jac_client/examples/all-in-one/context/BudgetContext.jac +1 -1
- jac_client/examples/all-in-one/main.jac +5 -386
- jac_client/examples/all-in-one/pages/(auth)/index.jac +299 -0
- jac_client/examples/all-in-one/pages/{nestedDemo.jac → (auth)/nested.jac} +3 -13
- jac_client/examples/all-in-one/pages/{loginPage.jac → (public)/login.jac} +1 -1
- jac_client/examples/all-in-one/pages/{signupPage.jac → (public)/signup.jac} +1 -1
- jac_client/examples/all-in-one/pages/{notFound.jac → [...notFound].jac} +2 -1
- jac_client/examples/all-in-one/pages/budget.jac +11 -0
- jac_client/examples/all-in-one/pages/budget_planner_ui.cl.jac +1 -1
- jac_client/examples/all-in-one/pages/features.jac +8 -0
- jac_client/examples/all-in-one/pages/features_test_ui.cl.jac +7 -7
- jac_client/examples/all-in-one/pages/{LandingPage.jac → landing.jac} +4 -9
- jac_client/examples/all-in-one/pages/layout.jac +20 -0
- jac_client/examples/nested-folders/nested-advance/src/ButtonRoot.jac +1 -1
- jac_client/examples/nested-folders/nested-advance/src/level1/ButtonSecondL.jac +1 -1
- jac_client/examples/nested-folders/nested-advance/src/level1/level2/ButtonThirdL.jac +1 -1
- jac_client/plugin/client_runtime.cl.jac +4 -2
- jac_client/plugin/impl/client_runtime.impl.jac +12 -1
- jac_client/plugin/plugin_config.jac +4 -11
- jac_client/plugin/src/compiler.jac +15 -1
- jac_client/plugin/src/impl/compiler.impl.jac +216 -23
- jac_client/plugin/src/impl/package_installer.impl.jac +3 -2
- jac_client/plugin/src/impl/route_scanner.impl.jac +201 -0
- jac_client/plugin/src/impl/vite_bundler.impl.jac +15 -11
- jac_client/plugin/src/route_scanner.jac +44 -0
- jac_client/plugin/utils/impl/bun_installer.impl.jac +16 -19
- jac_client/plugin/utils/impl/client_deps.impl.jac +12 -16
- jac_client/templates/fullstack.jacpack +3 -2
- jac_client/tests/test_e2e.py +19 -28
- {jac_client-0.2.13.dist-info → jac_client-0.2.14.dist-info}/METADATA +2 -2
- {jac_client-0.2.13.dist-info → jac_client-0.2.14.dist-info}/RECORD +39 -35
- jac_client/examples/all-in-one/pages/BudgetPlanner.jac +0 -140
- jac_client/examples/all-in-one/pages/FeaturesTest.jac +0 -157
- {jac_client-0.2.13.dist-info → jac_client-0.2.14.dist-info}/WHEEL +0 -0
- {jac_client-0.2.13.dist-info → jac_client-0.2.14.dist-info}/entry_points.txt +0 -0
- {jac_client-0.2.13.dist-info → jac_client-0.2.14.dist-info}/top_level.txt +0 -0
|
@@ -6,7 +6,7 @@ cl import from .TransactionItem {
|
|
|
6
6
|
|
|
7
7
|
cl {
|
|
8
8
|
# Props: transactions list and delete handler
|
|
9
|
-
def:pub TransactionList(transactions: list, onDelete: any) ->
|
|
9
|
+
def:pub TransactionList(transactions: list, onDelete: any) -> JsxElement {
|
|
10
10
|
if transactions.length == 0 {
|
|
11
11
|
return
|
|
12
12
|
<div className="empty-state">
|
|
@@ -25,7 +25,7 @@ cl {
|
|
|
25
25
|
Transactions ({transactions.length})
|
|
26
26
|
</h3>
|
|
27
27
|
{transactions.map(
|
|
28
|
-
lambda tx: dict ->
|
|
28
|
+
lambda tx: dict -> JsxElement { return
|
|
29
29
|
<TransactionItem
|
|
30
30
|
key={tx["id"]}
|
|
31
31
|
id={tx["id"]}
|
|
@@ -7,7 +7,7 @@ cl import from "@jac/runtime" {
|
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
cl {
|
|
10
|
-
def:pub Navigation ->
|
|
10
|
+
def:pub Navigation -> JsxElement {
|
|
11
11
|
location = useLocation();
|
|
12
12
|
isLoggedIn = jacIsLoggedIn();
|
|
13
13
|
navigate = useNavigate();
|
|
@@ -93,19 +93,13 @@ cl {
|
|
|
93
93
|
<Link to="/nested" style={linkStyle("/nested")}>
|
|
94
94
|
Nested Imports
|
|
95
95
|
</Link>
|
|
96
|
-
<Link
|
|
97
|
-
to="/features-test"
|
|
98
|
-
style={linkStyle("/features-test")}
|
|
99
|
-
>
|
|
96
|
+
<Link to="/features" style={linkStyle("/features")}>
|
|
100
97
|
Features Test
|
|
101
98
|
</Link>
|
|
102
99
|
<Link to="/landing" style={linkStyle("/landing")}>
|
|
103
100
|
Landing Page
|
|
104
101
|
</Link>
|
|
105
|
-
<Link
|
|
106
|
-
to="/budget-planner"
|
|
107
|
-
style={linkStyle("/budget-planner")}
|
|
108
|
-
>
|
|
102
|
+
<Link to="/budget" style={linkStyle("/budget")}>
|
|
109
103
|
Budget Planner
|
|
110
104
|
</Link>
|
|
111
105
|
</>
|
|
@@ -11,7 +11,7 @@ cl {
|
|
|
11
11
|
glob:pub BudgetContext = createContext(None);
|
|
12
12
|
|
|
13
13
|
# Provider component - wraps app and provides budget state
|
|
14
|
-
def:pub BudgetProvider(children: any) ->
|
|
14
|
+
def:pub BudgetProvider(children: any) -> JsxElement {
|
|
15
15
|
budget = useBudget();
|
|
16
16
|
|
|
17
17
|
return
|
|
@@ -29,16 +29,7 @@ walker:pub get_server_message {
|
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
# Features Test Page - Backend Logic
|
|
33
|
-
# This file is intentionally kept empty to demonstrate the separation of concerns
|
|
34
|
-
# where UI logic resides in .cl.jac files and backend walker logic in app.jac
|
|
35
|
-
|
|
36
|
-
# All walker implementations for this feature are in main.jac
|
|
37
|
-
# This demonstrates that you can have separate .jac files for different purposes
|
|
38
32
|
# Features Test - Backend Walkers
|
|
39
|
-
# This file demonstrates walker functionality for testing various JAC features
|
|
40
|
-
|
|
41
|
-
# Node definition for storing test data
|
|
42
33
|
node TestData {
|
|
43
34
|
has message: str,
|
|
44
35
|
count: int = 0,
|
|
@@ -156,387 +147,15 @@ walker process_complex_data {
|
|
|
156
147
|
}
|
|
157
148
|
}
|
|
158
149
|
|
|
159
|
-
#
|
|
160
|
-
# Combined example: auth + routing + CSS styling + asset serving + nested folder imports
|
|
161
|
-
#
|
|
162
|
-
cl import from react { useEffect, useRef }
|
|
163
|
-
cl import from "@jac/runtime" {
|
|
164
|
-
Router,
|
|
165
|
-
Routes,
|
|
166
|
-
Route,
|
|
167
|
-
Link,
|
|
168
|
-
useNavigate,
|
|
169
|
-
Navigate,
|
|
170
|
-
jacIsLoggedIn
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
# Pure CSS + asset-in-CSS example
|
|
150
|
+
# Global CSS styles
|
|
174
151
|
cl import ".styles/styles.css";
|
|
175
152
|
|
|
176
|
-
#
|
|
177
|
-
cl import from .pages.loginPage { LoginPage }
|
|
178
|
-
|
|
179
|
-
# Signup Page
|
|
180
|
-
cl import from .pages.signupPage { SignupPage }
|
|
181
|
-
|
|
182
|
-
# Simple 404 page
|
|
183
|
-
cl import from .pages.notFound { NotFound }
|
|
184
|
-
|
|
185
|
-
# Navigation component with active link styling and auth
|
|
186
|
-
cl import from .components.navigation {
|
|
187
|
-
Navigation
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
# Page showing nested imports from different folders
|
|
191
|
-
cl import from .pages.nestedDemo {
|
|
192
|
-
NestedImportsDemo
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
cl import from .pages.FeaturesTest { FeaturesTest }
|
|
196
|
-
|
|
197
|
-
cl import from .pages.LandingPage { LandingPage }
|
|
198
|
-
|
|
199
|
-
cl import from .pages.BudgetPlanner { BudgetPlanner }
|
|
200
|
-
|
|
201
|
-
# Context provider
|
|
202
|
-
cl import from .context.BudgetContext { BudgetProvider }
|
|
203
|
-
|
|
204
|
-
# TypeScript component import
|
|
205
|
-
cl import from ".components/Card.tsx" { Card }
|
|
206
|
-
|
|
207
|
-
# Main app wrapped in Router (same API as with-router/ example)
|
|
153
|
+
# App wrapper -- file-based routing is handled automatically via pages/ directory
|
|
208
154
|
cl {
|
|
209
|
-
def:pub
|
|
210
|
-
# Check if user is logged in, redirect if not
|
|
211
|
-
if not jacIsLoggedIn() {
|
|
212
|
-
return
|
|
213
|
-
<Navigate to="/login" />;
|
|
214
|
-
}
|
|
215
|
-
has count: int = 0,
|
|
216
|
-
pingResult: str = "",
|
|
217
|
-
serverMessage: str = "",
|
|
218
|
-
lastTodoMessage: str = "";
|
|
219
|
-
|
|
220
|
-
can with count entry {
|
|
221
|
-
console.log("Home count changed: ", count);
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
# Call simple backend walkers
|
|
225
|
-
async def handlePing -> None {
|
|
226
|
-
result = root spawn ping_server();
|
|
227
|
-
if result.reports and result.reports.length > 0 {
|
|
228
|
-
pingResult = result.reports[0][0];
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
async def loadServerMessage -> None {
|
|
233
|
-
result = root spawn get_server_message();
|
|
234
|
-
if result.reports and result.reports.length > 0 {
|
|
235
|
-
serverMessage = result.reports[0][0];
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
# Create a sample Todo node in the graph with a hardcoded payload
|
|
240
|
-
async def handleCreateSampleTodo -> None {
|
|
241
|
-
result = root spawn create_todo(text="Sample todo from all-in-one app");
|
|
242
|
-
if result.reports and result.reports.length > 0 {
|
|
243
|
-
todo = result.reports[0][0];
|
|
244
|
-
lastTodoMessage = "Created Todo: " + todo.text;
|
|
245
|
-
console.log("Created Todo node:", todo);
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
async can with entry {
|
|
250
|
-
await loadServerMessage();
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
# Initialize a Web Worker and handle message-based communication
|
|
254
|
-
workerRef = useRef(None);
|
|
255
|
-
has message: str = "";
|
|
256
|
-
|
|
257
|
-
useEffect(
|
|
258
|
-
lambda -> None { workerRef.current = Reflect.construct(
|
|
259
|
-
Worker, ["/workers/worker.js"]
|
|
260
|
-
);workerRef.current.onmessage = lambda event: any -> None { console.log(
|
|
261
|
-
"Message received from worker:", event.data
|
|
262
|
-
);message = event.data;};return (
|
|
263
|
-
lambda -> None { workerRef.current.terminate();}
|
|
264
|
-
); },
|
|
265
|
-
[]
|
|
266
|
-
);
|
|
267
|
-
handleClick = lambda -> None { workerRef.current.postMessage("");};
|
|
268
|
-
|
|
155
|
+
def:pub app(children: any = None) -> any {
|
|
269
156
|
return
|
|
270
|
-
<div
|
|
271
|
-
|
|
272
|
-
"padding": "2rem",
|
|
273
|
-
"fontFamily": "system-ui, -apple-system, sans-serif"
|
|
274
|
-
}}
|
|
275
|
-
>
|
|
276
|
-
<h1>
|
|
277
|
-
🍔 Router + Styling + Assets Demo
|
|
278
|
-
</h1>
|
|
279
|
-
<p>
|
|
280
|
-
This home page combines
|
|
281
|
-
{" "}
|
|
282
|
-
<strong>
|
|
283
|
-
React Router,
|
|
284
|
-
</strong>
|
|
285
|
-
{" "}
|
|
286
|
-
<strong>
|
|
287
|
-
pure CSS styling,
|
|
288
|
-
</strong>
|
|
289
|
-
{" "}
|
|
290
|
-
<strong>
|
|
291
|
-
staticassets
|
|
292
|
-
</strong>
|
|
293
|
-
{" "}
|
|
294
|
-
and
|
|
295
|
-
{" "}
|
|
296
|
-
<strong>
|
|
297
|
-
nested folder imports
|
|
298
|
-
</strong>
|
|
299
|
-
</p>
|
|
300
|
-
<div className="container">
|
|
301
|
-
<h2
|
|
302
|
-
style={{
|
|
303
|
-
"color": "white",
|
|
304
|
-
"textShadow": "2px 2px 4px rgba(0,0,0,0.6)"
|
|
305
|
-
}}
|
|
306
|
-
>
|
|
307
|
-
CSS Background Image
|
|
308
|
-
</h2>
|
|
309
|
-
<p
|
|
310
|
-
style={{
|
|
311
|
-
"color": "white",
|
|
312
|
-
"maxWidth": "480px",
|
|
313
|
-
"textShadow": "1px 1px 3px rgba(0,0,0,0.7)"
|
|
314
|
-
}}
|
|
315
|
-
>
|
|
316
|
-
This section uses the burger image as a background via CSS, just like the
|
|
317
|
-
{" "}
|
|
318
|
-
<code>
|
|
319
|
-
asset-serving/css-with-image
|
|
320
|
-
</code>
|
|
321
|
-
{" "}
|
|
322
|
-
example.
|
|
323
|
-
</p>
|
|
324
|
-
</div>
|
|
325
|
-
<Card
|
|
326
|
-
title="TypeScript Card Component"
|
|
327
|
-
description="This card is built with TypeScript and demonstrates type-safe component usage in Jac"
|
|
328
|
-
variant="highlighted"
|
|
329
|
-
>
|
|
330
|
-
<p style={{"margin": "0.5rem 0", "color": "#374151"}}>
|
|
331
|
-
This is a TypeScript component imported and used in Jac code!
|
|
332
|
-
</p>
|
|
333
|
-
</Card>
|
|
334
|
-
<div className="card">
|
|
335
|
-
<h3>
|
|
336
|
-
Direct <img> asset
|
|
337
|
-
</h3>
|
|
338
|
-
<img
|
|
339
|
-
src="/static/assets/burger.png"
|
|
340
|
-
alt="Burger asset served by Jac"
|
|
341
|
-
className="burgerImage"
|
|
342
|
-
/>
|
|
343
|
-
<p style={{"marginTop": "0.75rem", "color": "#555"}}>
|
|
344
|
-
This image is served from the project
|
|
345
|
-
{" "}
|
|
346
|
-
<code>
|
|
347
|
-
assets/
|
|
348
|
-
</code>
|
|
349
|
-
{" "}
|
|
350
|
-
folder using the
|
|
351
|
-
{" "}
|
|
352
|
-
<code>
|
|
353
|
-
/static/assets/
|
|
354
|
-
</code>
|
|
355
|
-
{" "}
|
|
356
|
-
path.
|
|
357
|
-
</p>
|
|
358
|
-
</div>
|
|
359
|
-
<div style={{"marginTop": "2rem"}}>
|
|
360
|
-
<h3>
|
|
361
|
-
Counter with pure CSS classes
|
|
362
|
-
</h3>
|
|
363
|
-
<p>
|
|
364
|
-
You've clicked the burger
|
|
365
|
-
{" "}
|
|
366
|
-
<strong>
|
|
367
|
-
{count}
|
|
368
|
-
</strong>
|
|
369
|
-
{" "}
|
|
370
|
-
times.
|
|
371
|
-
</p>
|
|
372
|
-
<button
|
|
373
|
-
onClick={lambda e: any -> None { count = count + 1;}}
|
|
374
|
-
style={{
|
|
375
|
-
"padding": "0.6rem 1.4rem",
|
|
376
|
-
"fontSize": "1rem",
|
|
377
|
-
"backgroundColor": "#ff6b35",
|
|
378
|
-
"color": "white",
|
|
379
|
-
"border": "none",
|
|
380
|
-
"borderRadius": "6px",
|
|
381
|
-
"cursor": "pointer",
|
|
382
|
-
"boxShadow": "0 2px 4px rgba(0,0,0,0.2)"
|
|
383
|
-
}}
|
|
384
|
-
>
|
|
385
|
-
Click the Burger! 🍔
|
|
386
|
-
</button>
|
|
387
|
-
</div>
|
|
388
|
-
<div style={{"marginTop": "2rem"}}>
|
|
389
|
-
<h3>
|
|
390
|
-
Backend Walkers
|
|
391
|
-
</h3>
|
|
392
|
-
<p>
|
|
393
|
-
Basic example walkers:
|
|
394
|
-
{" "}
|
|
395
|
-
<code>
|
|
396
|
-
ping_server
|
|
397
|
-
</code>
|
|
398
|
-
{" "}
|
|
399
|
-
and
|
|
400
|
-
{" "}
|
|
401
|
-
<code>
|
|
402
|
-
get_server_message
|
|
403
|
-
</code>
|
|
404
|
-
</p>
|
|
405
|
-
<button
|
|
406
|
-
onClick={lambda e: any -> None { handlePing();}}
|
|
407
|
-
style={{
|
|
408
|
-
"padding": "0.5rem 1.2rem",
|
|
409
|
-
"marginRight": "0.75rem",
|
|
410
|
-
"backgroundColor": "#3b82f6",
|
|
411
|
-
"color": "white",
|
|
412
|
-
"border": "none",
|
|
413
|
-
"borderRadius": "6px",
|
|
414
|
-
"cursor": "pointer"
|
|
415
|
-
}}
|
|
416
|
-
>
|
|
417
|
-
Ping Backend
|
|
418
|
-
</button>
|
|
419
|
-
<button
|
|
420
|
-
onClick={lambda e: any -> None { handleCreateSampleTodo();}}
|
|
421
|
-
style={{
|
|
422
|
-
"padding": "0.5rem 1.2rem",
|
|
423
|
-
"backgroundColor": "#10b981",
|
|
424
|
-
"color": "white",
|
|
425
|
-
"border": "none",
|
|
426
|
-
"borderRadius": "6px",
|
|
427
|
-
"cursor": "pointer"
|
|
428
|
-
}}
|
|
429
|
-
>
|
|
430
|
-
Create Sample Todo
|
|
431
|
-
</button>
|
|
432
|
-
{pingResult
|
|
433
|
-
and (
|
|
434
|
-
<span style={{"marginLeft": "0.5rem", "color": "#374151"}}>
|
|
435
|
-
Result:
|
|
436
|
-
{" "}
|
|
437
|
-
<code>
|
|
438
|
-
{pingResult}
|
|
439
|
-
</code>
|
|
440
|
-
</span>
|
|
441
|
-
)}
|
|
442
|
-
{serverMessage
|
|
443
|
-
and (
|
|
444
|
-
<p style={{"marginTop": "0.75rem", "color": "#374151"}}>
|
|
445
|
-
Message:
|
|
446
|
-
{" "}
|
|
447
|
-
<code>
|
|
448
|
-
{serverMessage}
|
|
449
|
-
</code>
|
|
450
|
-
</p>
|
|
451
|
-
)}
|
|
452
|
-
{lastTodoMessage
|
|
453
|
-
and (
|
|
454
|
-
<p style={{"marginTop": "0.5rem", "color": "#111827"}}>
|
|
455
|
-
{lastTodoMessage}
|
|
456
|
-
</p>
|
|
457
|
-
)}
|
|
458
|
-
</div>
|
|
459
|
-
<div style={{"marginTop": "2rem"}}>
|
|
460
|
-
<h3>
|
|
461
|
-
Web Worker
|
|
462
|
-
</h3>
|
|
463
|
-
<p>
|
|
464
|
-
This demonstrates how to communicate with a
|
|
465
|
-
{" "}
|
|
466
|
-
<strong>
|
|
467
|
-
Python backend worker
|
|
468
|
-
</strong>
|
|
469
|
-
{" "}
|
|
470
|
-
using Web Workers for asynchronous processing.
|
|
471
|
-
</p>
|
|
472
|
-
<p
|
|
473
|
-
style={{
|
|
474
|
-
"fontSize": "0.9rem",
|
|
475
|
-
"color": "#666",
|
|
476
|
-
"marginTop": "0.5rem"
|
|
477
|
-
}}
|
|
478
|
-
>
|
|
479
|
-
File:
|
|
480
|
-
{" "}
|
|
481
|
-
<code>
|
|
482
|
-
worker.py
|
|
483
|
-
</code>
|
|
484
|
-
{" "}
|
|
485
|
-
— Runs in a separate thread to avoid blocking the UI.
|
|
486
|
-
</p>
|
|
487
|
-
<button
|
|
488
|
-
onClick={lambda -> None { handleClick();}}
|
|
489
|
-
style={{
|
|
490
|
-
"padding": "0.5rem 1.2rem",
|
|
491
|
-
"marginRight": "0.75rem",
|
|
492
|
-
"backgroundColor": "#d73bf6ff",
|
|
493
|
-
"color": "white",
|
|
494
|
-
"border": "none",
|
|
495
|
-
"borderRadius": "6px",
|
|
496
|
-
"cursor": "pointer"
|
|
497
|
-
}}
|
|
498
|
-
>
|
|
499
|
-
Call Python Worker
|
|
500
|
-
</button>
|
|
501
|
-
{message
|
|
502
|
-
&& (
|
|
503
|
-
<p style={{marginTop: "1rem", fontWeight: "bold"}}>
|
|
504
|
-
{message}
|
|
505
|
-
</p>
|
|
506
|
-
)}
|
|
507
|
-
</div>
|
|
157
|
+
<div style={{"fontFamily": "system-ui, -apple-system, sans-serif"}}>
|
|
158
|
+
{children}
|
|
508
159
|
</div>;
|
|
509
160
|
}
|
|
510
|
-
|
|
511
|
-
def:pub app -> any {
|
|
512
|
-
return
|
|
513
|
-
<Router>
|
|
514
|
-
<div style={{"fontFamily": "system-ui, -apple-system, sans-serif"}}>
|
|
515
|
-
<Navigation />
|
|
516
|
-
<div
|
|
517
|
-
style={{
|
|
518
|
-
"maxWidth": "960px",
|
|
519
|
-
"margin": "0 auto",
|
|
520
|
-
"padding": "0 1rem 3rem 1rem"
|
|
521
|
-
}}
|
|
522
|
-
>
|
|
523
|
-
<Routes>
|
|
524
|
-
<Route path="/" element={<HomePage />} />
|
|
525
|
-
<Route path="/login" element={<LoginPage />} />
|
|
526
|
-
<Route path="/signup" element={<SignupPage />} />
|
|
527
|
-
<Route path="/nested" element={<NestedImportsDemo />} />
|
|
528
|
-
<Route path="/features-test" element={<FeaturesTest />} />
|
|
529
|
-
<Route path="/landing" element={<LandingPage />} />
|
|
530
|
-
<Route
|
|
531
|
-
path="/budget-planner"
|
|
532
|
-
element={<BudgetProvider>
|
|
533
|
-
<BudgetPlanner />
|
|
534
|
-
</BudgetProvider>}
|
|
535
|
-
/>
|
|
536
|
-
<Route path="*" element={<NotFound />} />
|
|
537
|
-
</Routes>
|
|
538
|
-
</div>
|
|
539
|
-
</div>
|
|
540
|
-
</Router>;
|
|
541
|
-
}
|
|
542
161
|
}
|