jac-client 0.2.8__py3-none-any.whl → 0.2.11__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.
Files changed (119) hide show
  1. jac_client/examples/all-in-one/button.jac +4 -3
  2. jac_client/examples/all-in-one/components/CategoryFilter.jac +36 -24
  3. jac_client/examples/all-in-one/components/Header.jac +12 -8
  4. jac_client/examples/all-in-one/components/ProfitOverview.jac +49 -35
  5. jac_client/examples/all-in-one/components/Summary.jac +59 -36
  6. jac_client/examples/all-in-one/components/TransactionForm.jac +142 -112
  7. jac_client/examples/all-in-one/components/TransactionItem.jac +37 -30
  8. jac_client/examples/all-in-one/components/TransactionList.jac +33 -26
  9. jac_client/examples/all-in-one/components/button.jac +4 -3
  10. jac_client/examples/all-in-one/components/navigation.jac +111 -117
  11. jac_client/examples/all-in-one/constants/categories.jac +23 -24
  12. jac_client/examples/all-in-one/constants/clients.jac +7 -8
  13. jac_client/examples/all-in-one/context/BudgetContext.jac +9 -6
  14. jac_client/examples/all-in-one/hooks/useBudget.jac +18 -12
  15. jac_client/examples/all-in-one/hooks/useLocalStorage.jac +14 -13
  16. jac_client/examples/all-in-one/main.jac +542 -0
  17. jac_client/examples/all-in-one/pages/BudgetPlanner.jac +26 -12
  18. jac_client/examples/all-in-one/pages/FeaturesTest.jac +43 -12
  19. jac_client/examples/all-in-one/pages/LandingPage.jac +113 -90
  20. jac_client/examples/all-in-one/pages/budget_planner_ui.cl.jac +65 -0
  21. jac_client/examples/all-in-one/pages/features_test_ui.cl.jac +675 -0
  22. jac_client/examples/all-in-one/pages/loginPage.jac +114 -119
  23. jac_client/examples/all-in-one/pages/nestedDemo.jac +44 -51
  24. jac_client/examples/all-in-one/pages/notFound.jac +15 -21
  25. jac_client/examples/all-in-one/pages/signupPage.jac +113 -119
  26. jac_client/examples/all-in-one/utils/formatters.jac +5 -8
  27. jac_client/examples/asset-serving/css-with-image/main.jac +92 -0
  28. jac_client/examples/asset-serving/image-asset/main.jac +56 -0
  29. jac_client/examples/asset-serving/import-alias/main.jac +109 -0
  30. jac_client/examples/basic/main.jac +23 -0
  31. jac_client/examples/basic-auth/main.jac +363 -0
  32. jac_client/examples/basic-auth-with-router/main.jac +451 -0
  33. jac_client/examples/basic-full-stack/main.jac +362 -0
  34. jac_client/examples/css-styling/js-styling/main.jac +63 -0
  35. jac_client/examples/css-styling/material-ui/main.jac +122 -0
  36. jac_client/examples/css-styling/pure-css/main.jac +55 -0
  37. jac_client/examples/css-styling/sass-example/main.jac +55 -0
  38. jac_client/examples/css-styling/styled-components/main.jac +62 -0
  39. jac_client/examples/css-styling/tailwind-example/main.jac +74 -0
  40. jac_client/examples/full-stack-with-auth/main.jac +696 -0
  41. jac_client/examples/little-x/main.jac +681 -0
  42. jac_client/examples/little-x/src/submit-button.jac +15 -14
  43. jac_client/examples/nested-folders/nested-advance/main.jac +26 -0
  44. jac_client/examples/nested-folders/nested-advance/src/ButtonRoot.jac +4 -6
  45. jac_client/examples/nested-folders/nested-advance/src/level1/ButtonSecondL.jac +9 -13
  46. jac_client/examples/nested-folders/nested-advance/src/level1/Card.jac +29 -32
  47. jac_client/examples/nested-folders/nested-advance/src/level1/level2/ButtonThirdL.jac +12 -18
  48. jac_client/examples/nested-folders/nested-basic/{src/app.jac → main.jac} +7 -5
  49. jac_client/examples/nested-folders/nested-basic/src/button.jac +4 -3
  50. jac_client/examples/nested-folders/nested-basic/src/components/button.jac +4 -3
  51. jac_client/examples/ts-support/main.jac +35 -0
  52. jac_client/examples/with-router/main.jac +286 -0
  53. jac_client/plugin/cli.jac +491 -411
  54. jac_client/plugin/client.jac +25 -0
  55. jac_client/plugin/client_runtime.cl.jac +10 -4
  56. jac_client/plugin/impl/client.impl.jac +96 -55
  57. jac_client/plugin/impl/client_runtime.impl.jac +155 -1
  58. jac_client/plugin/plugin_config.jac +211 -29
  59. jac_client/plugin/src/__init__.jac +0 -2
  60. jac_client/plugin/src/compiler.jac +0 -1
  61. jac_client/plugin/src/config_loader.jac +1 -0
  62. jac_client/plugin/src/desktop_config.jac +31 -0
  63. jac_client/plugin/src/impl/compiler.impl.jac +49 -17
  64. jac_client/plugin/src/impl/config_loader.impl.jac +8 -0
  65. jac_client/plugin/src/impl/desktop_config.impl.jac +191 -0
  66. jac_client/plugin/src/impl/jac_to_js.impl.jac +5 -1
  67. jac_client/plugin/src/impl/package_installer.impl.jac +20 -20
  68. jac_client/plugin/src/impl/vite_bundler.impl.jac +191 -64
  69. jac_client/plugin/src/targets/desktop/sidecar/main.py +144 -0
  70. jac_client/plugin/src/targets/desktop_target.jac +37 -0
  71. jac_client/plugin/src/targets/impl/desktop_target.impl.jac +2347 -0
  72. jac_client/plugin/src/targets/impl/registry.impl.jac +64 -0
  73. jac_client/plugin/src/targets/impl/web_target.impl.jac +157 -0
  74. jac_client/plugin/src/targets/register.jac +21 -0
  75. jac_client/plugin/src/targets/registry.jac +87 -0
  76. jac_client/plugin/src/targets/web_target.jac +35 -0
  77. jac_client/plugin/src/vite_bundler.jac +6 -0
  78. jac_client/plugin/utils/__init__.jac +3 -0
  79. jac_client/plugin/utils/bun_installer.jac +16 -0
  80. jac_client/plugin/utils/impl/bun_installer.impl.jac +99 -0
  81. jac_client/templates/client.jacpack +72 -0
  82. jac_client/templates/fullstack.jacpack +61 -0
  83. jac_client/tests/conftest.py +103 -47
  84. jac_client/tests/fixtures/spawn_test/app.jac +49 -52
  85. jac_client/tests/fixtures/with-ts/app.jac +27 -27
  86. jac_client/tests/test_cli.py +182 -71
  87. jac_client/tests/test_e2e.py +232 -0
  88. jac_client/tests/test_helpers.py +58 -0
  89. jac_client/tests/test_it.py +91 -135
  90. jac_client/tests/test_it_desktop.py +891 -0
  91. {jac_client-0.2.8.dist-info → jac_client-0.2.11.dist-info}/METADATA +6 -6
  92. jac_client-0.2.11.dist-info/RECORD +113 -0
  93. {jac_client-0.2.8.dist-info → jac_client-0.2.11.dist-info}/WHEEL +1 -1
  94. jac_client/examples/all-in-one/app.jac +0 -573
  95. jac_client/examples/all-in-one/pages/BudgetPlanner.cl.jac +0 -70
  96. jac_client/examples/all-in-one/pages/FeaturesTest.cl.jac +0 -552
  97. jac_client/examples/asset-serving/css-with-image/src/app.jac +0 -88
  98. jac_client/examples/asset-serving/image-asset/src/app.jac +0 -55
  99. jac_client/examples/asset-serving/import-alias/src/app.jac +0 -111
  100. jac_client/examples/basic/src/app.jac +0 -21
  101. jac_client/examples/basic-auth/src/app.jac +0 -371
  102. jac_client/examples/basic-auth-with-router/src/app.jac +0 -464
  103. jac_client/examples/basic-full-stack/src/app.jac +0 -359
  104. jac_client/examples/css-styling/js-styling/src/app.jac +0 -84
  105. jac_client/examples/css-styling/material-ui/src/app.jac +0 -122
  106. jac_client/examples/css-styling/pure-css/src/app.jac +0 -64
  107. jac_client/examples/css-styling/sass-example/src/app.jac +0 -64
  108. jac_client/examples/css-styling/styled-components/src/app.jac +0 -71
  109. jac_client/examples/css-styling/tailwind-example/src/app.jac +0 -63
  110. jac_client/examples/full-stack-with-auth/src/app.jac +0 -722
  111. jac_client/examples/little-x/src/app.jac +0 -719
  112. jac_client/examples/nested-folders/nested-advance/src/app.jac +0 -35
  113. jac_client/examples/ts-support/src/app.jac +0 -35
  114. jac_client/examples/with-router/src/app.jac +0 -323
  115. jac_client/plugin/src/babel_processor.jac +0 -18
  116. jac_client/plugin/src/impl/babel_processor.impl.jac +0 -89
  117. jac_client-0.2.8.dist-info/RECORD +0 -97
  118. {jac_client-0.2.8.dist-info → jac_client-0.2.11.dist-info}/entry_points.txt +0 -0
  119. {jac_client-0.2.8.dist-info → jac_client-0.2.11.dist-info}/top_level.txt +0 -0
