@mmapp/react-compiler 0.1.0-alpha.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.
Files changed (314) hide show
  1. package/README.md +107 -0
  2. package/compile-blueprint-chat.mjs +99 -0
  3. package/compile-blueprint-glass-console.mjs +98 -0
  4. package/compile-chat-defs.mjs +92 -0
  5. package/dist/babel/index.d.mts +3 -0
  6. package/dist/babel/index.d.ts +3 -0
  7. package/dist/babel/index.js +4851 -0
  8. package/dist/babel/index.mjs +7 -0
  9. package/dist/chunk-26U577GB.mjs +3465 -0
  10. package/dist/chunk-2FBDFAX6.mjs +2362 -0
  11. package/dist/chunk-2L4QSMXG.mjs +175 -0
  12. package/dist/chunk-2REDFOER.mjs +931 -0
  13. package/dist/chunk-46YKSHQR.mjs +175 -0
  14. package/dist/chunk-4XHK6FWL.mjs +2058 -0
  15. package/dist/chunk-5M7DKKBC.mjs +215 -0
  16. package/dist/chunk-5VNJ7C6N.mjs +154 -0
  17. package/dist/chunk-6CQOAAMV.mjs +1803 -0
  18. package/dist/chunk-6SEVAAVT.mjs +3516 -0
  19. package/dist/chunk-6YLR5ZDA.mjs +2829 -0
  20. package/dist/chunk-AOGY2GK6.mjs +3292 -0
  21. package/dist/chunk-AXXUXRNA.mjs +1434 -0
  22. package/dist/chunk-CHLVKMQW.mjs +175 -0
  23. package/dist/chunk-CKGOZAB7.mjs +939 -0
  24. package/dist/chunk-D34RAZUX.mjs +2223 -0
  25. package/dist/chunk-EQGA6A6D.mjs +121 -0
  26. package/dist/chunk-EY2CSXYA.mjs +822 -0
  27. package/dist/chunk-FIQ65CDR.mjs +925 -0
  28. package/dist/chunk-FOZXJFAR.mjs +186 -0
  29. package/dist/chunk-FX6URXWN.mjs +186 -0
  30. package/dist/chunk-G7SMOWOL.mjs +828 -0
  31. package/dist/chunk-GGB4G5YY.mjs +175 -0
  32. package/dist/chunk-HLRGCCIL.mjs +4839 -0
  33. package/dist/chunk-HOIUP6IF.mjs +690 -0
  34. package/dist/chunk-I3AU7GRD.mjs +120 -0
  35. package/dist/chunk-ILFGMUVD.mjs +1933 -0
  36. package/dist/chunk-IPTX5MJU.mjs +3223 -0
  37. package/dist/chunk-ITGUSH2Z.mjs +2783 -0
  38. package/dist/chunk-IXHBCAMF.mjs +3306 -0
  39. package/dist/chunk-J7TWJ3TM.mjs +2784 -0
  40. package/dist/chunk-JDPLDGVF.mjs +4810 -0
  41. package/dist/chunk-K53XP2DL.mjs +148 -0
  42. package/dist/chunk-K5HX2SVL.mjs +1902 -0
  43. package/dist/chunk-KFGYOOVS.mjs +214 -0
  44. package/dist/chunk-KFVVOS5N.mjs +925 -0
  45. package/dist/chunk-L2OZ4CDV.mjs +113 -0
  46. package/dist/chunk-MIZV3TAN.mjs +3293 -0
  47. package/dist/chunk-NKKLQE5V.mjs +148 -0
  48. package/dist/chunk-NOW23XFZ.mjs +186 -0
  49. package/dist/chunk-NRXQKQ74.mjs +148 -0
  50. package/dist/chunk-OWI6XWCD.mjs +3375 -0
  51. package/dist/chunk-PRUMNNDI.mjs +3192 -0
  52. package/dist/chunk-QTBD5B3F.mjs +148 -0
  53. package/dist/chunk-SKSDPPNT.mjs +3788 -0
  54. package/dist/chunk-SP2YUS33.mjs +186 -0
  55. package/dist/chunk-SU4E6E7B.mjs +3153 -0
  56. package/dist/chunk-SYUUKW5A.mjs +3379 -0
  57. package/dist/chunk-UL2XZEMA.mjs +3128 -0
  58. package/dist/chunk-XMWUHQVV.mjs +939 -0
  59. package/dist/chunk-XZNEDRGN.mjs +3876 -0
  60. package/dist/chunk-Y6FXYEAI.mjs +10 -0
  61. package/dist/chunk-YFS6JMYO.mjs +3342 -0
  62. package/dist/chunk-Z6AIQ4KL.mjs +113 -0
  63. package/dist/cli/index.d.mts +1 -0
  64. package/dist/cli/index.d.ts +1 -0
  65. package/dist/cli/index.js +11585 -0
  66. package/dist/cli/index.mjs +701 -0
  67. package/dist/codemod/cli.d.mts +1 -0
  68. package/dist/codemod/cli.d.ts +1 -0
  69. package/dist/codemod/cli.js +1104 -0
  70. package/dist/codemod/cli.mjs +157 -0
  71. package/dist/codemod/index.d.mts +148 -0
  72. package/dist/codemod/index.d.ts +148 -0
  73. package/dist/codemod/index.js +981 -0
  74. package/dist/codemod/index.mjs +25 -0
  75. package/dist/dev-server-Bs_sz2DG.d.mts +111 -0
  76. package/dist/dev-server-Bs_sz2DG.d.ts +111 -0
  77. package/dist/dev-server-CjoufJ-u.d.mts +109 -0
  78. package/dist/dev-server-CjoufJ-u.d.ts +109 -0
  79. package/dist/dev-server.d.mts +3 -0
  80. package/dist/dev-server.d.ts +3 -0
  81. package/dist/dev-server.js +7603 -0
  82. package/dist/dev-server.mjs +11 -0
  83. package/dist/envelope-DD7v0v6E.d.mts +265 -0
  84. package/dist/envelope-DD7v0v6E.d.ts +265 -0
  85. package/dist/envelope-vCVjrHlo.d.mts +265 -0
  86. package/dist/envelope-vCVjrHlo.d.ts +265 -0
  87. package/dist/envelope.d.mts +2 -0
  88. package/dist/envelope.d.ts +2 -0
  89. package/dist/envelope.js +5184 -0
  90. package/dist/envelope.mjs +9 -0
  91. package/dist/index-B5gSgvnd.d.mts +44 -0
  92. package/dist/index-B5gSgvnd.d.ts +44 -0
  93. package/dist/index-Bs0MnR54.d.mts +103 -0
  94. package/dist/index-Bs0MnR54.d.ts +103 -0
  95. package/dist/index-DR0nNc_f.d.mts +101 -0
  96. package/dist/index-DR0nNc_f.d.ts +101 -0
  97. package/dist/index-revho_gS.d.mts +104 -0
  98. package/dist/index-revho_gS.d.ts +104 -0
  99. package/dist/index.d.mts +1099 -0
  100. package/dist/index.d.ts +1099 -0
  101. package/dist/index.js +10162 -0
  102. package/dist/index.mjs +372 -0
  103. package/dist/init-IXEE2RCF.mjs +340 -0
  104. package/dist/project-compiler-EGJUTAJU.mjs +10 -0
  105. package/dist/project-compiler-VFR6CSDX.mjs +10 -0
  106. package/dist/project-decompiler-5GY2KSG4.mjs +7 -0
  107. package/dist/pull-A2QUHW4K.mjs +109 -0
  108. package/dist/pull-JBEQWVPE.mjs +109 -0
  109. package/dist/testing/index.d.mts +211 -0
  110. package/dist/testing/index.d.ts +211 -0
  111. package/dist/testing/index.js +5106 -0
  112. package/dist/testing/index.mjs +247 -0
  113. package/dist/vite/index.d.mts +59 -0
  114. package/dist/vite/index.d.ts +59 -0
  115. package/dist/vite/index.js +5023 -0
  116. package/dist/vite/index.mjs +8 -0
  117. package/examples/README.md +72 -0
  118. package/examples/authentication/main.workflow.tsx +139 -0
  119. package/examples/authentication/mm.config.ts +22 -0
  120. package/examples/authentication/models/auth.ts +45 -0
  121. package/examples/authentication/pages/LoginPage.tsx +79 -0
  122. package/examples/authentication/pages/SignupPage.tsx +87 -0
  123. package/examples/counter.workflow.tsx +65 -0
  124. package/examples/dashboard.workflow.tsx +419 -0
  125. package/examples/invoice-approval/actions/invoice.server.ts +72 -0
  126. package/examples/invoice-approval/main.workflow.tsx +168 -0
  127. package/examples/invoice-approval/mm.config.ts +18 -0
  128. package/examples/invoice-approval/models/invoice.ts +46 -0
  129. package/examples/invoice-approval/pages/InvoiceDetailPage.tsx +175 -0
  130. package/examples/invoice-approval/pages/InvoiceFormPage.tsx +198 -0
  131. package/examples/invoice-approval/pages/InvoiceListPage.tsx +141 -0
  132. package/examples/todo-app.workflow.tsx +131 -0
  133. package/examples/uber-app/actions/matching.server.ts +177 -0
  134. package/examples/uber-app/actions/notifications.server.ts +176 -0
  135. package/examples/uber-app/actions/payments.server.ts +184 -0
  136. package/examples/uber-app/actions/pricing.server.ts +176 -0
  137. package/examples/uber-app/app/admin/analytics.tsx +102 -0
  138. package/examples/uber-app/app/admin/fleet.tsx +102 -0
  139. package/examples/uber-app/app/admin/surge-pricing.tsx +95 -0
  140. package/examples/uber-app/app/driver/dashboard.tsx +87 -0
  141. package/examples/uber-app/app/driver/earnings.tsx +101 -0
  142. package/examples/uber-app/app/driver/navigation.tsx +94 -0
  143. package/examples/uber-app/app/driver/ride-acceptance.tsx +103 -0
  144. package/examples/uber-app/app/rider/home.tsx +109 -0
  145. package/examples/uber-app/app/rider/payment-methods.tsx +134 -0
  146. package/examples/uber-app/app/rider/ride-history.tsx +90 -0
  147. package/examples/uber-app/app/rider/ride-tracking.tsx +108 -0
  148. package/examples/uber-app/components/DriverCard.tsx +176 -0
  149. package/examples/uber-app/components/MapView.tsx +216 -0
  150. package/examples/uber-app/components/RatingStars.tsx +227 -0
  151. package/examples/uber-app/components/RideCard.tsx +167 -0
  152. package/examples/uber-app/mm.config.ts +30 -0
  153. package/examples/uber-app/models/location.model.ts +70 -0
  154. package/examples/uber-app/models/payment.model.ts +87 -0
  155. package/examples/uber-app/models/rating.model.ts +54 -0
  156. package/examples/uber-app/models/ride.model.ts +118 -0
  157. package/examples/uber-app/models/user.model.ts +66 -0
  158. package/examples/uber-app/models/vehicle.model.ts +63 -0
  159. package/examples/uber-app/tests/payment.test.tsx +129 -0
  160. package/examples/uber-app/tests/ride-flow.test.tsx +123 -0
  161. package/examples/uber-app/workflows/dispute-resolution.workflow.tsx +205 -0
  162. package/examples/uber-app/workflows/driver-onboarding.workflow.tsx +227 -0
  163. package/examples/uber-app/workflows/payment-processing.workflow.tsx +223 -0
  164. package/examples/uber-app/workflows/ride-request.workflow.tsx +194 -0
  165. package/package.json +77 -0
  166. package/package.json.backup +86 -0
  167. package/scripts/decompile.ts +226 -0
  168. package/scripts/seed-auth.ts +267 -0
  169. package/scripts/seed-uber.ts +248 -0
  170. package/scripts/validate-uber.ts +119 -0
  171. package/seed-blueprint-chat.mjs +444 -0
  172. package/seed-blueprint-glass-console.mjs +445 -0
  173. package/seed-compiled.mjs +318 -0
  174. package/src/RoundTripValidator.ts +400 -0
  175. package/src/__tests__/atom-rendering-coverage.test.ts +680 -0
  176. package/src/__tests__/auth-module-compilation.test.ts +247 -0
  177. package/src/__tests__/auth-template-compilation.test.ts +589 -0
  178. package/src/__tests__/change-extractor.test.ts +142 -0
  179. package/src/__tests__/cli-pull.test.ts +73 -0
  180. package/src/__tests__/cli-test.test.ts +72 -0
  181. package/src/__tests__/component-extractor.test.ts +331 -0
  182. package/src/__tests__/context-extractor.test.ts +145 -0
  183. package/src/__tests__/decompiler.test.ts +718 -0
  184. package/src/__tests__/define-blueprint.test.ts +133 -0
  185. package/src/__tests__/definition-validator.test.ts +519 -0
  186. package/src/__tests__/during-extractor.test.ts +152 -0
  187. package/src/__tests__/effect-extractor.test.ts +107 -0
  188. package/src/__tests__/event-emission.test.ts +127 -0
  189. package/src/__tests__/examples.test.ts +236 -0
  190. package/src/__tests__/full-blueprint-coverage.test.ts +1221 -0
  191. package/src/__tests__/golden-suite.test.ts +403 -0
  192. package/src/__tests__/grammar-island-extractor.test.ts +289 -0
  193. package/src/__tests__/instance-key.test.ts +82 -0
  194. package/src/__tests__/ir-migration.test.ts +255 -0
  195. package/src/__tests__/lock-file.test.ts +117 -0
  196. package/src/__tests__/model-extractor.test.ts +195 -0
  197. package/src/__tests__/model-field-acl.test.ts +237 -0
  198. package/src/__tests__/model-hooks.test.ts +130 -0
  199. package/src/__tests__/model-ref-resolution.test.ts +268 -0
  200. package/src/__tests__/model-roundtrip.test.ts +502 -0
  201. package/src/__tests__/model-runtime.test.ts +112 -0
  202. package/src/__tests__/model-transitions.test.ts +183 -0
  203. package/src/__tests__/nrt-action-trace.test.ts +391 -0
  204. package/src/__tests__/pipeline-hardening.test.ts +413 -0
  205. package/src/__tests__/project-compiler.test.ts +546 -0
  206. package/src/__tests__/project-decompiler.test.ts +343 -0
  207. package/src/__tests__/query-compilation.test.ts +145 -0
  208. package/src/__tests__/round-trip/PLAN.md +158 -0
  209. package/src/__tests__/round-trip/README.md +52 -0
  210. package/src/__tests__/round-trip/RESULTS.md +86 -0
  211. package/src/__tests__/round-trip/fixtures/data-heavy/main.workflow.tsx +55 -0
  212. package/src/__tests__/round-trip/fixtures/data-heavy/mm.config.ts +11 -0
  213. package/src/__tests__/round-trip/fixtures/data-heavy/models/contact.ts +54 -0
  214. package/src/__tests__/round-trip/fixtures/full-workflow/main.workflow.tsx +79 -0
  215. package/src/__tests__/round-trip/fixtures/full-workflow/mm.config.ts +12 -0
  216. package/src/__tests__/round-trip/fixtures/full-workflow/models/order.ts +50 -0
  217. package/src/__tests__/round-trip/fixtures/simple-crud/main.workflow.tsx +25 -0
  218. package/src/__tests__/round-trip/fixtures/simple-crud/mm.config.ts +11 -0
  219. package/src/__tests__/round-trip/fixtures/simple-crud/models/task.ts +32 -0
  220. package/src/__tests__/round-trip/fixtures/view-heavy/main.workflow.tsx +79 -0
  221. package/src/__tests__/round-trip/fixtures/view-heavy/mm.config.ts +10 -0
  222. package/src/__tests__/round-trip/round-trip.test.ts +2598 -0
  223. package/src/__tests__/round-trip-ir.test.ts +300 -0
  224. package/src/__tests__/round-trip.test.ts +1212 -0
  225. package/src/__tests__/route-merging.test.ts +372 -0
  226. package/src/__tests__/router-composition.test.ts +489 -0
  227. package/src/__tests__/router-extractor.test.ts +176 -0
  228. package/src/__tests__/server-action-extractor.test.ts +128 -0
  229. package/src/__tests__/smart-type-inference.test.ts +365 -0
  230. package/src/__tests__/source-envelope.test.ts +284 -0
  231. package/src/__tests__/source-fidelity.test.ts +516 -0
  232. package/src/__tests__/state-extractor.test.ts +115 -0
  233. package/src/__tests__/strict-mode.test.ts +227 -0
  234. package/src/__tests__/transition-effect-extractor.test.ts +119 -0
  235. package/src/__tests__/transition-extractor.test.ts +68 -0
  236. package/src/__tests__/ts-to-expression.test.ts +462 -0
  237. package/src/__tests__/type-generator.test.ts +201 -0
  238. package/src/__tests__/uber-validation.test.ts +502 -0
  239. package/src/action-compiler.ts +361 -0
  240. package/src/babel/emitters/experience-transform.ts +199 -0
  241. package/src/babel/emitters/ir-to-tsx-emitter.ts +110 -0
  242. package/src/babel/emitters/pure-form-emitter.ts +1023 -0
  243. package/src/babel/emitters/runtime-glue-emitter.ts +39 -0
  244. package/src/babel/extractors/change-extractor.ts +199 -0
  245. package/src/babel/extractors/component-extractor.ts +907 -0
  246. package/src/babel/extractors/computed-extractor.ts +262 -0
  247. package/src/babel/extractors/context-extractor.ts +277 -0
  248. package/src/babel/extractors/during-extractor.ts +295 -0
  249. package/src/babel/extractors/effect-extractor.ts +340 -0
  250. package/src/babel/extractors/event-extractor.ts +235 -0
  251. package/src/babel/extractors/grammar-island-extractor.ts +302 -0
  252. package/src/babel/extractors/model-extractor.ts +1018 -0
  253. package/src/babel/extractors/router-extractor.ts +303 -0
  254. package/src/babel/extractors/server-action-extractor.ts +173 -0
  255. package/src/babel/extractors/server-action-hook-extractor.ts +72 -0
  256. package/src/babel/extractors/server-state-extractor.ts +88 -0
  257. package/src/babel/extractors/state-extractor.ts +214 -0
  258. package/src/babel/extractors/transition-effect-extractor.ts +176 -0
  259. package/src/babel/extractors/transition-extractor.ts +143 -0
  260. package/src/babel/index.ts +24 -0
  261. package/src/babel/transpilers/ts-to-expression.ts +674 -0
  262. package/src/babel/visitor.ts +807 -0
  263. package/src/cli/auth.ts +255 -0
  264. package/src/cli/build.ts +288 -0
  265. package/src/cli/deploy.ts +206 -0
  266. package/src/cli/index.ts +328 -0
  267. package/src/cli/init.ts +388 -0
  268. package/src/cli/installer.ts +261 -0
  269. package/src/cli/lock-file.ts +94 -0
  270. package/src/cli/mmrc.ts +22 -0
  271. package/src/cli/pull.ts +172 -0
  272. package/src/cli/registry-client.ts +175 -0
  273. package/src/cli/test.ts +397 -0
  274. package/src/cli/type-generator.ts +243 -0
  275. package/src/codemod/__tests__/forward.test.ts +239 -0
  276. package/src/codemod/__tests__/reverse.test.ts +145 -0
  277. package/src/codemod/__tests__/round-trip.test.ts +137 -0
  278. package/src/codemod/annotation.ts +97 -0
  279. package/src/codemod/classify.ts +197 -0
  280. package/src/codemod/cli.ts +207 -0
  281. package/src/codemod/control-flow.ts +409 -0
  282. package/src/codemod/forward.ts +244 -0
  283. package/src/codemod/import-manager.ts +171 -0
  284. package/src/codemod/index.ts +120 -0
  285. package/src/codemod/reverse.ts +197 -0
  286. package/src/codemod/rules.ts +174 -0
  287. package/src/codemod/state-transform.ts +126 -0
  288. package/src/decompiler/ast-builder.ts +538 -0
  289. package/src/decompiler/config-generator.ts +151 -0
  290. package/src/decompiler/index.ts +315 -0
  291. package/src/decompiler/project-decompiler.ts +1776 -0
  292. package/src/decompiler/project.ts +862 -0
  293. package/src/decompiler/split-strategy.ts +140 -0
  294. package/src/decompiler/state-emitter.ts +1053 -0
  295. package/src/decompiler/sx-emitter.ts +318 -0
  296. package/src/decompiler/workspace-hydrator.ts +189 -0
  297. package/src/dev-server.ts +238 -0
  298. package/src/envelope/fs-tree.ts +217 -0
  299. package/src/envelope/source-envelope.ts +264 -0
  300. package/src/envelope.ts +315 -0
  301. package/src/incremental-compiler.ts +401 -0
  302. package/src/index.ts +99 -0
  303. package/src/model-compiler.ts +277 -0
  304. package/src/project-compiler.ts +1629 -0
  305. package/src/route-extractor.ts +333 -0
  306. package/src/testing/index.ts +32 -0
  307. package/src/testing/snapshot.ts +252 -0
  308. package/src/testing/test-utils.ts +226 -0
  309. package/src/types.ts +68 -0
  310. package/src/vite/index.ts +288 -0
  311. package/test-compile.mjs +142 -0
  312. package/tsconfig.json +25 -0
  313. package/tsup.config.ts +23 -0
  314. package/vitest.config.ts +9 -0