@@ -1,573 +0,0 @@
1
- import from datetime { datetime, timedelta }
2
-
3
- #
4
- # Basic backend walkers
5
- #
6
- node Todo {
7
- has text: str,
8
- done: bool = False;
9
- }
10
-
11
- walker create_todo {
12
- has text: str;
13
-
14
- can create with `root entry {
15
- new_todo = here ++> Todo(text=self.text);
16
- report new_todo ;
17
- }
18
- }
19
-
20
- walker ping_server {
21
- can ping with `root entry {
22
- report "pong from backend!" ;
23
- }
24
- }
25
-
26
- walker get_server_message {
27
- can info with `root entry {
28
- report "hello from a basic walker!" ;
29
- }
30
- }
31
-
32
-
33
-
34
- # Features Test Page - Backend Logic
35
- # This file is intentionally kept empty to demonstrate the separation of concerns
36
- # where UI logic resides in .cl.jac files and backend walker logic in app.jac
37
-
38
- # All walker implementations for this feature are in src/app.jac
39
- # This demonstrates that you can have separate .jac files for different purposes
40
- # Features Test - Backend Walkers
41
- # This file demonstrates walker functionality for testing various JAC features
42
-
43
-
44
- # Node definition for storing test data
45
- node TestData {
46
- has message: str;
47
- has count: int = 0;
48
- has created_at: str = "";
49
- }
50
-
51
- # Walker: Create test data
52
- walker create_test_data {
53
- has message: str;
54
-
55
- can create with `root entry {
56
- new_data = here ++> TestData(
57
- message=self.message,
58
- count=1,
59
- created_at=datetime.now().strftime("%Y-%m-%d %H:%M:%S")
60
- );
61
- report new_data;
62
- }
63
- }
64
-
65
- # Walker: Read all test data
66
- walker read_test_data {
67
- can read with `root entry {
68
- visit [-->(`?TestData)];
69
- }
70
-
71
- can report_data with exit {
72
- report here;
73
- }
74
- }
75
-
76
- # Walker: Update test data
77
- walker update_test_data {
78
- has new_message: str;
79
-
80
- can update with TestData entry {
81
- here.message = self.new_message;
82
- here.count = here.count + 1;
83
- report here;
84
- }
85
- }
86
-
87
- # Walker: Delete test data
88
- walker delete_test_data {
89
- can delete with TestData entry {
90
- del here;
91
- report {"status": "deleted"};
92
- }
93
- }
94
-
95
- # Walker: String manipulation test
96
- walker test_string_methods {
97
- has input_text: str;
98
-
99
- can process with `root entry {
100
- result = {
101
- "original": self.input_text,
102
- "uppercase": self.input_text.upper(),
103
- "lowercase": self.input_text.lower(),
104
- "capitalized": self.input_text.capitalize(),
105
- "reversed": self.input_text[::-1],
106
- "length": len(self.input_text),
107
- "words": self.input_text.split(),
108
- "trimmed": self.input_text.strip(),
109
- "replaced": self.input_text.replace("test", "demo")
110
- };
111
- report result;
112
- }
113
- }
114
-
115
- # Walker: Array/List operations test
116
- walker test_list_operations {
117
- has numbers: list;
118
-
119
- can process with `root entry {
120
- result = {
121
- "original": self.numbers,
122
- "sorted": sorted(self.numbers),
123
- "reversed": list(reversed(self.numbers)),
124
- "sum": sum(self.numbers),
125
- "max": max(self.numbers) if len(self.numbers) > 0 else 0,
126
- "min": min(self.numbers) if len(self.numbers) > 0 else 0,
127
- "length": len(self.numbers),
128
- "doubled": [x * 2 for x in self.numbers]
129
- };
130
- report result;
131
- }
132
- }
133
-
134
- # Walker: Complex data processing
135
- walker process_complex_data {
136
- has items: list;
137
-
138
- can process with `root entry {
139
- processed = [];
140
- for item in self.items {
141
- processed.append({
142
- "id": item.get("id", 0),
143
- "name": item.get("name", "").upper(),
144
- "value": item.get("value", 0) * 2,
145
- "processed_at": datetime.now().strftime("%H:%M:%S")
146
- });
147
- }
148
-
149
- result = {
150
- "original_count": len(self.items),
151
- "processed_count": len(processed),
152
- "items": processed,
153
- "total_value": sum([p["value"] for p in processed])
154
- };
155
-
156
- report result;
157
- }
158
- }
159
-
160
-
161
- #
162
- # Combined example: auth + routing + CSS styling + asset serving + nested folder imports
163
- #
164
- cl import from react { useEffect, useRef }
165
- cl import from "@jac-client/utils" {
166
- Router,
167
- Routes,
168
- Route,
169
- Link,
170
- useNavigate,
171
- Navigate,
172
- jacIsLoggedIn
173
-
174
- }
175
-
176
- # Pure CSS + asset-in-CSS example
177
- cl import ".styles.css";
178
-
179
- # Login Page
180
- cl import from .pages.loginPage { LoginPage }
181
-
182
- # Signup Page
183
- cl import from .pages.signupPage { SignupPage }
184
-
185
- # Simple 404 page
186
- cl import from .pages.notFound { NotFound }
187
-
188
- # Navigation component with active link styling and auth
189
- cl import from .components.navigation { Navigation }
190
-
191
- # Page showing nested imports from different folders
192
- cl import from .pages.nestedDemo { NestedImportsDemo }
193
-
194
- cl import from .pages.FeaturesTest { FeaturesTest }
195
-
196
- cl import from .pages.LandingPage { LandingPage }
197
-
198
- cl import from .pages.BudgetPlanner { BudgetPlanner }
199
-
200
- # Context provider
201
- cl import from .context.BudgetContext { BudgetProvider }
202
-
203
-
204
-
205
- # TypeScript component import
206
- cl import from ".components/Card.tsx" { Card }
207
-
208
-
209
- # Main app wrapped in Router (same API as with-router/ example)
210
- cl {
211
- def:pub HomePage -> any {
212
- # Check if user is logged in, redirect if not
213
- if not jacIsLoggedIn() {
214
- return <Navigate to="/login" />;
215
- }
216
- has count: int = 0;
217
- has pingResult: str = "";
218
- has serverMessage: str = "";
219
- has lastTodoMessage: str = "";
220
-
221
- useEffect(
222
- lambda -> None{ console.log("Home count changed: ", count);} , [count]
223
- );
224
-
225
- # Call simple backend walkers
226
- async def handlePing -> None {
227
- result = root spawn ping_server();
228
- if result.reports and result.reports.length > 0 {
229
- pingResult = result.reports[0][0];
230
- }
231
- }
232
-
233
- async def loadServerMessage -> None {
234
- result = root spawn get_server_message();
235
- if result.reports and result.reports.length > 0 {
236
- serverMessage = result.reports[0][0];
237
- }
238
- }
239
-
240
- # Create a sample Todo node in the graph with a hardcoded payload
241
- async def handleCreateSampleTodo -> None {
242
- result = root spawn create_todo(text="Sample todo from all-in-one app");
243
- if result.reports and result.reports.length > 0 {
244
- todo = result.reports[0][0];
245
- lastTodoMessage = "Created Todo: " + todo.text;
246
- console.log("Created Todo node:", todo);
247
- }
248
- }
249
-
250
- useEffect(lambda -> None{ loadServerMessage();} , []);
251
-
252
- # Initialize a Web Worker and handle message-based communication
253
- workerRef = useRef(None);
254
- has message: str = "";
255
-
256
- useEffect(lambda -> None {
257
- workerRef.current = Reflect.construct(Worker, ["/workers/worker.js"]);
258
- workerRef.current.onmessage = lambda event: any -> None {
259
- console.log("Message received from worker:", event.data);
260
- message = event.data;
261
- };
262
- return (lambda -> None {
263
- workerRef.current.terminate();
264
- });
265
- }, []);
266
- handleClick = lambda -> None {
267
- workerRef.current.postMessage("");
268
- };
269
-
270
- return <div
271
- style={{
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
- static assets
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
331
- style={{"margin": "0.5rem 0", "color": "#374151"}}
332
- >
333
- This is a TypeScript component imported and used in Jac code!
334
- </p>
335
- </Card>
336
- <div className="card">
337
- <h3>
338
- Direct &lt;img&gt; asset
339
- </h3>
340
- <img
341
- src="/static/assets/burger.png"
342
- alt="Burger asset served by Jac"
343
- className="burgerImage"
344
- />
345
- <p
346
- style={{"marginTop": "0.75rem", "color": "#555"}}
347
- >
348
- This image is served from the project
349
- {" "}
350
- <code>
351
- assets/
352
- </code>
353
- {" "}
354
- folder using the
355
- {" "}
356
- <code>
357
- /static/assets/
358
- </code>
359
- {" "}
360
- path.
361
- </p>
362
- </div>
363
- <div
364
- style={{"marginTop": "2rem"}}
365
- >
366
- <h3>
367
- Counter with pure CSS classes
368
- </h3>
369
- <p>
370
- You've clicked the burger
371
- {" "}
372
- <strong>
373
- {count}
374
- </strong>
375
- {" "}
376
- times.
377
- </p>
378
- <button
379
- onClick={lambda e: any -> None{ count = count + 1;} }
380
- style={{
381
- "padding": "0.6rem 1.4rem",
382
- "fontSize": "1rem",
383
- "backgroundColor": "#ff6b35",
384
- "color": "white",
385
- "border": "none",
386
- "borderRadius": "6px",
387
- "cursor": "pointer",
388
- "boxShadow": "0 2px 4px rgba(0,0,0,0.2)"
389
- }}
390
- >
391
- Click the Burger! 🍔
392
- </button>
393
- </div>
394
- <div
395
- style={{"marginTop": "2rem"}}
396
- >
397
- <h3>
398
- Backend Walkers
399
- </h3>
400
- <p>
401
- Basic example walkers:
402
- {" "}
403
- <code>
404
- ping_server
405
- </code>
406
- {" "}
407
- and
408
- {" "}
409
- <code>
410
- get_server_message
411
- </code>
412
- </p>
413
- <button
414
- onClick={lambda e: any -> None{ handlePing();} }
415
- style={{
416
- "padding": "0.5rem 1.2rem",
417
- "marginRight": "0.75rem",
418
- "backgroundColor": "#3b82f6",
419
- "color": "white",
420
- "border": "none",
421
- "borderRadius": "6px",
422
- "cursor": "pointer"
423
- }}
424
- >
425
- Ping Backend
426
- </button>
427
- <button
428
- onClick={lambda e: any -> None{ handleCreateSampleTodo();} }
429
- style={{
430
- "padding": "0.5rem 1.2rem",
431
- "backgroundColor": "#10b981",
432
- "color": "white",
433
- "border": "none",
434
- "borderRadius": "6px",
435
- "cursor": "pointer"
436
- }}
437
- >
438
- Create Sample Todo
439
- </button>
440
- {pingResult
441
- and (
442
- <span
443
- style={{"marginLeft": "0.5rem", "color": "#374151"}}
444
- >
445
- Result:
446
- {" "}
447
- <code>
448
- {pingResult}
449
- </code>
450
- </span>
451
- )}
452
- {serverMessage
453
- and (
454
- <p
455
- style={{"marginTop": "0.75rem", "color": "#374151"}}
456
- >
457
- Message:
458
- {" "}
459
- <code>
460
- {serverMessage}
461
- </code>
462
- </p>
463
- )}
464
- {lastTodoMessage
465
- and (
466
- <p
467
- style={{"marginTop": "0.5rem", "color": "#111827"}}
468
- >
469
- {lastTodoMessage}
470
- </p>
471
- )}
472
- </div>
473
- <div
474
- style={{"marginTop": "2rem"}}
475
- >
476
- <h3>
477
- Web Worker
478
- </h3>
479
- <p>
480
- This demonstrates how to communicate with a
481
- {" "}
482
- <strong>Python backend worker</strong>
483
- {" "}
484
- using Web Workers for asynchronous processing.
485
- </p>
486
- <p
487
- style={{"fontSize": "0.9rem", "color": "#666", "marginTop": "0.5rem"}}
488
- >
489
- File:
490
- {" "}
491
- <code>
492
- worker.py
493
- </code>
494
- {" "}
495
- — Runs in a separate thread to avoid blocking the UI.
496
- </p>
497
- <button
498
- onClick={lambda -> None { handleClick(); }}
499
- style={{
500
- "padding": "0.5rem 1.2rem",
501
- "marginRight": "0.75rem",
502
- "backgroundColor": "#d73bf6ff",
503
- "color": "white",
504
- "border": "none",
505
- "borderRadius": "6px",
506
- "cursor": "pointer"
507
- }}
508
- >
509
- Call Python Worker
510
- </button>
511
- {message && (
512
- <p style={{ marginTop: "1rem", fontWeight: "bold" }}>
513
- {message}
514
- </p>
515
- )}
516
- </div>
517
- </div>;
518
- }
519
-
520
- def:pub app -> any {
521
- return <Router>
522
- <div
523
- style={{"fontFamily": "system-ui, -apple-system, sans-serif"}}
524
- >
525
- <Navigation />
526
- <div
527
- style={{
528
- "maxWidth": "960px",
529
- "margin": "0 auto",
530
- "padding": "0 1rem 3rem 1rem"
531
- }}
532
- >
533
- <Routes>
534
- <Route
535
- path="/"
536
- element={<HomePage />}
537
- />
538
- <Route
539
- path="/login"
540
- element={<LoginPage />}
541
- />
542
- <Route
543
- path="/signup"
544
- element={<SignupPage />}
545
- />
546
- <Route
547
- path="/nested"
548
- element={<NestedImportsDemo />}
549
- />
550
- <Route
551
- path="/features-test"
552
- element={<FeaturesTest />}
553
- />
554
- <Route
555
- path="/landing"
556
- element={<LandingPage />}
557
- />
558
- <Route
559
- path="/budget-planner"
560
- element={<BudgetProvider>
561
- <BudgetPlanner />
562
- </BudgetProvider>}
563
- />
564
- <Route
565
- path="*"
566
- element={<NotFound />}
567
- />
568
- </Routes>
569
- </div>
570
- </div>
571
- </Router>;
572
- }
573
- }
@@ -1,70 +0,0 @@
1
- # Budget Planner Page
2
- # Main application page with budget tracking features
3
-
4
- # Local JAC file imports
5
- cl import from ..context.BudgetContext { useBudgetContext }
6
- cl import from ..components.Header { Header }
7
- cl import from ..components.Summary { Summary }
8
- cl import from ..components.ProfitOverview { ProfitOverview }
9
- cl import from ..components.TransactionForm { TransactionForm }
10
- cl import from ..components.TransactionList { TransactionList }
11
- cl import from ..components.CategoryFilter { CategoryFilter }
12
- cl import from ..constants.categories { CATEGORY_COLORS }
13
-
14
- # cl import from "..components.PieChart.tsx" { PieChart }
15
-
16
-
17
- cl def:pub BudgetPlanner() -> any {
18
- [filter, setFilter] = useState("ALL");
19
- budget = useBudgetContext();
20
-
21
- # Filter transactions based on selected category
22
- filtered = budget["transactions"];
23
- if filter != "ALL" {
24
- filtered = filtered.filter(lambda tx: dict -> bool {
25
- return tx["category"] == filter;
26
- });
27
- }
28
-
29
- # Sort by date (newest first)
30
- sorted = filtered.slice().sort(lambda a: dict, b: dict -> int {
31
- return Reflect.construct(Date, [b["date"]]).getTime() - Reflect.construct(Date, [a["date"]]).getTime();
32
- });
33
-
34
- # Prepare chart data with colors
35
- chartData = budget["expensesByCategory"].map(lambda item: dict -> dict {
36
- return {
37
- "name": item["name"],
38
- "value": item["value"],
39
- "color": CATEGORY_COLORS[item["name"]]
40
- };
41
- });
42
-
43
- return <div className="app-container">
44
- <Header />
45
-
46
- <main className="main-content">
47
- <div className="left-panel">
48
- <Summary />
49
- <ProfitOverview />
50
- <TransactionForm />
51
- <CategoryFilter
52
- selectedCategory={filter}
53
- onSelect={setFilter}
54
- />
55
- <TransactionList
56
- transactions={sorted}
57
- onDelete={budget["deleteTransaction"]}
58
- />
59
- </div>
60
-
61
- <div className="right-panel">
62
- # <PieChart
63
- # data={chartData}
64
- # title="Expense Breakdown"
65
- # colors={CATEGORY_COLORS}
66
- # />
67
- </div>
68
- </main>
69
- </div>;
70
- }