@@ -0,0 +1,94 @@
1
+ import { useWorkflow, useTransition, useField, useComputed, useOnChange } from '@mindmatrix/react';
2
+ import { Stack, Row, Text, Button, Show, Each, Card, Badge, Heading } from '@mindmatrix/react';
3
+ import { RideRequest, RidePhase } from '../models/ride';
4
+ import { MapView } from '../components/MapView';
5
+ import { DirectionStep } from '../models/navigation';
6
+
7
+ export default function Navigation() {
8
+ const workflow = useWorkflow('active-ride');
9
+
10
+ const ride = useField<RideRequest>('ride.current');
11
+ const phase = useField<RidePhase>('ride.phase');
12
+ const directions = useField<DirectionStep[]>('ride.directions');
13
+ const currentStepIndex = useField<number>('ride.currentStep');
14
+
15
+ const currentFare = useComputed('ride.currentFare', () => {
16
+ const { distanceMiles, surgeFactor } = ride.value;
17
+ return (2.5 + distanceMiles * 1.75) * surgeFactor;
18
+ });
19
+
20
+ const arrivedAtPickup = useTransition('arrived-at-pickup');
21
+ const startRide = useTransition('start-ride');
22
+ const completeRide = useTransition('complete-ride');
23
+
24
+ useOnChange('ride.currentStep', (stepIndex) => {
25
+ // Auto-advance map when step changes
26
+ });
27
+
28
+ const handlePhaseAction = () => {
29
+ switch (phase.value) {
30
+ case 'en-route-to-pickup':
31
+ arrivedAtPickup.execute({ rideId: ride.value.id });
32
+ break;
33
+ case 'waiting-at-pickup':
34
+ startRide.execute({ rideId: ride.value.id });
35
+ break;
36
+ case 'in-progress':
37
+ completeRide.execute({ rideId: ride.value.id });
38
+ break;
39
+ }
40
+ };
41
+
42
+ const phaseLabel: Record<RidePhase, string> = {
43
+ 'en-route-to-pickup': 'Arrived at Pickup',
44
+ 'waiting-at-pickup': 'Start Ride',
45
+ 'in-progress': 'Complete Ride',
46
+ 'completed': 'Completed',
47
+ };
48
+
49
+ return (
50
+ <Stack gap="md" padding="md">
51
+ <MapView
52
+ pickup={ride.value.pickupCoords}
53
+ dropoff={ride.value.dropoffCoords}
54
+ currentStep={currentStepIndex.value}
55
+ directions={directions.value}
56
+ />
57
+
58
+ <Card padding="md">
59
+ <Row justify="between" align="center">
60
+ <Stack gap="xs">
61
+ <Text weight="medium">{ride.value.passengerName}</Text>
62
+ <Text size="sm" color="muted">
63
+ {phase.value === 'en-route-to-pickup'
64
+ ? ride.value.pickupAddress
65
+ : ride.value.dropoffAddress}
66
+ </Text>
67
+ </Stack>
68
+ <Text size="lg" weight="bold">${currentFare.value.toFixed(2)}</Text>
69
+ </Row>
70
+ </Card>
71
+
72
+ <Card padding="sm" maxHeight={200} overflow="scroll">
73
+ <Each items={directions.value}>
74
+ {(step, index) => (
75
+ <Row
76
+ key={step.id}
77
+ padding="sm"
78
+ background={index === currentStepIndex.value ? 'highlight' : 'none'}
79
+ >
80
+ <Badge variant="neutral">{step.distanceFt} ft</Badge>
81
+ <Text size="sm" flex={1}>{step.instruction}</Text>
82
+ </Row>
83
+ )}
84
+ </Each>
85
+ </Card>
86
+
87
+ <Show when={phase.value !== 'completed'}>
88
+ <Button variant="primary" size="lg" onPress={handlePhaseAction}>
89
+ {phaseLabel[phase.value]}
90
+ </Button>
91
+ </Show>
92
+ </Stack>
93
+ );
94
+ }
@@ -0,0 +1,103 @@
1
+ import { useState, useWorkflow, useTransition, useField, useOnEvent, useComputed } from '@mindmatrix/react';
2
+ import { Stack, Row, Text, Button, Show, Card, Badge, Heading } from '@mindmatrix/react';
3
+ import { RideRequest } from '../models/ride';
4
+ import { PassengerInfo } from '../models/passenger';
5
+
6
+ export default function RideAcceptance() {
7
+ const workflow = useWorkflow('ride-matching');
8
+ const [timeLeft, setTimeLeft] = useState(30);
9
+
10
+ const incomingRide = useField<RideRequest | null>('matching.pendingRequest');
11
+ const passenger = useField<PassengerInfo | null>('matching.passengerInfo');
12
+
13
+ const estimatedFare = useComputed('matching.estimatedFare', () => {
14
+ if (!incomingRide.value) return 0;
15
+ const { distanceMiles, surgeFactor } = incomingRide.value;
16
+ return (2.5 + distanceMiles * 1.75) * surgeFactor;
17
+ });
18
+
19
+ const acceptRide = useTransition('accept-ride');
20
+ const declineRide = useTransition('decline-ride');
21
+
22
+ useOnEvent('new-ride-request', (event) => {
23
+ setTimeLeft(30);
24
+ const timer = setInterval(() => {
25
+ setTimeLeft((prev) => {
26
+ if (prev <= 1) {
27
+ clearInterval(timer);
28
+ declineRide.execute({ reason: 'timeout' });
29
+ return 0;
30
+ }
31
+ return prev - 1;
32
+ });
33
+ }, 1000);
34
+ return () => clearInterval(timer);
35
+ });
36
+
37
+ const handleAccept = () => {
38
+ acceptRide.execute({ rideId: incomingRide.value?.id });
39
+ };
40
+
41
+ const handleDecline = () => {
42
+ declineRide.execute({ reason: 'driver-declined' });
43
+ };
44
+
45
+ return (
46
+ <Stack gap="lg" padding="md">
47
+ <Heading level={2}>Incoming Ride Request</Heading>
48
+
49
+ <Show when={incomingRide.value !== null}>
50
+ <Card padding="lg">
51
+ <Stack gap="md">
52
+ <Row justify="between">
53
+ <Badge variant="info">{timeLeft}s</Badge>
54
+ <Text size="xl" weight="bold">${estimatedFare.value.toFixed(2)}</Text>
55
+ </Row>
56
+
57
+ <Stack gap="sm">
58
+ <Row gap="sm" align="center">
59
+ <Badge variant="success">Pickup</Badge>
60
+ <Text>{incomingRide.value!.pickupAddress}</Text>
61
+ </Row>
62
+ <Row gap="sm" align="center">
63
+ <Badge variant="neutral">Dropoff</Badge>
64
+ <Text>{incomingRide.value!.dropoffAddress}</Text>
65
+ </Row>
66
+ </Stack>
67
+
68
+ <Row gap="md">
69
+ <Text size="sm" color="muted">
70
+ {incomingRide.value!.distanceMiles.toFixed(1)} mi
71
+ </Text>
72
+ <Text size="sm" color="muted">
73
+ ~{incomingRide.value!.estimatedMinutes} min
74
+ </Text>
75
+ </Row>
76
+
77
+ <Show when={passenger.value !== null}>
78
+ <Row gap="sm" align="center">
79
+ <Text weight="medium">{passenger.value!.name}</Text>
80
+ <Badge variant="warning">{passenger.value!.rating.toFixed(1)}</Badge>
81
+ </Row>
82
+ </Show>
83
+
84
+ <Row gap="md">
85
+ <Button variant="primary" size="lg" flex={1} onPress={handleAccept}>
86
+ Accept
87
+ </Button>
88
+ <Button variant="outline" size="lg" flex={1} onPress={handleDecline}>
89
+ Decline
90
+ </Button>
91
+ </Row>
92
+ </Stack>
93
+ </Card>
94
+ </Show>
95
+
96
+ <Show when={incomingRide.value === null}>
97
+ <Card padding="lg">
98
+ <Text align="center" color="muted">No pending ride requests</Text>
99
+ </Card>
100
+ </Show>
101
+ </Stack>
102
+ );
103
+ }
@@ -0,0 +1,109 @@
1
+ import {
2
+ useState, useWorkflow, useTransition, useField,
3
+ useComputed, useRole, useQuery, useOnEnter, useOnEvent,
4
+ } from '@mindmatrix/react';
5
+ import {
6
+ Stack, Row, Text, Button, Show, Each, Card, Badge,
7
+ Heading, Input,
8
+ } from '@mindmatrix/react';
9
+ import { Ride, VehicleType } from '../models/ride.model';
10
+ import { MapView } from '../components/MapView';
11
+ import { estimateFare } from '../actions/pricing.server';
12
+
13
+ const VEHICLE_TYPES: { key: VehicleType; label: string; icon: string }[] = [
14
+ { key: 'economy', label: 'Economy', icon: 'car' },
15
+ { key: 'premium', label: 'Premium', icon: 'car-premium' },
16
+ { key: 'xl', label: 'XL', icon: 'car-xl' },
17
+ { key: 'luxury', label: 'Luxury', icon: 'car-luxury' },
18
+ ];
19
+
20
+ export default function RiderHome() {
21
+ const workflow = useWorkflow<Ride>('ride-request');
22
+ const transition = useTransition(workflow);
23
+ const pickup = useField(workflow, 'pickup_address');
24
+ const dropoff = useField(workflow, 'dropoff_address');
25
+ const vehicleType = useField(workflow, 'vehicle_type');
26
+
27
+ const [selectedVehicle, setSelectedVehicle] = useState<VehicleType>('economy');
28
+
29
+ const fareEstimate = useComputed(workflow, 'fare_estimate', {
30
+ deps: [pickup.value, dropoff.value, selectedVehicle],
31
+ });
32
+
33
+ const routePreview = useComputed(workflow, 'route_preview', {
34
+ deps: [pickup.value, dropoff.value],
35
+ });
36
+
37
+ const handleSelectVehicle = (type: VehicleType) => {
38
+ setSelectedVehicle(type);
39
+ vehicleType.set(type);
40
+ };
41
+
42
+ const handleRequestRide = async () => {
43
+ await transition('request_ride', {
44
+ pickup_address: pickup.value,
45
+ dropoff_address: dropoff.value,
46
+ vehicle_type: selectedVehicle,
47
+ });
48
+ };
49
+
50
+ return (
51
+ <Stack gap={4} padding={4}>
52
+ <Heading level={2}>Where to?</Heading>
53
+
54
+ <Card padding={3}>
55
+ <Stack gap={3}>
56
+ <Input
57
+ label="Pickup"
58
+ placeholder="Enter pickup address"
59
+ value={pickup.value ?? ''}
60
+ onChange={pickup.set}
61
+ />
62
+ <Input
63
+ label="Dropoff"
64
+ placeholder="Enter destination"
65
+ value={dropoff.value ?? ''}
66
+ onChange={dropoff.set}
67
+ />
68
+ </Stack>
69
+ </Card>
70
+
71
+ <Show when={routePreview.value}>
72
+ <MapView route={routePreview.value} height={200} />
73
+ </Show>
74
+
75
+ <Row gap={2} wrap>
76
+ <Each items={VEHICLE_TYPES}>
77
+ {(vt) => (
78
+ <Card
79
+ key={vt.key}
80
+ padding={2}
81
+ selected={selectedVehicle === vt.key}
82
+ onPress={() => handleSelectVehicle(vt.key)}
83
+ >
84
+ <Text weight="bold">{vt.label}</Text>
85
+ </Card>
86
+ )}
87
+ </Each>
88
+ </Row>
89
+
90
+ <Show when={fareEstimate.value != null}>
91
+ <Card padding={3}>
92
+ <Row justify="between" align="center">
93
+ <Text color="muted">Estimated fare</Text>
94
+ <Text size="xl" weight="bold">${fareEstimate.value?.toFixed(2)}</Text>
95
+ </Row>
96
+ </Card>
97
+ </Show>
98
+
99
+ <Button
100
+ variant="primary"
101
+ size="lg"
102
+ disabled={!pickup.value || !dropoff.value}
103
+ onPress={handleRequestRide}
104
+ >
105
+ Request Ride
106
+ </Button>
107
+ </Stack>
108
+ );
109
+ }
@@ -0,0 +1,134 @@
1
+ import {
2
+ useState, useWorkflow, useTransition, useField,
3
+ useComputed, useRole, useQuery, useOnEnter, useOnEvent,
4
+ } from '@mindmatrix/react';
5
+ import {
6
+ Stack, Row, Text, Button, Show, Each, Card, Badge,
7
+ Heading, Input,
8
+ } from '@mindmatrix/react';
9
+ import { PaymentMethod } from '../models/payment.model';
10
+ import { addPaymentMethod, removePaymentMethod, setDefaultPayment } from '../actions/payments.server';
11
+
12
+ export default function PaymentMethods() {
13
+ const methods = useQuery<PaymentMethod[]>('payment-methods', {
14
+ sort: { is_default: 'desc', created_at: 'desc' },
15
+ });
16
+
17
+ const [showAddForm, setShowAddForm] = useState(false);
18
+ const [cardNumber, setCardNumber] = useState('');
19
+ const [expiry, setExpiry] = useState('');
20
+ const [cvv, setCvv] = useState('');
21
+ const [cardholderName, setCardholderName] = useState('');
22
+
23
+ const resetForm = () => {
24
+ setCardNumber('');
25
+ setExpiry('');
26
+ setCvv('');
27
+ setCardholderName('');
28
+ setShowAddForm(false);
29
+ };
30
+
31
+ const handleAddCard = async () => {
32
+ await addPaymentMethod({ cardNumber, expiry, cvv, cardholderName });
33
+ resetForm();
34
+ methods.refetch();
35
+ };
36
+
37
+ const handleDelete = async (id: string) => {
38
+ await removePaymentMethod(id);
39
+ methods.refetch();
40
+ };
41
+
42
+ const handleSetDefault = async (id: string) => {
43
+ await setDefaultPayment(id);
44
+ methods.refetch();
45
+ };
46
+
47
+ return (
48
+ <Stack gap={4} padding={4}>
49
+ <Row justify="between" align="center">
50
+ <Heading level={2}>Payment Methods</Heading>
51
+ <Button variant="secondary" onPress={() => setShowAddForm(!showAddForm)}>
52
+ {showAddForm ? 'Cancel' : 'Add Card'}
53
+ </Button>
54
+ </Row>
55
+
56
+ <Show when={showAddForm}>
57
+ <Card padding={3}>
58
+ <Stack gap={3}>
59
+ <Input
60
+ label="Cardholder Name"
61
+ placeholder="John Doe"
62
+ value={cardholderName}
63
+ onChange={setCardholderName}
64
+ />
65
+ <Input
66
+ label="Card Number"
67
+ placeholder="4242 4242 4242 4242"
68
+ value={cardNumber}
69
+ onChange={setCardNumber}
70
+ />
71
+ <Row gap={3}>
72
+ <Input
73
+ label="Expiry"
74
+ placeholder="MM/YY"
75
+ value={expiry}
76
+ onChange={setExpiry}
77
+ flex={1}
78
+ />
79
+ <Input
80
+ label="CVV"
81
+ placeholder="123"
82
+ value={cvv}
83
+ onChange={setCvv}
84
+ flex={1}
85
+ />
86
+ </Row>
87
+ <Button variant="primary" onPress={handleAddCard}>
88
+ Save Card
89
+ </Button>
90
+ </Stack>
91
+ </Card>
92
+ </Show>
93
+
94
+ <Show when={methods.loading}>
95
+ <Text color="muted" align="center">Loading payment methods...</Text>
96
+ </Show>
97
+
98
+ <Each items={methods.data ?? []}>
99
+ {(method) => (
100
+ <Card key={method.id} padding={3}>
101
+ <Row justify="between" align="center">
102
+ <Row gap={2} align="center">
103
+ <Text weight="bold">{method.brand}</Text>
104
+ <Text color="muted">**** {method.last_four}</Text>
105
+ <Text color="muted" size="sm">Exp {method.expiry}</Text>
106
+ <Show when={method.is_default}>
107
+ <Badge color="green">Default</Badge>
108
+ </Show>
109
+ </Row>
110
+ <Row gap={2}>
111
+ <Show when={!method.is_default}>
112
+ <Button
113
+ variant="ghost"
114
+ size="sm"
115
+ onPress={() => handleSetDefault(method.id)}
116
+ >
117
+ Set Default
118
+ </Button>
119
+ </Show>
120
+ <Button
121
+ variant="ghost"
122
+ size="sm"
123
+ onPress={() => handleDelete(method.id)}
124
+ >
125
+ Remove
126
+ </Button>
127
+ </Row>
128
+ </Row>
129
+ </Card>
130
+ )}
131
+ </Each>
132
+ </Stack>
133
+ );
134
+ }
@@ -0,0 +1,90 @@
1
+ import {
2
+ useState, useWorkflow, useTransition, useField,
3
+ useComputed, useRole, useQuery, useOnEnter, useOnEvent,
4
+ } from '@mindmatrix/react';
5
+ import {
6
+ Stack, Row, Text, Button, Show, Each, Card, Badge,
7
+ Heading, Input,
8
+ } from '@mindmatrix/react';
9
+ import { Ride } from '../models/ride.model';
10
+ import { RideCard } from '../components/RideCard';
11
+
12
+ export default function RideHistory() {
13
+ const [dateFrom, setDateFrom] = useState<string>('');
14
+ const [dateTo, setDateTo] = useState<string>('');
15
+
16
+ const rides = useQuery<Ride[]>('ride-request', {
17
+ filter: {
18
+ trip_status: 'completed',
19
+ ...(dateFrom && { created_at_gte: dateFrom }),
20
+ ...(dateTo && { created_at_lte: dateTo }),
21
+ },
22
+ sort: { created_at: 'desc' },
23
+ limit: 50,
24
+ });
25
+
26
+ const totalSpent = useComputed(rides, 'total_spent', {
27
+ deps: [rides.data],
28
+ });
29
+
30
+ return (
31
+ <Stack gap={4} padding={4}>
32
+ <Heading level={2}>Ride History</Heading>
33
+
34
+ <Card padding={3}>
35
+ <Row gap={3} align="end">
36
+ <Input
37
+ label="From"
38
+ type="date"
39
+ value={dateFrom}
40
+ onChange={setDateFrom}
41
+ flex={1}
42
+ />
43
+ <Input
44
+ label="To"
45
+ type="date"
46
+ value={dateTo}
47
+ onChange={setDateTo}
48
+ flex={1}
49
+ />
50
+ <Button
51
+ variant="secondary"
52
+ onPress={() => { setDateFrom(''); setDateTo(''); }}
53
+ >
54
+ Clear
55
+ </Button>
56
+ </Row>
57
+ </Card>
58
+
59
+ <Show when={totalSpent.value != null}>
60
+ <Row justify="between" padding={2}>
61
+ <Text color="muted">Total spent</Text>
62
+ <Text size="lg" weight="bold">${totalSpent.value?.toFixed(2)}</Text>
63
+ </Row>
64
+ </Show>
65
+
66
+ <Show when={rides.loading}>
67
+ <Text color="muted" align="center">Loading rides...</Text>
68
+ </Show>
69
+
70
+ <Show when={!rides.loading && rides.data?.length === 0}>
71
+ <Text color="muted" align="center">No rides found</Text>
72
+ </Show>
73
+
74
+ <Each items={rides.data ?? []}>
75
+ {(ride) => (
76
+ <RideCard
77
+ key={ride.id}
78
+ date={ride.created_at}
79
+ pickup={ride.pickup_address}
80
+ dropoff={ride.dropoff_address}
81
+ fare={ride.final_fare}
82
+ rating={ride.rider_rating}
83
+ driverName={ride.assigned_driver?.name}
84
+ vehicleType={ride.vehicle_type}
85
+ />
86
+ )}
87
+ </Each>
88
+ </Stack>
89
+ );
90
+ }
@@ -0,0 +1,108 @@
1
+ import {
2
+ useState, useWorkflow, useTransition, useField,
3
+ useComputed, useRole, useQuery, useOnEnter, useOnEvent,
4
+ } from '@mindmatrix/react';
5
+ import {
6
+ Stack, Row, Text, Button, Show, Each, Card, Badge,
7
+ Heading, Input,
8
+ } from '@mindmatrix/react';
9
+ import { Ride, DriverLocation, TripStatus } from '../models/ride.model';
10
+ import { MapView } from '../components/MapView';
11
+ import { DriverCard } from '../components/DriverCard';
12
+ import { shareTrip } from '../actions/sharing.server';
13
+
14
+ const STATUS_COLORS: Record<TripStatus, string> = {
15
+ matching: 'yellow',
16
+ driver_assigned: 'blue',
17
+ arriving: 'blue',
18
+ in_progress: 'green',
19
+ completed: 'gray',
20
+ cancelled: 'red',
21
+ };
22
+
23
+ export default function RideTracking() {
24
+ const workflow = useWorkflow<Ride>('ride-request');
25
+ const transition = useTransition(workflow);
26
+ const status = useField(workflow, 'trip_status');
27
+ const driver = useField(workflow, 'assigned_driver');
28
+ const route = useField(workflow, 'active_route');
29
+ const fare = useField(workflow, 'current_fare');
30
+
31
+ const [driverLocation, setDriverLocation] = useState<DriverLocation | null>(null);
32
+
33
+ const eta = useComputed(workflow, 'eta_minutes', {
34
+ deps: [driverLocation, route.value],
35
+ });
36
+
37
+ useOnEvent(workflow, 'driver_location_update', (event) => {
38
+ setDriverLocation(event.payload as DriverLocation);
39
+ });
40
+
41
+ useOnEnter(workflow, 'completed', () => {
42
+ // Trigger rating prompt when ride completes
43
+ });
44
+
45
+ const handleCancel = async () => {
46
+ await transition('cancel_ride', { reason: 'rider_cancelled' });
47
+ };
48
+
49
+ const handleShareTrip = async () => {
50
+ if (workflow.instanceId) {
51
+ await shareTrip(workflow.instanceId);
52
+ }
53
+ };
54
+
55
+ return (
56
+ <Stack gap={4} padding={4}>
57
+ <Row justify="between" align="center">
58
+ <Heading level={2}>Your Ride</Heading>
59
+ <Badge color={STATUS_COLORS[status.value as TripStatus] ?? 'gray'}>
60
+ {status.value}
61
+ </Badge>
62
+ </Row>
63
+
64
+ <MapView
65
+ route={route.value}
66
+ driverPin={driverLocation}
67
+ height={300}
68
+ followDriver
69
+ />
70
+
71
+ <Show when={eta.value != null}>
72
+ <Card padding={3}>
73
+ <Stack gap={1} align="center">
74
+ <Text size="3xl" weight="bold">{eta.value}</Text>
75
+ <Text color="muted">minutes away</Text>
76
+ </Stack>
77
+ </Card>
78
+ </Show>
79
+
80
+ <Show when={driver.value != null}>
81
+ <DriverCard
82
+ name={driver.value?.name}
83
+ rating={driver.value?.rating}
84
+ vehicle={driver.value?.vehicle}
85
+ photo={driver.value?.photo_url}
86
+ />
87
+ </Show>
88
+
89
+ <Show when={fare.value != null}>
90
+ <Row justify="between" padding={2}>
91
+ <Text color="muted">Current fare</Text>
92
+ <Text weight="bold">${fare.value?.toFixed(2)}</Text>
93
+ </Row>
94
+ </Show>
95
+
96
+ <Row gap={3}>
97
+ <Show when={status.value !== 'completed' && status.value !== 'cancelled'}>
98
+ <Button variant="danger" onPress={handleCancel} flex={1}>
99
+ Cancel Ride
100
+ </Button>
101
+ </Show>
102
+ <Button variant="secondary" onPress={handleShareTrip} flex={1}>
103
+ Share Trip
104
+ </Button>
105
+ </Row>
106
+ </Stack>
107
+ );
108
+ }