@amplitude/wizard 1.0.0-beta.2 → 1.0.0

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 (391) hide show
  1. package/README.md +171 -74
  2. package/dist/bin.js +338 -222
  3. package/dist/src/lib/agent-interface.js +64 -9
  4. package/dist/src/lib/agent-runner.js +1 -10
  5. package/dist/src/lib/api.d.ts +22 -4
  6. package/dist/src/lib/api.js +114 -12
  7. package/dist/src/lib/commandments.js +14 -1
  8. package/dist/src/lib/constants.d.ts +6 -5
  9. package/dist/src/lib/constants.js +13 -13
  10. package/dist/src/lib/credential-resolution.d.ts +45 -0
  11. package/dist/src/lib/credential-resolution.js +311 -0
  12. package/dist/src/lib/exit-codes.d.ts +10 -0
  13. package/dist/src/lib/exit-codes.js +12 -0
  14. package/dist/src/lib/health-checks/statuspage.d.ts +1 -0
  15. package/dist/src/lib/health-checks/statuspage.js +5 -1
  16. package/dist/src/lib/mode-config.d.ts +14 -0
  17. package/dist/src/lib/mode-config.js +14 -0
  18. package/dist/src/lib/session-checkpoint.d.ts +27 -0
  19. package/dist/src/lib/session-checkpoint.js +134 -0
  20. package/dist/src/lib/wizard-session.d.ts +44 -1
  21. package/dist/src/lib/wizard-session.js +70 -14
  22. package/dist/src/lib/wizard-tools.js +19 -4
  23. package/dist/src/steps/add-mcp-server-to-clients/clients/claude.d.ts +3 -0
  24. package/dist/src/steps/add-mcp-server-to-clients/clients/claude.js +6 -0
  25. package/dist/src/steps/add-mcp-server-to-clients/clients/cursor.js +3 -1
  26. package/dist/src/ui/agent-ui.d.ts +91 -0
  27. package/dist/src/ui/agent-ui.js +277 -0
  28. package/dist/src/ui/logging-ui.js +1 -1
  29. package/dist/src/ui/tui/App.d.ts +12 -0
  30. package/dist/src/ui/tui/App.js +29 -18
  31. package/dist/src/ui/tui/components/AmplitudeLogo.js +16 -17
  32. package/dist/src/ui/tui/components/AmplitudeTextLogo.d.ts +0 -2
  33. package/dist/src/ui/tui/components/AmplitudeTextLogo.js +53 -18
  34. package/dist/src/ui/tui/components/BrailleSpinner.d.ts +8 -0
  35. package/dist/src/ui/tui/components/BrailleSpinner.js +15 -0
  36. package/dist/src/ui/tui/components/ConsoleView.d.ts +8 -11
  37. package/dist/src/ui/tui/components/ConsoleView.js +51 -34
  38. package/dist/src/ui/tui/components/HeaderBar.d.ts +12 -0
  39. package/dist/src/ui/tui/components/HeaderBar.js +17 -0
  40. package/dist/src/ui/tui/components/JourneyStepper.d.ts +16 -0
  41. package/dist/src/ui/tui/components/JourneyStepper.js +83 -0
  42. package/dist/src/ui/tui/components/KeyHintBar.d.ts +19 -0
  43. package/dist/src/ui/tui/components/KeyHintBar.js +20 -0
  44. package/dist/src/ui/tui/console-commands.d.ts +1 -2
  45. package/dist/src/ui/tui/console-commands.js +48 -7
  46. package/dist/src/ui/tui/flows.d.ts +1 -1
  47. package/dist/src/ui/tui/flows.js +1 -1
  48. package/dist/src/ui/tui/hooks/useAsyncEffect.d.ts +15 -0
  49. package/dist/src/ui/tui/hooks/useAsyncEffect.js +35 -0
  50. package/dist/src/ui/tui/hooks/useWizardStore.d.ts +9 -0
  51. package/dist/src/ui/tui/hooks/useWizardStore.js +11 -0
  52. package/dist/src/ui/tui/ink-ui.js +1 -1
  53. package/dist/src/ui/tui/primitives/DissolveTransition.js +4 -5
  54. package/dist/src/ui/tui/primitives/EventPlanViewer.d.ts +3 -1
  55. package/dist/src/ui/tui/primitives/EventPlanViewer.js +8 -3
  56. package/dist/src/ui/tui/primitives/ProgressList.js +1 -1
  57. package/dist/src/ui/tui/primitives/SlashCommandInput.js +19 -4
  58. package/dist/src/ui/tui/primitives/SplitView.d.ts +2 -1
  59. package/dist/src/ui/tui/primitives/SplitView.js +10 -2
  60. package/dist/src/ui/tui/primitives/TabContainer.js +10 -2
  61. package/dist/src/ui/tui/primitives/index.d.ts +0 -1
  62. package/dist/src/ui/tui/primitives/index.js +0 -1
  63. package/dist/src/ui/tui/router.js +1 -1
  64. package/dist/src/ui/tui/screen-registry.d.ts +0 -7
  65. package/dist/src/ui/tui/screen-registry.js +13 -4
  66. package/dist/src/ui/tui/screens/ActivationOptionsScreen.d.ts +2 -2
  67. package/dist/src/ui/tui/screens/ActivationOptionsScreen.js +8 -8
  68. package/dist/src/ui/tui/screens/AuthScreen.js +57 -27
  69. package/dist/src/ui/tui/screens/ChecklistScreen.d.ts +2 -12
  70. package/dist/src/ui/tui/screens/ChecklistScreen.js +22 -33
  71. package/dist/src/ui/tui/screens/DataIngestionCheckScreen.d.ts +3 -12
  72. package/dist/src/ui/tui/screens/DataIngestionCheckScreen.js +109 -39
  73. package/dist/src/ui/tui/screens/DataSetupScreen.d.ts +3 -3
  74. package/dist/src/ui/tui/screens/DataSetupScreen.js +17 -10
  75. package/dist/src/ui/tui/screens/IntroScreen.d.ts +5 -3
  76. package/dist/src/ui/tui/screens/IntroScreen.js +132 -41
  77. package/dist/src/ui/tui/screens/LoginScreen.d.ts +1 -1
  78. package/dist/src/ui/tui/screens/LoginScreen.js +4 -4
  79. package/dist/src/ui/tui/screens/LogoutScreen.d.ts +4 -2
  80. package/dist/src/ui/tui/screens/LogoutScreen.js +17 -5
  81. package/dist/src/ui/tui/screens/McpScreen.d.ts +4 -4
  82. package/dist/src/ui/tui/screens/McpScreen.js +25 -17
  83. package/dist/src/ui/tui/screens/OutageScreen.d.ts +1 -1
  84. package/dist/src/ui/tui/screens/OutageScreen.js +5 -5
  85. package/dist/src/ui/tui/screens/OutroScreen.d.ts +5 -0
  86. package/dist/src/ui/tui/screens/OutroScreen.js +21 -14
  87. package/dist/src/ui/tui/screens/RegionSelectScreen.js +15 -13
  88. package/dist/src/ui/tui/screens/RunScreen.d.ts +7 -5
  89. package/dist/src/ui/tui/screens/RunScreen.js +102 -157
  90. package/dist/src/ui/tui/screens/SettingsOverrideScreen.d.ts +1 -1
  91. package/dist/src/ui/tui/screens/SettingsOverrideScreen.js +6 -5
  92. package/dist/src/ui/tui/screens/SetupScreen.d.ts +1 -1
  93. package/dist/src/ui/tui/screens/SetupScreen.js +7 -7
  94. package/dist/src/ui/tui/screens/SlackScreen.d.ts +2 -2
  95. package/dist/src/ui/tui/screens/SlackScreen.js +60 -35
  96. package/dist/src/ui/tui/session-constants.d.ts +41 -0
  97. package/dist/src/ui/tui/session-constants.js +38 -0
  98. package/dist/src/ui/tui/start-tui.d.ts +3 -1
  99. package/dist/src/ui/tui/start-tui.js +14 -10
  100. package/dist/src/ui/tui/store.d.ts +2 -1
  101. package/dist/src/ui/tui/store.js +33 -7
  102. package/dist/src/ui/tui/styles.d.ts +75 -19
  103. package/dist/src/ui/tui/styles.js +101 -19
  104. package/dist/src/ui/tui/utils/classify-error.d.ts +14 -0
  105. package/dist/src/ui/tui/utils/classify-error.js +90 -0
  106. package/dist/src/ui/tui/utils/diagnostics.d.ts +21 -0
  107. package/dist/src/ui/tui/utils/diagnostics.js +72 -0
  108. package/dist/src/ui/tui/utils/with-retry.d.ts +12 -0
  109. package/dist/src/ui/tui/utils/with-retry.js +32 -0
  110. package/dist/src/ui/tui/utils/with-timeout.d.ts +10 -0
  111. package/dist/src/ui/tui/utils/with-timeout.js +24 -0
  112. package/dist/src/utils/ampli-settings.d.ts +1 -1
  113. package/dist/src/utils/ampli-settings.js +15 -5
  114. package/dist/src/utils/api-key-store.js +5 -5
  115. package/dist/src/utils/atomic-write.d.ts +15 -0
  116. package/dist/src/utils/atomic-write.js +34 -0
  117. package/dist/src/utils/setup-utils.js +2 -2
  118. package/dist/src/utils/token-refresh.d.ts +22 -0
  119. package/dist/src/utils/token-refresh.js +79 -0
  120. package/dist/src/utils/wizard-abort.js +6 -1
  121. package/package.json +6 -6
  122. package/skills/instrumentation/add-analytics-instrumentation/SKILL.md +142 -0
  123. package/skills/instrumentation/diff-intake/SKILL.md +128 -0
  124. package/skills/instrumentation/discover-analytics-patterns/SKILL.md +185 -0
  125. package/skills/instrumentation/discover-event-surfaces/SKILL.md +322 -0
  126. package/skills/instrumentation/discover-event-surfaces/references/best-practices.md +563 -0
  127. package/skills/instrumentation/instrument-events/SKILL.md +169 -0
  128. package/skills/instrumentation/instrument-events/references/best-practices.md +563 -0
  129. package/skills/integration/integration-android/SKILL.md +49 -0
  130. package/skills/integration/integration-android/references/EXAMPLE.md +1977 -0
  131. package/skills/integration/integration-android/references/amplitude-quickstart.md +1845 -0
  132. package/skills/integration/integration-android/references/analytics.md +1778 -0
  133. package/skills/integration/integration-android/references/basic-integration-1.0-begin.md +43 -0
  134. package/skills/integration/integration-android/references/basic-integration-1.1-edit.md +35 -0
  135. package/skills/integration/integration-android/references/basic-integration-1.2-revise.md +23 -0
  136. package/skills/integration/integration-android/references/basic-integration-1.3-conclude.md +57 -0
  137. package/skills/integration/integration-angular/SKILL.md +49 -0
  138. package/skills/integration/integration-angular/references/EXAMPLE.md +899 -0
  139. package/skills/integration/integration-angular/references/amplitude-quickstart.md +1845 -0
  140. package/skills/integration/integration-angular/references/basic-integration-1.0-begin.md +43 -0
  141. package/skills/integration/integration-angular/references/basic-integration-1.1-edit.md +35 -0
  142. package/skills/integration/integration-angular/references/basic-integration-1.2-revise.md +23 -0
  143. package/skills/integration/integration-angular/references/basic-integration-1.3-conclude.md +57 -0
  144. package/skills/integration/integration-angular/references/browser-sdk-2.md +4680 -0
  145. package/skills/integration/integration-astro-hybrid/SKILL.md +56 -0
  146. package/skills/integration/integration-astro-hybrid/references/EXAMPLE.md +1095 -0
  147. package/skills/integration/integration-astro-hybrid/references/amplitude-quickstart.md +1845 -0
  148. package/skills/integration/integration-astro-hybrid/references/basic-integration-1.0-begin.md +43 -0
  149. package/skills/integration/integration-astro-hybrid/references/basic-integration-1.1-edit.md +35 -0
  150. package/skills/integration/integration-astro-hybrid/references/basic-integration-1.2-revise.md +23 -0
  151. package/skills/integration/integration-astro-hybrid/references/basic-integration-1.3-conclude.md +57 -0
  152. package/skills/integration/integration-astro-hybrid/references/browser-sdk-2.md +4680 -0
  153. package/skills/integration/integration-astro-ssr/SKILL.md +52 -0
  154. package/skills/integration/integration-astro-ssr/references/EXAMPLE.md +1106 -0
  155. package/skills/integration/integration-astro-ssr/references/amplitude-quickstart.md +1845 -0
  156. package/skills/integration/integration-astro-ssr/references/basic-integration-1.0-begin.md +43 -0
  157. package/skills/integration/integration-astro-ssr/references/basic-integration-1.1-edit.md +35 -0
  158. package/skills/integration/integration-astro-ssr/references/basic-integration-1.2-revise.md +23 -0
  159. package/skills/integration/integration-astro-ssr/references/basic-integration-1.3-conclude.md +57 -0
  160. package/skills/integration/integration-astro-ssr/references/browser-sdk-2.md +4680 -0
  161. package/skills/integration/integration-astro-static/SKILL.md +49 -0
  162. package/skills/integration/integration-astro-static/references/EXAMPLE.md +910 -0
  163. package/skills/integration/integration-astro-static/references/amplitude-quickstart.md +1845 -0
  164. package/skills/integration/integration-astro-static/references/basic-integration-1.0-begin.md +43 -0
  165. package/skills/integration/integration-astro-static/references/basic-integration-1.1-edit.md +35 -0
  166. package/skills/integration/integration-astro-static/references/basic-integration-1.2-revise.md +23 -0
  167. package/skills/integration/integration-astro-static/references/basic-integration-1.3-conclude.md +57 -0
  168. package/skills/integration/integration-astro-static/references/browser-sdk-2.md +4680 -0
  169. package/skills/integration/integration-astro-view-transitions/SKILL.md +51 -0
  170. package/skills/integration/integration-astro-view-transitions/references/EXAMPLE.md +979 -0
  171. package/skills/integration/integration-astro-view-transitions/references/amplitude-quickstart.md +1845 -0
  172. package/skills/integration/integration-astro-view-transitions/references/basic-integration-1.0-begin.md +43 -0
  173. package/skills/integration/integration-astro-view-transitions/references/basic-integration-1.1-edit.md +35 -0
  174. package/skills/integration/integration-astro-view-transitions/references/basic-integration-1.2-revise.md +23 -0
  175. package/skills/integration/integration-astro-view-transitions/references/basic-integration-1.3-conclude.md +57 -0
  176. package/skills/integration/integration-astro-view-transitions/references/browser-sdk-2.md +4680 -0
  177. package/skills/integration/integration-django/SKILL.md +57 -0
  178. package/skills/integration/integration-django/references/EXAMPLE.md +1005 -0
  179. package/skills/integration/integration-django/references/amplitude-quickstart.md +1845 -0
  180. package/skills/integration/integration-django/references/basic-integration-1.0-begin.md +43 -0
  181. package/skills/integration/integration-django/references/basic-integration-1.1-edit.md +35 -0
  182. package/skills/integration/integration-django/references/basic-integration-1.2-revise.md +23 -0
  183. package/skills/integration/integration-django/references/basic-integration-1.3-conclude.md +57 -0
  184. package/skills/integration/integration-django/references/python.md +1424 -0
  185. package/skills/integration/integration-expo/SKILL.md +53 -0
  186. package/skills/integration/integration-expo/references/EXAMPLE.md +1291 -0
  187. package/skills/integration/integration-expo/references/amplitude-quickstart.md +1845 -0
  188. package/skills/integration/integration-expo/references/basic-integration-1.0-begin.md +43 -0
  189. package/skills/integration/integration-expo/references/basic-integration-1.1-edit.md +35 -0
  190. package/skills/integration/integration-expo/references/basic-integration-1.2-revise.md +23 -0
  191. package/skills/integration/integration-expo/references/basic-integration-1.3-conclude.md +57 -0
  192. package/skills/integration/integration-expo/references/react-native-sdk.md +2819 -0
  193. package/skills/integration/integration-fastapi/SKILL.md +57 -0
  194. package/skills/integration/integration-fastapi/references/EXAMPLE.md +1389 -0
  195. package/skills/integration/integration-fastapi/references/amplitude-quickstart.md +1845 -0
  196. package/skills/integration/integration-fastapi/references/basic-integration-1.0-begin.md +43 -0
  197. package/skills/integration/integration-fastapi/references/basic-integration-1.1-edit.md +35 -0
  198. package/skills/integration/integration-fastapi/references/basic-integration-1.2-revise.md +23 -0
  199. package/skills/integration/integration-fastapi/references/basic-integration-1.3-conclude.md +57 -0
  200. package/skills/integration/integration-fastapi/references/python.md +1424 -0
  201. package/skills/integration/integration-flask/SKILL.md +56 -0
  202. package/skills/integration/integration-flask/references/EXAMPLE.md +1130 -0
  203. package/skills/integration/integration-flask/references/amplitude-quickstart.md +1845 -0
  204. package/skills/integration/integration-flask/references/basic-integration-1.0-begin.md +43 -0
  205. package/skills/integration/integration-flask/references/basic-integration-1.1-edit.md +35 -0
  206. package/skills/integration/integration-flask/references/basic-integration-1.2-revise.md +23 -0
  207. package/skills/integration/integration-flask/references/basic-integration-1.3-conclude.md +57 -0
  208. package/skills/integration/integration-flask/references/python.md +1424 -0
  209. package/skills/integration/integration-javascript_node/SKILL.md +54 -0
  210. package/skills/integration/integration-javascript_node/references/EXAMPLE.md +365 -0
  211. package/skills/integration/integration-javascript_node/references/amplitude-quickstart.md +1845 -0
  212. package/skills/integration/integration-javascript_node/references/analytics.md +1778 -0
  213. package/skills/integration/integration-javascript_node/references/basic-integration-1.0-begin.md +43 -0
  214. package/skills/integration/integration-javascript_node/references/basic-integration-1.1-edit.md +35 -0
  215. package/skills/integration/integration-javascript_node/references/basic-integration-1.2-revise.md +23 -0
  216. package/skills/integration/integration-javascript_node/references/basic-integration-1.3-conclude.md +57 -0
  217. package/skills/integration/integration-javascript_web/SKILL.md +58 -0
  218. package/skills/integration/integration-javascript_web/references/EXAMPLE.md +451 -0
  219. package/skills/integration/integration-javascript_web/references/amplitude-quickstart.md +1845 -0
  220. package/skills/integration/integration-javascript_web/references/basic-integration-1.0-begin.md +43 -0
  221. package/skills/integration/integration-javascript_web/references/basic-integration-1.1-edit.md +35 -0
  222. package/skills/integration/integration-javascript_web/references/basic-integration-1.2-revise.md +23 -0
  223. package/skills/integration/integration-javascript_web/references/basic-integration-1.3-conclude.md +57 -0
  224. package/skills/integration/integration-javascript_web/references/browser-sdk-2.md +4680 -0
  225. package/skills/integration/integration-laravel/SKILL.md +52 -0
  226. package/skills/integration/integration-laravel/references/EXAMPLE.md +2039 -0
  227. package/skills/integration/integration-laravel/references/amplitude-quickstart.md +1845 -0
  228. package/skills/integration/integration-laravel/references/analytics.md +1778 -0
  229. package/skills/integration/integration-laravel/references/basic-integration-1.0-begin.md +43 -0
  230. package/skills/integration/integration-laravel/references/basic-integration-1.1-edit.md +35 -0
  231. package/skills/integration/integration-laravel/references/basic-integration-1.2-revise.md +23 -0
  232. package/skills/integration/integration-laravel/references/basic-integration-1.3-conclude.md +57 -0
  233. package/skills/integration/integration-nextjs-app-router/SKILL.md +54 -0
  234. package/skills/integration/integration-nextjs-app-router/references/EXAMPLE.md +673 -0
  235. package/skills/integration/integration-nextjs-app-router/references/amplitude-quickstart.md +1845 -0
  236. package/skills/integration/integration-nextjs-app-router/references/basic-integration-1.0-begin.md +43 -0
  237. package/skills/integration/integration-nextjs-app-router/references/basic-integration-1.1-edit.md +35 -0
  238. package/skills/integration/integration-nextjs-app-router/references/basic-integration-1.2-revise.md +23 -0
  239. package/skills/integration/integration-nextjs-app-router/references/basic-integration-1.3-conclude.md +57 -0
  240. package/skills/integration/integration-nextjs-app-router/references/browser-sdk-2.md +4680 -0
  241. package/skills/integration/integration-nextjs-pages-router/SKILL.md +54 -0
  242. package/skills/integration/integration-nextjs-pages-router/references/EXAMPLE.md +735 -0
  243. package/skills/integration/integration-nextjs-pages-router/references/amplitude-quickstart.md +1845 -0
  244. package/skills/integration/integration-nextjs-pages-router/references/basic-integration-1.0-begin.md +43 -0
  245. package/skills/integration/integration-nextjs-pages-router/references/basic-integration-1.1-edit.md +35 -0
  246. package/skills/integration/integration-nextjs-pages-router/references/basic-integration-1.2-revise.md +23 -0
  247. package/skills/integration/integration-nextjs-pages-router/references/basic-integration-1.3-conclude.md +57 -0
  248. package/skills/integration/integration-nextjs-pages-router/references/browser-sdk-2.md +4680 -0
  249. package/skills/integration/integration-nuxt-3.6/SKILL.md +46 -0
  250. package/skills/integration/integration-nuxt-3.6/references/EXAMPLE.md +8422 -0
  251. package/skills/integration/integration-nuxt-3.6/references/amplitude-quickstart.md +1845 -0
  252. package/skills/integration/integration-nuxt-3.6/references/basic-integration-1.0-begin.md +43 -0
  253. package/skills/integration/integration-nuxt-3.6/references/basic-integration-1.1-edit.md +35 -0
  254. package/skills/integration/integration-nuxt-3.6/references/basic-integration-1.2-revise.md +23 -0
  255. package/skills/integration/integration-nuxt-3.6/references/basic-integration-1.3-conclude.md +57 -0
  256. package/skills/integration/integration-nuxt-3.6/references/browser-sdk-2.md +4680 -0
  257. package/skills/integration/integration-nuxt-4/SKILL.md +46 -0
  258. package/skills/integration/integration-nuxt-4/references/EXAMPLE.md +8670 -0
  259. package/skills/integration/integration-nuxt-4/references/amplitude-quickstart.md +1845 -0
  260. package/skills/integration/integration-nuxt-4/references/basic-integration-1.0-begin.md +43 -0
  261. package/skills/integration/integration-nuxt-4/references/basic-integration-1.1-edit.md +35 -0
  262. package/skills/integration/integration-nuxt-4/references/basic-integration-1.2-revise.md +23 -0
  263. package/skills/integration/integration-nuxt-4/references/basic-integration-1.3-conclude.md +57 -0
  264. package/skills/integration/integration-nuxt-4/references/browser-sdk-2.md +4680 -0
  265. package/skills/integration/integration-python/SKILL.md +53 -0
  266. package/skills/integration/integration-python/references/EXAMPLE.md +445 -0
  267. package/skills/integration/integration-python/references/amplitude-quickstart.md +1845 -0
  268. package/skills/integration/integration-python/references/basic-integration-1.0-begin.md +43 -0
  269. package/skills/integration/integration-python/references/basic-integration-1.1-edit.md +35 -0
  270. package/skills/integration/integration-python/references/basic-integration-1.2-revise.md +23 -0
  271. package/skills/integration/integration-python/references/basic-integration-1.3-conclude.md +57 -0
  272. package/skills/integration/integration-python/references/python.md +1424 -0
  273. package/skills/integration/integration-react-native/SKILL.md +49 -0
  274. package/skills/integration/integration-react-native/references/EXAMPLE.md +2253 -0
  275. package/skills/integration/integration-react-native/references/amplitude-quickstart.md +1845 -0
  276. package/skills/integration/integration-react-native/references/basic-integration-1.0-begin.md +43 -0
  277. package/skills/integration/integration-react-native/references/basic-integration-1.1-edit.md +35 -0
  278. package/skills/integration/integration-react-native/references/basic-integration-1.2-revise.md +23 -0
  279. package/skills/integration/integration-react-native/references/basic-integration-1.3-conclude.md +57 -0
  280. package/skills/integration/integration-react-native/references/react-native-sdk.md +2819 -0
  281. package/skills/integration/integration-react-react-router-6/SKILL.md +53 -0
  282. package/skills/integration/integration-react-react-router-6/references/EXAMPLE.md +570 -0
  283. package/skills/integration/integration-react-react-router-6/references/amplitude-quickstart.md +1845 -0
  284. package/skills/integration/integration-react-react-router-6/references/basic-integration-1.0-begin.md +43 -0
  285. package/skills/integration/integration-react-react-router-6/references/basic-integration-1.1-edit.md +35 -0
  286. package/skills/integration/integration-react-react-router-6/references/basic-integration-1.2-revise.md +23 -0
  287. package/skills/integration/integration-react-react-router-6/references/basic-integration-1.3-conclude.md +57 -0
  288. package/skills/integration/integration-react-react-router-6/references/browser-sdk-2.md +4680 -0
  289. package/skills/integration/integration-react-react-router-7-data/SKILL.md +53 -0
  290. package/skills/integration/integration-react-react-router-7-data/references/EXAMPLE.md +830 -0
  291. package/skills/integration/integration-react-react-router-7-data/references/amplitude-quickstart.md +1845 -0
  292. package/skills/integration/integration-react-react-router-7-data/references/basic-integration-1.0-begin.md +43 -0
  293. package/skills/integration/integration-react-react-router-7-data/references/basic-integration-1.1-edit.md +35 -0
  294. package/skills/integration/integration-react-react-router-7-data/references/basic-integration-1.2-revise.md +23 -0
  295. package/skills/integration/integration-react-react-router-7-data/references/basic-integration-1.3-conclude.md +57 -0
  296. package/skills/integration/integration-react-react-router-7-data/references/browser-sdk-2.md +4680 -0
  297. package/skills/integration/integration-react-react-router-7-declarative/SKILL.md +53 -0
  298. package/skills/integration/integration-react-react-router-7-declarative/references/EXAMPLE.md +609 -0
  299. package/skills/integration/integration-react-react-router-7-declarative/references/amplitude-quickstart.md +1845 -0
  300. package/skills/integration/integration-react-react-router-7-declarative/references/basic-integration-1.0-begin.md +43 -0
  301. package/skills/integration/integration-react-react-router-7-declarative/references/basic-integration-1.1-edit.md +35 -0
  302. package/skills/integration/integration-react-react-router-7-declarative/references/basic-integration-1.2-revise.md +23 -0
  303. package/skills/integration/integration-react-react-router-7-declarative/references/basic-integration-1.3-conclude.md +57 -0
  304. package/skills/integration/integration-react-react-router-7-declarative/references/browser-sdk-2.md +4680 -0
  305. package/skills/integration/integration-react-react-router-7-framework/SKILL.md +53 -0
  306. package/skills/integration/integration-react-react-router-7-framework/references/EXAMPLE.md +1081 -0
  307. package/skills/integration/integration-react-react-router-7-framework/references/amplitude-quickstart.md +1845 -0
  308. package/skills/integration/integration-react-react-router-7-framework/references/basic-integration-1.0-begin.md +43 -0
  309. package/skills/integration/integration-react-react-router-7-framework/references/basic-integration-1.1-edit.md +35 -0
  310. package/skills/integration/integration-react-react-router-7-framework/references/basic-integration-1.2-revise.md +23 -0
  311. package/skills/integration/integration-react-react-router-7-framework/references/basic-integration-1.3-conclude.md +57 -0
  312. package/skills/integration/integration-react-react-router-7-framework/references/browser-sdk-2.md +4680 -0
  313. package/skills/integration/integration-react-tanstack-router-code-based/SKILL.md +57 -0
  314. package/skills/integration/integration-react-tanstack-router-code-based/references/EXAMPLE.md +659 -0
  315. package/skills/integration/integration-react-tanstack-router-code-based/references/amplitude-quickstart.md +1845 -0
  316. package/skills/integration/integration-react-tanstack-router-code-based/references/basic-integration-1.0-begin.md +43 -0
  317. package/skills/integration/integration-react-tanstack-router-code-based/references/basic-integration-1.1-edit.md +35 -0
  318. package/skills/integration/integration-react-tanstack-router-code-based/references/basic-integration-1.2-revise.md +23 -0
  319. package/skills/integration/integration-react-tanstack-router-code-based/references/basic-integration-1.3-conclude.md +57 -0
  320. package/skills/integration/integration-react-tanstack-router-code-based/references/browser-sdk-2.md +4680 -0
  321. package/skills/integration/integration-react-tanstack-router-file-based/SKILL.md +57 -0
  322. package/skills/integration/integration-react-tanstack-router-file-based/references/EXAMPLE.md +777 -0
  323. package/skills/integration/integration-react-tanstack-router-file-based/references/amplitude-quickstart.md +1845 -0
  324. package/skills/integration/integration-react-tanstack-router-file-based/references/basic-integration-1.0-begin.md +43 -0
  325. package/skills/integration/integration-react-tanstack-router-file-based/references/basic-integration-1.1-edit.md +35 -0
  326. package/skills/integration/integration-react-tanstack-router-file-based/references/basic-integration-1.2-revise.md +23 -0
  327. package/skills/integration/integration-react-tanstack-router-file-based/references/basic-integration-1.3-conclude.md +57 -0
  328. package/skills/integration/integration-react-tanstack-router-file-based/references/browser-sdk-2.md +4680 -0
  329. package/skills/integration/integration-react-vite/SKILL.md +53 -0
  330. package/skills/integration/integration-react-vite/references/EXAMPLE.md +542 -0
  331. package/skills/integration/integration-react-vite/references/amplitude-quickstart.md +1845 -0
  332. package/skills/integration/integration-react-vite/references/basic-integration-1.0-begin.md +43 -0
  333. package/skills/integration/integration-react-vite/references/basic-integration-1.1-edit.md +35 -0
  334. package/skills/integration/integration-react-vite/references/basic-integration-1.2-revise.md +23 -0
  335. package/skills/integration/integration-react-vite/references/basic-integration-1.3-conclude.md +57 -0
  336. package/skills/integration/integration-react-vite/references/browser-sdk-2.md +4680 -0
  337. package/skills/integration/integration-ruby/SKILL.md +50 -0
  338. package/skills/integration/integration-ruby/references/EXAMPLE.md +420 -0
  339. package/skills/integration/integration-ruby/references/amplitude-quickstart.md +1845 -0
  340. package/skills/integration/integration-ruby/references/analytics.md +1778 -0
  341. package/skills/integration/integration-ruby/references/basic-integration-1.0-begin.md +43 -0
  342. package/skills/integration/integration-ruby/references/basic-integration-1.1-edit.md +35 -0
  343. package/skills/integration/integration-ruby/references/basic-integration-1.2-revise.md +23 -0
  344. package/skills/integration/integration-ruby/references/basic-integration-1.3-conclude.md +57 -0
  345. package/skills/integration/integration-ruby-on-rails/SKILL.md +55 -0
  346. package/skills/integration/integration-ruby-on-rails/references/EXAMPLE.md +1013 -0
  347. package/skills/integration/integration-ruby-on-rails/references/amplitude-quickstart.md +1845 -0
  348. package/skills/integration/integration-ruby-on-rails/references/analytics.md +1778 -0
  349. package/skills/integration/integration-ruby-on-rails/references/basic-integration-1.0-begin.md +43 -0
  350. package/skills/integration/integration-ruby-on-rails/references/basic-integration-1.1-edit.md +35 -0
  351. package/skills/integration/integration-ruby-on-rails/references/basic-integration-1.2-revise.md +23 -0
  352. package/skills/integration/integration-ruby-on-rails/references/basic-integration-1.3-conclude.md +57 -0
  353. package/skills/integration/integration-sveltekit/SKILL.md +47 -0
  354. package/skills/integration/integration-sveltekit/references/EXAMPLE.md +14121 -0
  355. package/skills/integration/integration-sveltekit/references/amplitude-quickstart.md +1845 -0
  356. package/skills/integration/integration-sveltekit/references/basic-integration-1.0-begin.md +43 -0
  357. package/skills/integration/integration-sveltekit/references/basic-integration-1.1-edit.md +35 -0
  358. package/skills/integration/integration-sveltekit/references/basic-integration-1.2-revise.md +23 -0
  359. package/skills/integration/integration-sveltekit/references/basic-integration-1.3-conclude.md +57 -0
  360. package/skills/integration/integration-sveltekit/references/browser-sdk-2.md +4680 -0
  361. package/skills/integration/integration-swift/SKILL.md +49 -0
  362. package/skills/integration/integration-swift/references/EXAMPLE.md +660 -0
  363. package/skills/integration/integration-swift/references/amplitude-quickstart.md +1845 -0
  364. package/skills/integration/integration-swift/references/analytics.md +1778 -0
  365. package/skills/integration/integration-swift/references/basic-integration-1.0-begin.md +43 -0
  366. package/skills/integration/integration-swift/references/basic-integration-1.1-edit.md +35 -0
  367. package/skills/integration/integration-swift/references/basic-integration-1.2-revise.md +23 -0
  368. package/skills/integration/integration-swift/references/basic-integration-1.3-conclude.md +57 -0
  369. package/skills/integration/integration-tanstack-start/SKILL.md +58 -0
  370. package/skills/integration/integration-tanstack-start/references/EXAMPLE.md +998 -0
  371. package/skills/integration/integration-tanstack-start/references/amplitude-quickstart.md +1845 -0
  372. package/skills/integration/integration-tanstack-start/references/basic-integration-1.0-begin.md +43 -0
  373. package/skills/integration/integration-tanstack-start/references/basic-integration-1.1-edit.md +35 -0
  374. package/skills/integration/integration-tanstack-start/references/basic-integration-1.2-revise.md +23 -0
  375. package/skills/integration/integration-tanstack-start/references/basic-integration-1.3-conclude.md +57 -0
  376. package/skills/integration/integration-tanstack-start/references/browser-sdk-2.md +4680 -0
  377. package/skills/integration/integration-vue-3/SKILL.md +46 -0
  378. package/skills/integration/integration-vue-3/references/EXAMPLE.md +846 -0
  379. package/skills/integration/integration-vue-3/references/amplitude-quickstart.md +1845 -0
  380. package/skills/integration/integration-vue-3/references/basic-integration-1.0-begin.md +43 -0
  381. package/skills/integration/integration-vue-3/references/basic-integration-1.1-edit.md +35 -0
  382. package/skills/integration/integration-vue-3/references/basic-integration-1.2-revise.md +23 -0
  383. package/skills/integration/integration-vue-3/references/basic-integration-1.3-conclude.md +57 -0
  384. package/skills/integration/integration-vue-3/references/browser-sdk-2.md +4680 -0
  385. package/skills/taxonomy/amplitude-quickstart-taxonomy-agent/SKILL.md +228 -0
  386. package/dist/src/ui/tui/components/TitleBar.d.ts +0 -8
  387. package/dist/src/ui/tui/components/TitleBar.js +0 -27
  388. package/dist/src/ui/tui/primitives/KagiSmallWebViewer.d.ts +0 -7
  389. package/dist/src/ui/tui/primitives/KagiSmallWebViewer.js +0 -101
  390. package/dist/src/utils/anthropic-status.d.ts +0 -17
  391. package/dist/src/utils/anthropic-status.js +0 -51
@@ -0,0 +1,2253 @@
1
+ # Amplitude React Native Example Project
2
+
3
+ Repository: https://github.com/amplitude/context-hub
4
+ Path: basics/react-native
5
+
6
+ ---
7
+
8
+ ## README.md
9
+
10
+ # Amplitude React Native example
11
+
12
+ This is a bare [React Native](https://reactnative.dev/) example (no Expo) demonstrating Amplitude integration with product analytics and user identification.
13
+
14
+ ## Features
15
+
16
+ - **Product analytics**: Track user events and behaviors
17
+ - **User authentication**: Demo login system with Amplitude user identification
18
+ - **Session persistence**: AsyncStorage for maintaining user sessions across app restarts
19
+ - **Native navigation**: React Navigation v7 with native stack navigator
20
+
21
+ ## Prerequisites
22
+
23
+ ### For iOS Development
24
+
25
+ You need a Mac with the following installed:
26
+
27
+ 1. **Xcode** (from the Mac App Store)
28
+ - Open App Store and search for "Xcode"
29
+ - Install it (~12GB download)
30
+ - After installing, open Xcode once to accept the license agreement
31
+
32
+ 2. **Xcode Command Line Tools**
33
+ ```bash
34
+ xcode-select --install
35
+ ```
36
+
37
+ 3. **CocoaPods** (iOS dependency manager)
38
+ ```bash
39
+ brew install cocoapods
40
+ ```
41
+ Or without Homebrew:
42
+ ```bash
43
+ sudo gem install cocoapods
44
+ ```
45
+
46
+ ### For Android Development
47
+
48
+ 1. **Android Studio** (the Android IDE)
49
+ ```bash
50
+ brew install --cask android-studio
51
+ ```
52
+ Or download from: https://developer.android.com/studio
53
+
54
+ 2. **First-time Android Studio Setup**
55
+ - Open Android Studio
56
+ - Complete the setup wizard (downloads Android SDK automatically)
57
+ - Go to **Settings → Languages & Frameworks → Android SDK**
58
+ - Ensure "Android SDK Platform 34" (or latest) is installed
59
+
60
+ 3. **Create an Android Emulator**
61
+ - In Android Studio: **Tools → Device Manager**
62
+ - Click **Create Device**
63
+ - Select a phone (e.g., "Pixel 7")
64
+ - Download a system image (e.g., API 34)
65
+ - Finish and click the **Play** button to launch
66
+
67
+ 4. **Environment Variables** (add to `~/.zshrc` or `~/.bashrc`)
68
+ ```bash
69
+ # Android SDK
70
+ export ANDROID_HOME=$HOME/Library/Android/sdk
71
+ export PATH=$PATH:$ANDROID_HOME/emulator
72
+ export PATH=$PATH:$ANDROID_HOME/platform-tools
73
+
74
+ # Java from Android Studio (required for Gradle)
75
+ export JAVA_HOME="/Applications/Android Studio.app/Contents/jbr/Contents/Home"
76
+ export PATH=$JAVA_HOME/bin:$PATH
77
+ ```
78
+ Then run `source ~/.zshrc` to apply.
79
+
80
+ 5. **Create local.properties file** (if SDK location is not detected)
81
+ Create `android/local.properties` with:
82
+ ```
83
+ sdk.dir=$HOME/Library/Android/sdk
84
+ ```
85
+
86
+ 6. **Clear Gradle cache** (required when jumping between different versions of Gradle)
87
+ ```bash
88
+ rm -rf ~/.gradle/caches/modules-2/files-2.1/org.gradle.toolchains/foojay-resolver
89
+ ```
90
+
91
+ ## Getting started
92
+
93
+ ### 1. Install dependencies
94
+
95
+ ```bash
96
+ npm install
97
+ ```
98
+
99
+ ### 2. Configure environment variables
100
+
101
+ Create a `.env` file:
102
+
103
+ ```bash
104
+ cp .env.example .env
105
+ ```
106
+
107
+ Edit `.env` and add your Amplitude API key:
108
+
109
+ ```bash
110
+ AMPLITUDE_API_KEY=your_amplitude_api_key_here
111
+ ```
112
+
113
+ Get your Amplitude API key from your [Amplitude project settings](https://app.amplitude.com).
114
+
115
+ > **Note:** The app will still run without an Amplitude API key - analytics will simply be disabled.
116
+
117
+ ### 3. Run on iOS
118
+
119
+ Install iOS dependencies (first time only):
120
+ ```bash
121
+ cd ios && pod install && cd ..
122
+ ```
123
+
124
+ Run the app:
125
+ ```bash
126
+ npm run ios
127
+ ```
128
+
129
+ > **Note:** First build takes 5-10 minutes. Subsequent builds are much faster.
130
+
131
+ ### 4. Run on Android
132
+
133
+ Make sure an Android emulator is running (from Android Studio Device Manager), then:
134
+
135
+ ```bash
136
+ npm run android
137
+ ```
138
+
139
+ > **Note:** First build takes 3-5 minutes.
140
+
141
+ ## Troubleshooting
142
+
143
+ ### iOS Issues
144
+
145
+ **"No `Podfile' found"**
146
+ - Make sure you're in the `ios` directory: `cd ios && pod install`
147
+
148
+ **Build fails with signing errors**
149
+ - Open `ios/BurritoApp.xcworkspace` in Xcode
150
+ - Select the project → Signing & Capabilities
151
+ - Select your development team
152
+
153
+ **Simulator not launching**
154
+ - Open Xcode → Open Developer Tool → Simulator
155
+ - Or run: `open -a Simulator`
156
+
157
+ ### Android Issues
158
+
159
+ **"SDK location not found"**
160
+ - Ensure `ANDROID_HOME` is set in your shell profile
161
+ - Run `source ~/.zshrc` after adding it
162
+
163
+ **"No connected devices"**
164
+ - Launch an emulator from Android Studio Device Manager
165
+ - Or connect a physical device with USB debugging enabled
166
+
167
+ **Gradle build fails**
168
+ - Try: `cd android && ./gradlew clean && cd ..`
169
+ - Then: `npm run android`
170
+
171
+ ## Project structure
172
+
173
+ ```
174
+ src/
175
+ ├── config/
176
+ │ └── amplitude.ts # Amplitude client configuration
177
+ ├── contexts/
178
+ │ └── AuthContext.tsx # Authentication context with Amplitude integration
179
+ ├── navigation/
180
+ │ └── RootNavigator.tsx # React Navigation stack navigator
181
+ ├── screens/
182
+ │ ├── HomeScreen.tsx # Home/login screen
183
+ │ ├── BurritoScreen.tsx # Demo feature screen with event tracking
184
+ │ └── ProfileScreen.tsx # User profile screen
185
+ ├── services/
186
+ │ └── storage.ts # AsyncStorage wrapper for persistence
187
+ ├── styles/
188
+ │ └── theme.ts # Shared style constants
189
+ └── types/
190
+ └── env.d.ts # Type declarations for environment variables
191
+
192
+ App.tsx # Root component
193
+ index.js # App entry point
194
+ .env # Environment variables (create from .env.example)
195
+ ios/ # Native iOS project (Xcode)
196
+ android/ # Native Android project (Android Studio)
197
+ ```
198
+
199
+ ## Key integration points
200
+
201
+ ### Amplitude client setup (config/amplitude.ts)
202
+
203
+ The Amplitude client is initialized with the API key from environment variables:
204
+
205
+ ```typescript
206
+ import * as amplitude from '@amplitude/analytics-react-native'
207
+ import Config from 'react-native-config'
208
+
209
+ const apiKey = Config.AMPLITUDE_API_KEY
210
+ const isAmplitudeConfigured = apiKey && apiKey !== 'your_amplitude_api_key_here'
211
+
212
+ if (isAmplitudeConfigured && apiKey) {
213
+ amplitude.init(apiKey)
214
+ }
215
+
216
+ export { amplitude }
217
+ ```
218
+
219
+ ### Screen tracking (App.tsx)
220
+
221
+ Screen views are tracked manually via React Navigation's `onStateChange`:
222
+
223
+ ```typescript
224
+ import { amplitude } from './src/config/amplitude'
225
+
226
+ onStateChange={() => {
227
+ const currentRouteName = navigationRef.current?.getCurrentRoute()?.name
228
+ if (previousRouteName !== currentRouteName && currentRouteName) {
229
+ amplitude.track('Screen Viewed', {
230
+ screen_name: currentRouteName,
231
+ previous_screen: previousRouteName,
232
+ })
233
+ }
234
+ }}
235
+ ```
236
+
237
+ ### User identification (contexts/AuthContext.tsx)
238
+
239
+ ```typescript
240
+ import { Identify } from '@amplitude/analytics-react-native'
241
+ import { amplitude } from '../config/amplitude'
242
+
243
+ // On login - identify user with properties
244
+ amplitude.setUserId(username)
245
+ const identifyObj = new Identify()
246
+ identifyObj.set('username', username)
247
+ amplitude.identify(identifyObj)
248
+
249
+ // Track login event
250
+ amplitude.track('User Logged In', {
251
+ username,
252
+ is_new_user: isNewUser,
253
+ })
254
+
255
+ // On logout - reset clears identity
256
+ amplitude.track('User Logged Out')
257
+ amplitude.reset()
258
+ ```
259
+
260
+ ### Event tracking (screens/BurritoScreen.tsx)
261
+
262
+ ```typescript
263
+ import { amplitude } from '../config/amplitude'
264
+
265
+ amplitude.track('Burrito Considered', {
266
+ total_considerations: newCount,
267
+ username: user.username,
268
+ })
269
+ ```
270
+
271
+ ### Session persistence (services/storage.ts)
272
+
273
+ AsyncStorage replaces localStorage for persisting user sessions:
274
+
275
+ ```typescript
276
+ import AsyncStorage from '@react-native-async-storage/async-storage'
277
+
278
+ export const storage = {
279
+ getCurrentUser: async (): Promise<string | null> => {
280
+ return await AsyncStorage.getItem('currentUser')
281
+ },
282
+
283
+ setCurrentUser: async (username: string): Promise<void> => {
284
+ await AsyncStorage.setItem('currentUser', username)
285
+ },
286
+
287
+ saveUser: async (user: User): Promise<void> => {
288
+ const users = await storage.getUsers()
289
+ users[user.username] = user
290
+ await AsyncStorage.setItem('users', JSON.stringify(users))
291
+ },
292
+ }
293
+ ```
294
+
295
+ ## Learn more
296
+
297
+ - [Amplitude documentation](https://amplitude.com/docs)
298
+ - [Amplitude React Native SDK](https://amplitude.com/docs/sdks/analytics/react-native)
299
+ - [React Native documentation](https://reactnative.dev/docs/getting-started)
300
+ - [React Native environment setup](https://reactnative.dev/docs/set-up-your-environment)
301
+ - [React Navigation documentation](https://reactnavigation.org/docs/getting-started)
302
+
303
+ ---
304
+
305
+ ## __tests__/App.test.tsx
306
+
307
+ ```tsx
308
+ /**
309
+ * @format
310
+ */
311
+
312
+ import React from 'react';
313
+ import ReactTestRenderer from 'react-test-renderer';
314
+ import App from '../App';
315
+
316
+ test('renders correctly', async () => {
317
+ await ReactTestRenderer.act(() => {
318
+ ReactTestRenderer.create(<App />);
319
+ });
320
+ });
321
+
322
+ ```
323
+
324
+ ---
325
+
326
+ ## .env.example
327
+
328
+ ```example
329
+ AMPLITUDE_API_KEY=your_amplitude_api_key_here
330
+
331
+ ```
332
+
333
+ ---
334
+
335
+ ## .prettierrc.js
336
+
337
+ ```js
338
+ module.exports = {
339
+ arrowParens: 'avoid',
340
+ singleQuote: true,
341
+ trailingComma: 'all',
342
+ };
343
+
344
+ ```
345
+
346
+ ---
347
+
348
+ ## android/app/debug.keystore
349
+
350
+ ```keystore
351
+ ����androiddebugkeyCJ���0��0
352
+ +*��N���O�J�`>���X'����_���ȏ� R9���,xJ'K~\j��:ز��}�U)Q]"���ա!� Ȉ��Ù��F�5�H�x�A�\�P�)��@�I�s�d��>�2#m�י�j/8p��","ȁ��|\����1e�7�!����h(����.�Fi5��o��ung�*�!�����vF��֪�Sb!��T��4�
353
+ ˺��s����Y�qX.5090�{0�c�#.�b0
354
+ Unknown10U Android10U
355
+ Unknown10U Android10U
356
+ ���n &�l�Dx�%�
357
+ �EIr�M�%�����a�!00U ��8�Ҋ�X��
358
+ �C(�#� 0
359
+ m~<���vֶ�'.��h%�h� w�0E^{�ù�/Oz��u�R��$_1�I�~����s��ܖ��ӓ���֭�\�JX��j��;RC�՜�n<q�f�$��Z1N�������7����ڵk[Ųm��5^B����]W��e���i4V��*:�D~]z�ޝ����<��l.e���Ɖ��#�L�:c�~0�?���q�I�@���x�٨�*I�ӗ���Y`G'@^w�
360
+ ```
361
+
362
+ ---
363
+
364
+ ## android/app/proguard-rules.pro
365
+
366
+ ```pro
367
+ # Add project specific ProGuard rules here.
368
+ # By default, the flags in this file are appended to flags specified
369
+ # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt
370
+ # You can edit the include path and order by changing the proguardFiles
371
+ # directive in build.gradle.
372
+ #
373
+ # For more details, see
374
+ # http://developer.android.com/guide/developing/tools/proguard.html
375
+
376
+ # Add any project specific keep options here:
377
+
378
+ ```
379
+
380
+ ---
381
+
382
+ ## android/app/src/main/AndroidManifest.xml
383
+
384
+ ```xml
385
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android">
386
+
387
+ <uses-permission android:name="android.permission.INTERNET" />
388
+
389
+ <application
390
+ android:name=".MainApplication"
391
+ android:label="@string/app_name"
392
+ android:icon="@mipmap/ic_launcher"
393
+ android:roundIcon="@mipmap/ic_launcher_round"
394
+ android:allowBackup="false"
395
+ android:theme="@style/AppTheme"
396
+ android:usesCleartextTraffic="${usesCleartextTraffic}"
397
+ android:supportsRtl="true">
398
+ <activity
399
+ android:name=".MainActivity"
400
+ android:label="@string/app_name"
401
+ android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode"
402
+ android:launchMode="singleTask"
403
+ android:windowSoftInputMode="adjustResize"
404
+ android:exported="true">
405
+ <intent-filter>
406
+ <action android:name="android.intent.action.MAIN" />
407
+ <category android:name="android.intent.category.LAUNCHER" />
408
+ </intent-filter>
409
+ </activity>
410
+ </application>
411
+ </manifest>
412
+
413
+ ```
414
+
415
+ ---
416
+
417
+ ## android/app/src/main/java/com/burritoapp/MainActivity.kt
418
+
419
+ ```kt
420
+ package com.burritoapp
421
+
422
+ import com.facebook.react.ReactActivity
423
+ import com.facebook.react.ReactActivityDelegate
424
+ import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled
425
+ import com.facebook.react.defaults.DefaultReactActivityDelegate
426
+
427
+ class MainActivity : ReactActivity() {
428
+
429
+ /**
430
+ * Returns the name of the main component registered from JavaScript. This is used to schedule
431
+ * rendering of the component.
432
+ */
433
+ override fun getMainComponentName(): String = "BurritoApp"
434
+
435
+ /**
436
+ * Returns the instance of the [ReactActivityDelegate]. We use [DefaultReactActivityDelegate]
437
+ * which allows you to enable New Architecture with a single boolean flags [fabricEnabled]
438
+ */
439
+ override fun createReactActivityDelegate(): ReactActivityDelegate =
440
+ DefaultReactActivityDelegate(this, mainComponentName, fabricEnabled)
441
+ }
442
+
443
+ ```
444
+
445
+ ---
446
+
447
+ ## android/app/src/main/java/com/burritoapp/MainApplication.kt
448
+
449
+ ```kt
450
+ package com.burritoapp
451
+
452
+ import android.app.Application
453
+ import com.facebook.react.PackageList
454
+ import com.facebook.react.ReactApplication
455
+ import com.facebook.react.ReactHost
456
+ import com.facebook.react.ReactNativeApplicationEntryPoint.loadReactNative
457
+ import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost
458
+
459
+ class MainApplication : Application(), ReactApplication {
460
+
461
+ override val reactHost: ReactHost by lazy {
462
+ getDefaultReactHost(
463
+ context = applicationContext,
464
+ packageList =
465
+ PackageList(this).packages.apply {
466
+ // Packages that cannot be autolinked yet can be added manually here, for example:
467
+ // add(MyReactNativePackage())
468
+ },
469
+ )
470
+ }
471
+
472
+ override fun onCreate() {
473
+ super.onCreate()
474
+ loadReactNative(this)
475
+ }
476
+ }
477
+
478
+ ```
479
+
480
+ ---
481
+
482
+ ## android/app/src/main/res/drawable/rn_edit_text_material.xml
483
+
484
+ ```xml
485
+ <?xml version="1.0" encoding="utf-8"?>
486
+ <!-- Copyright (C) 2014 The Android Open Source Project
487
+
488
+ Licensed under the Apache License, Version 2.0 (the "License");
489
+ you may not use this file except in compliance with the License.
490
+ You may obtain a copy of the License at
491
+
492
+ http://www.apache.org/licenses/LICENSE-2.0
493
+
494
+ Unless required by applicable law or agreed to in writing, software
495
+ distributed under the License is distributed on an "AS IS" BASIS,
496
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
497
+ See the License for the specific language governing permissions and
498
+ limitations under the License.
499
+ -->
500
+ <inset xmlns:android="http://schemas.android.com/apk/res/android"
501
+ android:insetLeft="@dimen/abc_edit_text_inset_horizontal_material"
502
+ android:insetRight="@dimen/abc_edit_text_inset_horizontal_material"
503
+ android:insetTop="@dimen/abc_edit_text_inset_top_material"
504
+ android:insetBottom="@dimen/abc_edit_text_inset_bottom_material"
505
+ >
506
+
507
+ <selector>
508
+ <!--
509
+ This file is a copy of abc_edit_text_material (https://bit.ly/3k8fX7I).
510
+ The item below with state_pressed="false" and state_focused="false" causes a NullPointerException.
511
+ NullPointerException:tempt to invoke virtual method 'android.graphics.drawable.Drawable android.graphics.drawable.Drawable$ConstantState.newDrawable(android.content.res.Resources)'
512
+
513
+ <item android:state_pressed="false" android:state_focused="false" android:drawable="@drawable/abc_textfield_default_mtrl_alpha"/>
514
+
515
+ For more info, see https://bit.ly/3CdLStv (react-native/pull/29452) and https://bit.ly/3nxOMoR.
516
+ -->
517
+ <item android:state_enabled="false" android:drawable="@drawable/abc_textfield_default_mtrl_alpha"/>
518
+ <item android:drawable="@drawable/abc_textfield_activated_mtrl_alpha"/>
519
+ </selector>
520
+
521
+ </inset>
522
+
523
+ ```
524
+
525
+ ---
526
+
527
+ ## android/app/src/main/res/values/strings.xml
528
+
529
+ ```xml
530
+ <resources>
531
+ <string name="app_name">BurritoApp</string>
532
+ </resources>
533
+
534
+ ```
535
+
536
+ ---
537
+
538
+ ## android/app/src/main/res/values/styles.xml
539
+
540
+ ```xml
541
+ <resources>
542
+
543
+ <!-- Base application theme. -->
544
+ <style name="AppTheme" parent="Theme.AppCompat.DayNight.NoActionBar">
545
+ <!-- Customize your theme here. -->
546
+ <item name="android:editTextBackground">@drawable/rn_edit_text_material</item>
547
+ </style>
548
+
549
+ </resources>
550
+
551
+ ```
552
+
553
+ ---
554
+
555
+ ## android/gradle.properties
556
+
557
+ ```properties
558
+ # Project-wide Gradle settings.
559
+
560
+ # IDE (e.g. Android Studio) users:
561
+ # Gradle settings configured through the IDE *will override*
562
+ # any settings specified in this file.
563
+
564
+ # For more details on how to configure your build environment visit
565
+ # http://www.gradle.org/docs/current/userguide/build_environment.html
566
+
567
+ # Specifies the JVM arguments used for the daemon process.
568
+ # The setting is particularly useful for tweaking memory settings.
569
+ # Default value: -Xmx512m -XX:MaxMetaspaceSize=256m
570
+ org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m
571
+
572
+ # When configured, Gradle will run in incubating parallel mode.
573
+ # This option should only be used with decoupled projects. More details, visit
574
+ # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
575
+ # org.gradle.parallel=true
576
+
577
+ # AndroidX package structure to make it clearer which packages are bundled with the
578
+ # Android operating system, and which are packaged with your app's APK
579
+ # https://developer.android.com/topic/libraries/support-library/androidx-rn
580
+ android.useAndroidX=true
581
+
582
+ # Use this property to specify which architecture you want to build.
583
+ # You can also override it from the CLI using
584
+ # ./gradlew <task> -PreactNativeArchitectures=x86_64
585
+ reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64
586
+
587
+ # Use this property to enable support to the new architecture.
588
+ # This will allow you to use TurboModules and the Fabric render in
589
+ # your application. You should enable this flag either if you want
590
+ # to write custom TurboModules/Fabric components OR use libraries that
591
+ # are providing them.
592
+ newArchEnabled=true
593
+
594
+ # Use this property to enable or disable the Hermes JS engine.
595
+ # If set to false, you will be using JSC instead.
596
+ hermesEnabled=true
597
+
598
+ # Use this property to enable edge-to-edge display support.
599
+ # This allows your app to draw behind system bars for an immersive UI.
600
+ # Note: Only works with ReactActivity and should not be used with custom Activity.
601
+ edgeToEdgeEnabled=false
602
+
603
+ ```
604
+
605
+ ---
606
+
607
+ ## App.tsx
608
+
609
+ ```tsx
610
+ import React, { useRef } from 'react'
611
+ import { StatusBar } from 'react-native'
612
+ import { SafeAreaProvider } from 'react-native-safe-area-context'
613
+ import {
614
+ NavigationContainer,
615
+ NavigationContainerRef,
616
+ } from '@react-navigation/native'
617
+
618
+ import { AuthProvider } from './src/contexts/AuthContext'
619
+ import { RootNavigator, RootStackParamList } from './src/navigation/RootNavigator'
620
+ import { amplitude } from './src/config/amplitude'
621
+ import { colors } from './src/styles/theme'
622
+
623
+ /**
624
+ * Burrito Consideration App
625
+ *
626
+ * A demo React Native application showcasing Amplitude analytics integration.
627
+ *
628
+ * Features:
629
+ * - User authentication (demo mode - accepts any credentials)
630
+ * - Burrito consideration counter with event tracking
631
+ * - User profile with statistics
632
+ */
633
+ export default function App() {
634
+ const navigationRef = useRef<NavigationContainerRef<RootStackParamList>>(null)
635
+ const routeNameRef = useRef<string | undefined>()
636
+
637
+ return (
638
+ <SafeAreaProvider>
639
+ <StatusBar
640
+ barStyle="light-content"
641
+ backgroundColor={colors.headerBackground}
642
+ />
643
+ <NavigationContainer
644
+ ref={navigationRef}
645
+ onReady={() => {
646
+ // Store the initial route name
647
+ routeNameRef.current = navigationRef.current?.getCurrentRoute()?.name
648
+ }}
649
+ onStateChange={() => {
650
+ // Track screen views manually for React Navigation v7
651
+ const previousRouteName = routeNameRef.current
652
+ const currentRouteName = navigationRef.current?.getCurrentRoute()?.name
653
+
654
+ if (previousRouteName !== currentRouteName && currentRouteName) {
655
+ // Track screen view event
656
+ amplitude.track('Screen Viewed', {
657
+ screen_name: currentRouteName,
658
+ previous_screen: previousRouteName,
659
+ })
660
+ }
661
+
662
+ // Update the stored route name
663
+ routeNameRef.current = currentRouteName
664
+ }}
665
+ >
666
+ <AuthProvider>
667
+ <RootNavigator />
668
+ </AuthProvider>
669
+ </NavigationContainer>
670
+ </SafeAreaProvider>
671
+ )
672
+ }
673
+
674
+ ```
675
+
676
+ ---
677
+
678
+ ## babel.config.js
679
+
680
+ ```js
681
+ module.exports = {
682
+ presets: ['module:@react-native/babel-preset'],
683
+ };
684
+
685
+ ```
686
+
687
+ ---
688
+
689
+ ## Gemfile
690
+
691
+ ```
692
+ source 'https://rubygems.org'
693
+
694
+ # You may use http://rbenv.org/ or https://rvm.io/ to install and use this version
695
+ ruby ">= 2.6.10"
696
+
697
+ # Exclude problematic versions of cocoapods and activesupport that causes build failures.
698
+ gem 'cocoapods', '>= 1.13', '!= 1.15.0', '!= 1.15.1'
699
+ gem 'activesupport', '>= 6.1.7.5', '!= 7.1.0'
700
+ gem 'xcodeproj', '< 1.26.0'
701
+ gem 'concurrent-ruby', '< 1.3.4'
702
+
703
+ # Ruby 3.4.0 has removed some libraries from the standard library.
704
+ gem 'bigdecimal'
705
+ gem 'logger'
706
+ gem 'benchmark'
707
+ gem 'mutex_m'
708
+
709
+ ```
710
+
711
+ ---
712
+
713
+ ## index.js
714
+
715
+ ```js
716
+ /**
717
+ * @format
718
+ */
719
+
720
+ import { AppRegistry } from 'react-native';
721
+ import App from './App';
722
+ import { name as appName } from './app.json';
723
+
724
+ AppRegistry.registerComponent(appName, () => App);
725
+
726
+ ```
727
+
728
+ ---
729
+
730
+ ## ios/.xcode.env
731
+
732
+ ```env
733
+ # This `.xcode.env` file is versioned and is used to source the environment
734
+ # used when running script phases inside Xcode.
735
+ # To customize your local environment, you can create an `.xcode.env.local`
736
+ # file that is not versioned.
737
+
738
+ # NODE_BINARY variable contains the PATH to the node executable.
739
+ #
740
+ # Customize the NODE_BINARY variable here.
741
+ # For example, to use nvm with brew, add the following line
742
+ # . "$(brew --prefix nvm)/nvm.sh" --no-use
743
+ export NODE_BINARY=$(command -v node)
744
+
745
+ ```
746
+
747
+ ---
748
+
749
+ ## ios/BurritoApp.xcodeproj/xcshareddata/xcschemes/BurritoApp.xcscheme
750
+
751
+ ```xcscheme
752
+ <?xml version="1.0" encoding="UTF-8"?>
753
+ <Scheme
754
+ LastUpgradeVersion = "1210"
755
+ version = "1.3">
756
+ <BuildAction
757
+ parallelizeBuildables = "YES"
758
+ buildImplicitDependencies = "YES">
759
+ <BuildActionEntries>
760
+ <BuildActionEntry
761
+ buildForTesting = "YES"
762
+ buildForRunning = "YES"
763
+ buildForProfiling = "YES"
764
+ buildForArchiving = "YES"
765
+ buildForAnalyzing = "YES">
766
+ <BuildableReference
767
+ BuildableIdentifier = "primary"
768
+ BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
769
+ BuildableName = "BurritoApp.app"
770
+ BlueprintName = "BurritoApp"
771
+ ReferencedContainer = "container:BurritoApp.xcodeproj">
772
+ </BuildableReference>
773
+ </BuildActionEntry>
774
+ </BuildActionEntries>
775
+ </BuildAction>
776
+ <TestAction
777
+ buildConfiguration = "Debug"
778
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
779
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
780
+ shouldUseLaunchSchemeArgsEnv = "YES">
781
+ <Testables>
782
+ <TestableReference
783
+ skipped = "NO">
784
+ <BuildableReference
785
+ BuildableIdentifier = "primary"
786
+ BlueprintIdentifier = "00E356ED1AD99517003FC87E"
787
+ BuildableName = "BurritoAppTests.xctest"
788
+ BlueprintName = "BurritoAppTests"
789
+ ReferencedContainer = "container:BurritoApp.xcodeproj">
790
+ </BuildableReference>
791
+ </TestableReference>
792
+ </Testables>
793
+ </TestAction>
794
+ <LaunchAction
795
+ buildConfiguration = "Debug"
796
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
797
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
798
+ launchStyle = "0"
799
+ useCustomWorkingDirectory = "NO"
800
+ ignoresPersistentStateOnLaunch = "NO"
801
+ debugDocumentVersioning = "YES"
802
+ debugServiceExtension = "internal"
803
+ allowLocationSimulation = "YES">
804
+ <BuildableProductRunnable
805
+ runnableDebuggingMode = "0">
806
+ <BuildableReference
807
+ BuildableIdentifier = "primary"
808
+ BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
809
+ BuildableName = "BurritoApp.app"
810
+ BlueprintName = "BurritoApp"
811
+ ReferencedContainer = "container:BurritoApp.xcodeproj">
812
+ </BuildableReference>
813
+ </BuildableProductRunnable>
814
+ </LaunchAction>
815
+ <ProfileAction
816
+ buildConfiguration = "Release"
817
+ shouldUseLaunchSchemeArgsEnv = "YES"
818
+ savedToolIdentifier = ""
819
+ useCustomWorkingDirectory = "NO"
820
+ debugDocumentVersioning = "YES">
821
+ <BuildableProductRunnable
822
+ runnableDebuggingMode = "0">
823
+ <BuildableReference
824
+ BuildableIdentifier = "primary"
825
+ BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
826
+ BuildableName = "BurritoApp.app"
827
+ BlueprintName = "BurritoApp"
828
+ ReferencedContainer = "container:BurritoApp.xcodeproj">
829
+ </BuildableReference>
830
+ </BuildableProductRunnable>
831
+ </ProfileAction>
832
+ <AnalyzeAction
833
+ buildConfiguration = "Debug">
834
+ </AnalyzeAction>
835
+ <ArchiveAction
836
+ buildConfiguration = "Release"
837
+ revealArchiveInOrganizer = "YES">
838
+ </ArchiveAction>
839
+ </Scheme>
840
+
841
+ ```
842
+
843
+ ---
844
+
845
+ ## ios/BurritoApp.xcworkspace/contents.xcworkspacedata
846
+
847
+ ```xcworkspacedata
848
+ <?xml version="1.0" encoding="UTF-8"?>
849
+ <Workspace
850
+ version = "1.0">
851
+ <FileRef
852
+ location = "group:BurritoApp.xcodeproj">
853
+ </FileRef>
854
+ <FileRef
855
+ location = "group:Pods/Pods.xcodeproj">
856
+ </FileRef>
857
+ </Workspace>
858
+
859
+ ```
860
+
861
+ ---
862
+
863
+ ## ios/BurritoApp/AppDelegate.swift
864
+
865
+ ```swift
866
+ import UIKit
867
+ import React
868
+ import React_RCTAppDelegate
869
+ import ReactAppDependencyProvider
870
+
871
+ @main
872
+ class AppDelegate: UIResponder, UIApplicationDelegate {
873
+ var window: UIWindow?
874
+
875
+ var reactNativeDelegate: ReactNativeDelegate?
876
+ var reactNativeFactory: RCTReactNativeFactory?
877
+
878
+ func application(
879
+ _ application: UIApplication,
880
+ didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
881
+ ) -> Bool {
882
+ let delegate = ReactNativeDelegate()
883
+ let factory = RCTReactNativeFactory(delegate: delegate)
884
+ delegate.dependencyProvider = RCTAppDependencyProvider()
885
+
886
+ reactNativeDelegate = delegate
887
+ reactNativeFactory = factory
888
+
889
+ window = UIWindow(frame: UIScreen.main.bounds)
890
+
891
+ factory.startReactNative(
892
+ withModuleName: "BurritoApp",
893
+ in: window,
894
+ launchOptions: launchOptions
895
+ )
896
+
897
+ return true
898
+ }
899
+ }
900
+
901
+ class ReactNativeDelegate: RCTDefaultReactNativeFactoryDelegate {
902
+ override func sourceURL(for bridge: RCTBridge) -> URL? {
903
+ self.bundleURL()
904
+ }
905
+
906
+ override func bundleURL() -> URL? {
907
+ #if DEBUG
908
+ RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index")
909
+ #else
910
+ Bundle.main.url(forResource: "main", withExtension: "jsbundle")
911
+ #endif
912
+ }
913
+ }
914
+
915
+ ```
916
+
917
+ ---
918
+
919
+ ## ios/BurritoApp/Info.plist
920
+
921
+ ```plist
922
+ <?xml version="1.0" encoding="UTF-8"?>
923
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
924
+ <plist version="1.0">
925
+ <dict>
926
+ <key>CADisableMinimumFrameDurationOnPhone</key>
927
+ <true/>
928
+ <key>CFBundleDevelopmentRegion</key>
929
+ <string>en</string>
930
+ <key>CFBundleDisplayName</key>
931
+ <string>BurritoApp</string>
932
+ <key>CFBundleExecutable</key>
933
+ <string>$(EXECUTABLE_NAME)</string>
934
+ <key>CFBundleIdentifier</key>
935
+ <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
936
+ <key>CFBundleInfoDictionaryVersion</key>
937
+ <string>6.0</string>
938
+ <key>CFBundleName</key>
939
+ <string>$(PRODUCT_NAME)</string>
940
+ <key>CFBundlePackageType</key>
941
+ <string>APPL</string>
942
+ <key>CFBundleShortVersionString</key>
943
+ <string>$(MARKETING_VERSION)</string>
944
+ <key>CFBundleSignature</key>
945
+ <string>????</string>
946
+ <key>CFBundleVersion</key>
947
+ <string>$(CURRENT_PROJECT_VERSION)</string>
948
+ <key>LSRequiresIPhoneOS</key>
949
+ <true/>
950
+ <key>NSAppTransportSecurity</key>
951
+ <dict>
952
+ <key>NSAllowsArbitraryLoads</key>
953
+ <false/>
954
+ <key>NSAllowsLocalNetworking</key>
955
+ <true/>
956
+ </dict>
957
+ <key>NSLocationWhenInUseUsageDescription</key>
958
+ <string></string>
959
+ <key>RCTNewArchEnabled</key>
960
+ <true/>
961
+ <key>UILaunchStoryboardName</key>
962
+ <string>LaunchScreen</string>
963
+ <key>UIRequiredDeviceCapabilities</key>
964
+ <array>
965
+ <string>arm64</string>
966
+ </array>
967
+ <key>UISupportedInterfaceOrientations</key>
968
+ <array>
969
+ <string>UIInterfaceOrientationPortrait</string>
970
+ <string>UIInterfaceOrientationLandscapeLeft</string>
971
+ <string>UIInterfaceOrientationLandscapeRight</string>
972
+ </array>
973
+ <key>UIViewControllerBasedStatusBarAppearance</key>
974
+ <false/>
975
+ </dict>
976
+ </plist>
977
+
978
+ ```
979
+
980
+ ---
981
+
982
+ ## ios/BurritoApp/LaunchScreen.storyboard
983
+
984
+ ```storyboard
985
+ <?xml version="1.0" encoding="UTF-8"?>
986
+ <document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="15702" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
987
+ <device id="retina4_7" orientation="portrait" appearance="light"/>
988
+ <dependencies>
989
+ <deployment identifier="iOS"/>
990
+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15704"/>
991
+ <capability name="Safe area layout guides" minToolsVersion="9.0"/>
992
+ <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
993
+ </dependencies>
994
+ <scenes>
995
+ <!--View Controller-->
996
+ <scene sceneID="EHf-IW-A2E">
997
+ <objects>
998
+ <viewController id="01J-lp-oVM" sceneMemberID="viewController">
999
+ <view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
1000
+ <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
1001
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
1002
+ <subviews>
1003
+ <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="BurritoApp" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="GJd-Yh-RWb">
1004
+ <rect key="frame" x="0.0" y="202" width="375" height="43"/>
1005
+ <fontDescription key="fontDescription" type="boldSystem" pointSize="36"/>
1006
+ <nil key="highlightedColor"/>
1007
+ </label>
1008
+ <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Powered by React Native" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="MN2-I3-ftu">
1009
+ <rect key="frame" x="0.0" y="626" width="375" height="21"/>
1010
+ <fontDescription key="fontDescription" type="system" pointSize="17"/>
1011
+ <nil key="highlightedColor"/>
1012
+ </label>
1013
+ </subviews>
1014
+ <color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
1015
+ <constraints>
1016
+ <constraint firstItem="Bcu-3y-fUS" firstAttribute="bottom" secondItem="MN2-I3-ftu" secondAttribute="bottom" constant="20" id="OZV-Vh-mqD"/>
1017
+ <constraint firstItem="Bcu-3y-fUS" firstAttribute="centerX" secondItem="GJd-Yh-RWb" secondAttribute="centerX" id="Q3B-4B-g5h"/>
1018
+ <constraint firstItem="MN2-I3-ftu" firstAttribute="centerX" secondItem="Bcu-3y-fUS" secondAttribute="centerX" id="akx-eg-2ui"/>
1019
+ <constraint firstItem="MN2-I3-ftu" firstAttribute="leading" secondItem="Bcu-3y-fUS" secondAttribute="leading" id="i1E-0Y-4RG"/>
1020
+ <constraint firstItem="GJd-Yh-RWb" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="bottom" multiplier="1/3" constant="1" id="moa-c2-u7t"/>
1021
+ <constraint firstItem="GJd-Yh-RWb" firstAttribute="leading" secondItem="Bcu-3y-fUS" secondAttribute="leading" symbolic="YES" id="x7j-FC-K8j"/>
1022
+ </constraints>
1023
+ <viewLayoutGuide key="safeArea" id="Bcu-3y-fUS"/>
1024
+ </view>
1025
+ </viewController>
1026
+ <placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
1027
+ </objects>
1028
+ <point key="canvasLocation" x="52.173913043478265" y="375"/>
1029
+ </scene>
1030
+ </scenes>
1031
+ </document>
1032
+
1033
+ ```
1034
+
1035
+ ---
1036
+
1037
+ ## ios/BurritoApp/PrivacyInfo.xcprivacy
1038
+
1039
+ ```xcprivacy
1040
+ <?xml version="1.0" encoding="UTF-8"?>
1041
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
1042
+ <plist version="1.0">
1043
+ <dict>
1044
+ <key>NSPrivacyAccessedAPITypes</key>
1045
+ <array>
1046
+ <dict>
1047
+ <key>NSPrivacyAccessedAPIType</key>
1048
+ <string>NSPrivacyAccessedAPICategoryFileTimestamp</string>
1049
+ <key>NSPrivacyAccessedAPITypeReasons</key>
1050
+ <array>
1051
+ <string>C617.1</string>
1052
+ </array>
1053
+ </dict>
1054
+ <dict>
1055
+ <key>NSPrivacyAccessedAPIType</key>
1056
+ <string>NSPrivacyAccessedAPICategorySystemBootTime</string>
1057
+ <key>NSPrivacyAccessedAPITypeReasons</key>
1058
+ <array>
1059
+ <string>35F9.1</string>
1060
+ </array>
1061
+ </dict>
1062
+ <dict>
1063
+ <key>NSPrivacyAccessedAPIType</key>
1064
+ <string>NSPrivacyAccessedAPICategoryUserDefaults</string>
1065
+ <key>NSPrivacyAccessedAPITypeReasons</key>
1066
+ <array>
1067
+ <string>CA92.1</string>
1068
+ </array>
1069
+ </dict>
1070
+ <dict>
1071
+ <key>NSPrivacyAccessedAPIType</key>
1072
+ <string>NSPrivacyAccessedAPICategoryDiskSpace</string>
1073
+ <key>NSPrivacyAccessedAPITypeReasons</key>
1074
+ <array>
1075
+ <string>85F4.1</string>
1076
+ </array>
1077
+ </dict>
1078
+ </array>
1079
+ <key>NSPrivacyCollectedDataTypes</key>
1080
+ <array/>
1081
+ <key>NSPrivacyTracking</key>
1082
+ <false/>
1083
+ </dict>
1084
+ </plist>
1085
+
1086
+ ```
1087
+
1088
+ ---
1089
+
1090
+ ## ios/Podfile
1091
+
1092
+ ```
1093
+ # Resolve react_native_pods.rb with node to allow for hoisting
1094
+ require Pod::Executable.execute_command('node', ['-p',
1095
+ 'require.resolve(
1096
+ "react-native/scripts/react_native_pods.rb",
1097
+ {paths: [process.argv[1]]},
1098
+ )', __dir__]).strip
1099
+
1100
+ platform :ios, min_ios_version_supported
1101
+ prepare_react_native_project!
1102
+
1103
+ linkage = ENV['USE_FRAMEWORKS']
1104
+ if linkage != nil
1105
+ Pod::UI.puts "Configuring Pod with #{linkage}ally linked Frameworks".green
1106
+ use_frameworks! :linkage => linkage.to_sym
1107
+ end
1108
+
1109
+ target 'BurritoApp' do
1110
+ config = use_native_modules!
1111
+
1112
+ use_react_native!(
1113
+ :path => config[:reactNativePath],
1114
+ # An absolute path to your application root.
1115
+ :app_path => "#{Pod::Config.instance.installation_root}/.."
1116
+ )
1117
+
1118
+ post_install do |installer|
1119
+ react_native_post_install(
1120
+ installer,
1121
+ config[:reactNativePath],
1122
+ :mac_catalyst_enabled => false,
1123
+ # :ccache_enabled => true
1124
+ )
1125
+ end
1126
+ end
1127
+
1128
+ ```
1129
+
1130
+ ---
1131
+
1132
+ ## jest.config.js
1133
+
1134
+ ```js
1135
+ module.exports = {
1136
+ preset: 'react-native',
1137
+ };
1138
+
1139
+ ```
1140
+
1141
+ ---
1142
+
1143
+ ## metro.config.js
1144
+
1145
+ ```js
1146
+ const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config');
1147
+
1148
+ /**
1149
+ * Metro configuration
1150
+ * https://reactnative.dev/docs/metro
1151
+ *
1152
+ * @type {import('@react-native/metro-config').MetroConfig}
1153
+ */
1154
+ const config = {};
1155
+
1156
+ module.exports = mergeConfig(getDefaultConfig(__dirname), config);
1157
+
1158
+ ```
1159
+
1160
+ ---
1161
+
1162
+ ## src/config/amplitude.ts
1163
+
1164
+ ```ts
1165
+ import * as amplitude from '@amplitude/analytics-react-native'
1166
+ import Config from 'react-native-config'
1167
+
1168
+ // Environment variables are embedded at build time via react-native-config
1169
+ // Ensure .env file exists with AMPLITUDE_API_KEY
1170
+ const apiKey = Config.AMPLITUDE_API_KEY
1171
+ const isAmplitudeConfigured = apiKey && apiKey !== 'your_amplitude_api_key_here'
1172
+
1173
+ if (!isAmplitudeConfigured) {
1174
+ console.warn(
1175
+ 'Amplitude API key not configured. Analytics will be disabled. ' +
1176
+ 'Set AMPLITUDE_API_KEY in your .env file to enable analytics.'
1177
+ )
1178
+ }
1179
+
1180
+ if (isAmplitudeConfigured && apiKey) {
1181
+ amplitude.init(apiKey)
1182
+ }
1183
+
1184
+ export { amplitude }
1185
+ export const isAmplitudeEnabled = isAmplitudeConfigured
1186
+
1187
+ ```
1188
+
1189
+ ---
1190
+
1191
+ ## src/contexts/AuthContext.tsx
1192
+
1193
+ ```tsx
1194
+ import React, {
1195
+ createContext,
1196
+ useContext,
1197
+ useState,
1198
+ useEffect,
1199
+ ReactNode,
1200
+ useCallback,
1201
+ } from 'react'
1202
+ import { Identify } from '@amplitude/analytics-react-native'
1203
+ import { amplitude } from '../config/amplitude'
1204
+ import { storage, User } from '../services/storage'
1205
+
1206
+ interface AuthContextType {
1207
+ user: User | null
1208
+ isLoading: boolean
1209
+ login: (username: string, password: string) => Promise<boolean>
1210
+ logout: () => Promise<void>
1211
+ incrementBurritoConsiderations: () => Promise<void>
1212
+ }
1213
+
1214
+ const AuthContext = createContext<AuthContextType | undefined>(undefined)
1215
+
1216
+ interface AuthProviderProps {
1217
+ children: ReactNode
1218
+ }
1219
+
1220
+ /**
1221
+ * Authentication Provider with Amplitude integration
1222
+ *
1223
+ * Manages user authentication state and integrates with Amplitude for:
1224
+ * - User identification (amplitude.setUserId + amplitude.identify)
1225
+ * - Login/logout event tracking
1226
+ * - Session reset on logout
1227
+ */
1228
+ export function AuthProvider({ children }: AuthProviderProps) {
1229
+ const [user, setUser] = useState<User | null>(null)
1230
+ const [isLoading, setIsLoading] = useState(true)
1231
+
1232
+ // Restore session on app launch
1233
+ useEffect(() => {
1234
+ restoreSession()
1235
+ }, [])
1236
+
1237
+ const restoreSession = async () => {
1238
+ try {
1239
+ const storedUsername = await storage.getCurrentUser()
1240
+ if (storedUsername) {
1241
+ const existingUser = await storage.getUser(storedUsername)
1242
+ if (existingUser) {
1243
+ setUser(existingUser)
1244
+
1245
+ // Re-identify user in Amplitude on session restore
1246
+ amplitude.setUserId(storedUsername)
1247
+ const identifyObj = new Identify()
1248
+ identifyObj.set('username', storedUsername)
1249
+ amplitude.identify(identifyObj)
1250
+ }
1251
+ }
1252
+ } catch (error) {
1253
+ console.error('Failed to restore session:', error)
1254
+ } finally {
1255
+ setIsLoading(false)
1256
+ }
1257
+ }
1258
+
1259
+ const login = useCallback(
1260
+ async (username: string, password: string): Promise<boolean> => {
1261
+ // Simple validation (demo app accepts any username/password)
1262
+ if (!username.trim() || !password.trim()) {
1263
+ return false
1264
+ }
1265
+
1266
+ try {
1267
+ // Check if user exists or create new
1268
+ const existingUser = await storage.getUser(username)
1269
+ const isNewUser = !existingUser
1270
+
1271
+ const userData: User = existingUser || {
1272
+ username,
1273
+ burritoConsiderations: 0,
1274
+ }
1275
+
1276
+ // Save user data
1277
+ await storage.saveUser(userData)
1278
+ await storage.setCurrentUser(username)
1279
+ setUser(userData)
1280
+
1281
+ // Identify user in Amplitude using username as user ID
1282
+ amplitude.setUserId(username)
1283
+ const identifyObj = new Identify()
1284
+ identifyObj.set('username', username)
1285
+ amplitude.identify(identifyObj)
1286
+
1287
+ // Track login event with properties
1288
+ amplitude.track('User Logged In', {
1289
+ username,
1290
+ is_new_user: isNewUser,
1291
+ })
1292
+
1293
+ return true
1294
+ } catch (error) {
1295
+ console.error('Login error:', error)
1296
+ return false
1297
+ }
1298
+ },
1299
+ [],
1300
+ )
1301
+
1302
+ const logout = useCallback(async () => {
1303
+ // Track logout event before reset
1304
+ amplitude.track('User Logged Out')
1305
+
1306
+ // Reset Amplitude - clears the current user's identity
1307
+ amplitude.reset()
1308
+
1309
+ await storage.removeCurrentUser()
1310
+ setUser(null)
1311
+ }, [])
1312
+
1313
+ const incrementBurritoConsiderations = useCallback(async () => {
1314
+ if (user) {
1315
+ const updatedUser: User = {
1316
+ ...user,
1317
+ burritoConsiderations: user.burritoConsiderations + 1,
1318
+ }
1319
+ setUser(updatedUser)
1320
+ await storage.saveUser(updatedUser)
1321
+ }
1322
+ }, [user])
1323
+
1324
+ return (
1325
+ <AuthContext.Provider
1326
+ value={{
1327
+ user,
1328
+ isLoading,
1329
+ login,
1330
+ logout,
1331
+ incrementBurritoConsiderations,
1332
+ }}
1333
+ >
1334
+ {children}
1335
+ </AuthContext.Provider>
1336
+ )
1337
+ }
1338
+
1339
+ export function useAuth() {
1340
+ const context = useContext(AuthContext)
1341
+ if (context === undefined) {
1342
+ throw new Error('useAuth must be used within an AuthProvider')
1343
+ }
1344
+ return context
1345
+ }
1346
+
1347
+ ```
1348
+
1349
+ ---
1350
+
1351
+ ## src/navigation/RootNavigator.tsx
1352
+
1353
+ ```tsx
1354
+ import React from 'react'
1355
+ import { ActivityIndicator, View, StyleSheet } from 'react-native'
1356
+ import { createNativeStackNavigator } from '@react-navigation/native-stack'
1357
+ import { useAuth } from '../contexts/AuthContext'
1358
+ import { colors } from '../styles/theme'
1359
+
1360
+ import HomeScreen from '../screens/HomeScreen'
1361
+ import BurritoScreen from '../screens/BurritoScreen'
1362
+ import ProfileScreen from '../screens/ProfileScreen'
1363
+
1364
+ // Type definitions for navigation
1365
+ export type RootStackParamList = {
1366
+ Home: undefined
1367
+ Burrito: undefined
1368
+ Profile: undefined
1369
+ }
1370
+
1371
+ const Stack = createNativeStackNavigator<RootStackParamList>()
1372
+
1373
+ export function RootNavigator() {
1374
+ const { isLoading } = useAuth()
1375
+
1376
+ // Show loading indicator while restoring session
1377
+ if (isLoading) {
1378
+ return (
1379
+ <View style={styles.loadingContainer}>
1380
+ <ActivityIndicator size="large" color={colors.primary} />
1381
+ </View>
1382
+ )
1383
+ }
1384
+
1385
+ return (
1386
+ <Stack.Navigator
1387
+ screenOptions={{
1388
+ headerStyle: {
1389
+ backgroundColor: colors.headerBackground,
1390
+ },
1391
+ headerTintColor: colors.headerText,
1392
+ headerTitleStyle: {
1393
+ fontWeight: 'bold',
1394
+ },
1395
+ headerBackTitleVisible: false,
1396
+ animation: 'slide_from_right',
1397
+ }}
1398
+ >
1399
+ <Stack.Screen
1400
+ name="Home"
1401
+ component={HomeScreen}
1402
+ options={{
1403
+ title: 'Burrito App',
1404
+ }}
1405
+ />
1406
+ <Stack.Screen
1407
+ name="Burrito"
1408
+ component={BurritoScreen}
1409
+ options={{
1410
+ title: 'Burrito Consideration',
1411
+ }}
1412
+ />
1413
+ <Stack.Screen
1414
+ name="Profile"
1415
+ component={ProfileScreen}
1416
+ options={{
1417
+ title: 'Profile',
1418
+ }}
1419
+ />
1420
+ </Stack.Navigator>
1421
+ )
1422
+ }
1423
+
1424
+ const styles = StyleSheet.create({
1425
+ loadingContainer: {
1426
+ flex: 1,
1427
+ justifyContent: 'center',
1428
+ alignItems: 'center',
1429
+ backgroundColor: colors.background,
1430
+ },
1431
+ })
1432
+
1433
+ ```
1434
+
1435
+ ---
1436
+
1437
+ ## src/screens/BurritoScreen.tsx
1438
+
1439
+ ```tsx
1440
+ import React, { useState, useEffect } from 'react'
1441
+ import { View, Text, TouchableOpacity, StyleSheet } from 'react-native'
1442
+ import { useNavigation } from '@react-navigation/native'
1443
+ import { NativeStackNavigationProp } from '@react-navigation/native-stack'
1444
+ import { amplitude } from '../config/amplitude'
1445
+ import { useAuth } from '../contexts/AuthContext'
1446
+ import { RootStackParamList } from '../navigation/RootNavigator'
1447
+ import {
1448
+ colors,
1449
+ spacing,
1450
+ typography,
1451
+ borderRadius,
1452
+ shadows,
1453
+ } from '../styles/theme'
1454
+
1455
+ type BurritoScreenNavigationProp = NativeStackNavigationProp<
1456
+ RootStackParamList,
1457
+ 'Burrito'
1458
+ >
1459
+
1460
+ /**
1461
+ * Burrito Consideration Screen
1462
+ *
1463
+ * Demonstrates Amplitude event tracking with custom properties.
1464
+ * Each time the user considers a burrito, an event is tracked.
1465
+ */
1466
+ export default function BurritoScreen() {
1467
+ const { user, incrementBurritoConsiderations } = useAuth()
1468
+ const navigation = useNavigation<BurritoScreenNavigationProp>()
1469
+ const [hasConsidered, setHasConsidered] = useState(false)
1470
+
1471
+ // Redirect to home if not logged in
1472
+ useEffect(() => {
1473
+ if (!user) {
1474
+ navigation.navigate('Home')
1475
+ }
1476
+ }, [user, navigation])
1477
+
1478
+ if (!user) {
1479
+ return null
1480
+ }
1481
+
1482
+ const handleConsideration = async () => {
1483
+ const newCount = user.burritoConsiderations + 1
1484
+
1485
+ // Update state first for immediate feedback
1486
+ await incrementBurritoConsiderations()
1487
+ setHasConsidered(true)
1488
+
1489
+ // Hide success message after 2 seconds
1490
+ setTimeout(() => setHasConsidered(false), 2000)
1491
+
1492
+ // Track custom event in Amplitude with properties
1493
+ amplitude.track('Burrito Considered', {
1494
+ total_considerations: newCount,
1495
+ username: user.username,
1496
+ })
1497
+ }
1498
+
1499
+ return (
1500
+ <View style={styles.container}>
1501
+ <View style={styles.card}>
1502
+ <Text style={styles.title}>Burrito Consideration Zone</Text>
1503
+ <Text style={styles.text}>
1504
+ Take a moment to truly consider the potential of burritos.
1505
+ </Text>
1506
+
1507
+ <TouchableOpacity
1508
+ style={styles.burritoButton}
1509
+ onPress={handleConsideration}
1510
+ activeOpacity={0.8}
1511
+ testID="consider-burrito-button"
1512
+ >
1513
+ <Text style={styles.burritoButtonText}>Consider Burrito</Text>
1514
+ </TouchableOpacity>
1515
+
1516
+ {hasConsidered && (
1517
+ <View style={styles.successContainer}>
1518
+ <Text style={styles.success}>
1519
+ Thank you for your consideration!
1520
+ </Text>
1521
+ <Text style={styles.successCount}>
1522
+ Count: {user.burritoConsiderations}
1523
+ </Text>
1524
+ </View>
1525
+ )}
1526
+
1527
+ <View style={styles.stats}>
1528
+ <Text style={styles.statsTitle}>Consideration Stats</Text>
1529
+ <Text style={styles.statsText}>
1530
+ Total considerations: {user.burritoConsiderations}
1531
+ </Text>
1532
+ </View>
1533
+ </View>
1534
+ </View>
1535
+ )
1536
+ }
1537
+
1538
+ const styles = StyleSheet.create({
1539
+ container: {
1540
+ flex: 1,
1541
+ backgroundColor: colors.background,
1542
+ padding: spacing.md,
1543
+ },
1544
+ card: {
1545
+ backgroundColor: colors.cardBackground,
1546
+ borderRadius: borderRadius.md,
1547
+ padding: spacing.lg,
1548
+ ...shadows.md,
1549
+ },
1550
+ title: {
1551
+ fontSize: typography.sizes.xl,
1552
+ fontWeight: typography.weights.bold,
1553
+ color: colors.text,
1554
+ marginBottom: spacing.sm,
1555
+ },
1556
+ text: {
1557
+ fontSize: typography.sizes.md,
1558
+ color: colors.text,
1559
+ marginBottom: spacing.lg,
1560
+ lineHeight: 24,
1561
+ },
1562
+ burritoButton: {
1563
+ backgroundColor: colors.burrito,
1564
+ borderRadius: borderRadius.sm,
1565
+ padding: spacing.lg,
1566
+ alignItems: 'center',
1567
+ marginVertical: spacing.md,
1568
+ ...shadows.sm,
1569
+ },
1570
+ burritoButtonText: {
1571
+ color: colors.white,
1572
+ fontSize: typography.sizes.lg,
1573
+ fontWeight: typography.weights.bold,
1574
+ },
1575
+ successContainer: {
1576
+ alignItems: 'center',
1577
+ marginVertical: spacing.sm,
1578
+ },
1579
+ success: {
1580
+ color: colors.success,
1581
+ fontSize: typography.sizes.md,
1582
+ fontWeight: typography.weights.medium,
1583
+ },
1584
+ successCount: {
1585
+ color: colors.success,
1586
+ fontSize: typography.sizes.lg,
1587
+ fontWeight: typography.weights.bold,
1588
+ marginTop: spacing.xs,
1589
+ },
1590
+ stats: {
1591
+ backgroundColor: colors.statsBackground,
1592
+ padding: spacing.md,
1593
+ borderRadius: borderRadius.sm,
1594
+ marginTop: spacing.lg,
1595
+ },
1596
+ statsTitle: {
1597
+ fontSize: typography.sizes.lg,
1598
+ fontWeight: typography.weights.semibold,
1599
+ color: colors.text,
1600
+ marginBottom: spacing.xs,
1601
+ },
1602
+ statsText: {
1603
+ fontSize: typography.sizes.md,
1604
+ color: colors.text,
1605
+ },
1606
+ })
1607
+
1608
+ ```
1609
+
1610
+ ---
1611
+
1612
+ ## src/screens/HomeScreen.tsx
1613
+
1614
+ ```tsx
1615
+ import React, { useState } from 'react'
1616
+ import {
1617
+ View,
1618
+ Text,
1619
+ TextInput,
1620
+ TouchableOpacity,
1621
+ StyleSheet,
1622
+ ScrollView,
1623
+ KeyboardAvoidingView,
1624
+ Platform,
1625
+ } from 'react-native'
1626
+ import { useNavigation } from '@react-navigation/native'
1627
+ import { NativeStackNavigationProp } from '@react-navigation/native-stack'
1628
+ import { useAuth } from '../contexts/AuthContext'
1629
+ import { RootStackParamList } from '../navigation/RootNavigator'
1630
+ import {
1631
+ colors,
1632
+ spacing,
1633
+ typography,
1634
+ borderRadius,
1635
+ shadows,
1636
+ } from '../styles/theme'
1637
+
1638
+ type HomeScreenNavigationProp = NativeStackNavigationProp<
1639
+ RootStackParamList,
1640
+ 'Home'
1641
+ >
1642
+
1643
+ export default function HomeScreen() {
1644
+ const { user, login, logout } = useAuth()
1645
+ const navigation = useNavigation<HomeScreenNavigationProp>()
1646
+ const [username, setUsername] = useState('')
1647
+ const [password, setPassword] = useState('')
1648
+ const [error, setError] = useState('')
1649
+ const [isSubmitting, setIsSubmitting] = useState(false)
1650
+
1651
+ const handleSubmit = async () => {
1652
+ setError('')
1653
+
1654
+ if (!username.trim() || !password.trim()) {
1655
+ setError('Please provide both username and password')
1656
+ return
1657
+ }
1658
+
1659
+ setIsSubmitting(true)
1660
+ try {
1661
+ const success = await login(username, password)
1662
+ if (success) {
1663
+ setUsername('')
1664
+ setPassword('')
1665
+ } else {
1666
+ setError('An error occurred during login')
1667
+ }
1668
+ } catch {
1669
+ setError('An error occurred during login')
1670
+ } finally {
1671
+ setIsSubmitting(false)
1672
+ }
1673
+ }
1674
+
1675
+ // Logged in view
1676
+ if (user) {
1677
+ return (
1678
+ <ScrollView
1679
+ style={styles.scrollView}
1680
+ contentContainerStyle={styles.scrollContent}
1681
+ >
1682
+ <View style={styles.card}>
1683
+ <Text style={styles.title}>Welcome back, {user.username}!</Text>
1684
+ <Text style={styles.text}>
1685
+ You are now logged in. Feel free to explore:
1686
+ </Text>
1687
+
1688
+ <View style={styles.buttonGroup}>
1689
+ <TouchableOpacity
1690
+ style={[styles.button, styles.burritoButton]}
1691
+ onPress={() => navigation.navigate('Burrito')}
1692
+ activeOpacity={0.8}
1693
+ >
1694
+ <Text style={styles.buttonText}>Consider Burritos</Text>
1695
+ </TouchableOpacity>
1696
+
1697
+ <TouchableOpacity
1698
+ style={[styles.button, styles.primaryButton]}
1699
+ onPress={() => navigation.navigate('Profile')}
1700
+ activeOpacity={0.8}
1701
+ >
1702
+ <Text style={styles.buttonText}>View Profile</Text>
1703
+ </TouchableOpacity>
1704
+
1705
+ <TouchableOpacity
1706
+ style={[styles.button, styles.logoutButton]}
1707
+ onPress={logout}
1708
+ activeOpacity={0.8}
1709
+ >
1710
+ <Text style={styles.buttonText}>Logout</Text>
1711
+ </TouchableOpacity>
1712
+ </View>
1713
+ </View>
1714
+ </ScrollView>
1715
+ )
1716
+ }
1717
+
1718
+ // Login view
1719
+ return (
1720
+ <KeyboardAvoidingView
1721
+ style={styles.container}
1722
+ behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
1723
+ >
1724
+ <ScrollView
1725
+ style={styles.scrollView}
1726
+ contentContainerStyle={styles.scrollContent}
1727
+ keyboardShouldPersistTaps="handled"
1728
+ >
1729
+ <View style={styles.card}>
1730
+ <Text style={styles.title}>Welcome to Burrito Consideration App</Text>
1731
+ <Text style={styles.text}>
1732
+ Please sign in to begin your burrito journey
1733
+ </Text>
1734
+
1735
+ <View style={styles.form}>
1736
+ <Text style={styles.label}>Username:</Text>
1737
+ <TextInput
1738
+ style={styles.input}
1739
+ value={username}
1740
+ onChangeText={setUsername}
1741
+ placeholder="Enter any username"
1742
+ placeholderTextColor={colors.textLight}
1743
+ autoCapitalize="none"
1744
+ autoCorrect={false}
1745
+ autoComplete="username"
1746
+ editable={!isSubmitting}
1747
+ />
1748
+
1749
+ <Text style={styles.label}>Password:</Text>
1750
+ <TextInput
1751
+ style={styles.input}
1752
+ value={password}
1753
+ onChangeText={setPassword}
1754
+ placeholder="Enter any password"
1755
+ placeholderTextColor={colors.textLight}
1756
+ secureTextEntry
1757
+ autoComplete="password"
1758
+ editable={!isSubmitting}
1759
+ />
1760
+
1761
+ {error ? <Text style={styles.error}>{error}</Text> : null}
1762
+
1763
+ <TouchableOpacity
1764
+ style={[
1765
+ styles.button,
1766
+ styles.primaryButton,
1767
+ isSubmitting && styles.buttonDisabled,
1768
+ ]}
1769
+ onPress={handleSubmit}
1770
+ disabled={isSubmitting}
1771
+ activeOpacity={0.8}
1772
+ >
1773
+ <Text style={styles.buttonText}>
1774
+ {isSubmitting ? 'Signing In...' : 'Sign In'}
1775
+ </Text>
1776
+ </TouchableOpacity>
1777
+ </View>
1778
+
1779
+ <Text style={styles.note}>
1780
+ Note: This is a demo app. Use any username and password to sign in.
1781
+ </Text>
1782
+ </View>
1783
+ </ScrollView>
1784
+ </KeyboardAvoidingView>
1785
+ )
1786
+ }
1787
+
1788
+ const styles = StyleSheet.create({
1789
+ container: {
1790
+ flex: 1,
1791
+ backgroundColor: colors.background,
1792
+ },
1793
+ scrollView: {
1794
+ flex: 1,
1795
+ backgroundColor: colors.background,
1796
+ },
1797
+ scrollContent: {
1798
+ flexGrow: 1,
1799
+ padding: spacing.md,
1800
+ justifyContent: 'center',
1801
+ },
1802
+ card: {
1803
+ backgroundColor: colors.cardBackground,
1804
+ borderRadius: borderRadius.md,
1805
+ padding: spacing.lg,
1806
+ ...shadows.md,
1807
+ },
1808
+ title: {
1809
+ fontSize: typography.sizes.xl,
1810
+ fontWeight: typography.weights.bold,
1811
+ color: colors.text,
1812
+ marginBottom: spacing.sm,
1813
+ },
1814
+ text: {
1815
+ fontSize: typography.sizes.md,
1816
+ color: colors.text,
1817
+ marginBottom: spacing.md,
1818
+ lineHeight: 24,
1819
+ },
1820
+ form: {
1821
+ marginTop: spacing.md,
1822
+ },
1823
+ label: {
1824
+ fontSize: typography.sizes.md,
1825
+ fontWeight: typography.weights.medium,
1826
+ color: colors.text,
1827
+ marginBottom: spacing.xs,
1828
+ },
1829
+ input: {
1830
+ backgroundColor: colors.inputBackground,
1831
+ borderWidth: 1,
1832
+ borderColor: colors.border,
1833
+ borderRadius: borderRadius.sm,
1834
+ padding: spacing.sm,
1835
+ fontSize: typography.sizes.md,
1836
+ color: colors.text,
1837
+ marginBottom: spacing.md,
1838
+ },
1839
+ buttonGroup: {
1840
+ marginTop: spacing.md,
1841
+ gap: spacing.sm,
1842
+ },
1843
+ button: {
1844
+ borderRadius: borderRadius.sm,
1845
+ padding: spacing.md,
1846
+ alignItems: 'center',
1847
+ marginTop: spacing.sm,
1848
+ },
1849
+ primaryButton: {
1850
+ backgroundColor: colors.primary,
1851
+ },
1852
+ burritoButton: {
1853
+ backgroundColor: colors.burrito,
1854
+ },
1855
+ logoutButton: {
1856
+ backgroundColor: colors.danger,
1857
+ },
1858
+ buttonDisabled: {
1859
+ opacity: 0.6,
1860
+ },
1861
+ buttonText: {
1862
+ color: colors.white,
1863
+ fontSize: typography.sizes.md,
1864
+ fontWeight: typography.weights.semibold,
1865
+ },
1866
+ error: {
1867
+ color: colors.danger,
1868
+ marginBottom: spacing.sm,
1869
+ fontSize: typography.sizes.sm,
1870
+ },
1871
+ note: {
1872
+ marginTop: spacing.lg,
1873
+ color: colors.textSecondary,
1874
+ fontSize: typography.sizes.sm,
1875
+ textAlign: 'center',
1876
+ lineHeight: 20,
1877
+ },
1878
+ })
1879
+
1880
+ ```
1881
+
1882
+ ---
1883
+
1884
+ ## src/screens/ProfileScreen.tsx
1885
+
1886
+ ```tsx
1887
+ import React, { useEffect } from 'react'
1888
+ import { View, Text, StyleSheet } from 'react-native'
1889
+ import { useNavigation } from '@react-navigation/native'
1890
+ import { NativeStackNavigationProp } from '@react-navigation/native-stack'
1891
+ import { useAuth } from '../contexts/AuthContext'
1892
+ import { RootStackParamList } from '../navigation/RootNavigator'
1893
+ import {
1894
+ colors,
1895
+ spacing,
1896
+ typography,
1897
+ borderRadius,
1898
+ shadows,
1899
+ } from '../styles/theme'
1900
+
1901
+ type ProfileScreenNavigationProp = NativeStackNavigationProp<
1902
+ RootStackParamList,
1903
+ 'Profile'
1904
+ >
1905
+
1906
+ /**
1907
+ * Profile Screen
1908
+ *
1909
+ * Displays user information and burrito journey stats.
1910
+ */
1911
+ export default function ProfileScreen() {
1912
+ const { user } = useAuth()
1913
+ const navigation = useNavigation<ProfileScreenNavigationProp>()
1914
+
1915
+ // Redirect to home if not logged in
1916
+ useEffect(() => {
1917
+ if (!user) {
1918
+ navigation.navigate('Home')
1919
+ }
1920
+ }, [user, navigation])
1921
+
1922
+ if (!user) {
1923
+ return null
1924
+ }
1925
+
1926
+ const getJourneyMessage = () => {
1927
+ const count = user.burritoConsiderations
1928
+ if (count === 0) {
1929
+ return "You haven't considered any burritos yet. Visit the Burrito Consideration page to start!"
1930
+ } else if (count === 1) {
1931
+ return "You've considered the burrito potential once. Keep going!"
1932
+ } else if (count < 5) {
1933
+ return "You're getting the hang of burrito consideration!"
1934
+ } else if (count < 10) {
1935
+ return "You're becoming a burrito consideration expert!"
1936
+ } else {
1937
+ return 'You are a true burrito consideration master!'
1938
+ }
1939
+ }
1940
+
1941
+ return (
1942
+ <View style={styles.container}>
1943
+ <View style={styles.card}>
1944
+ <Text style={styles.title}>User Profile</Text>
1945
+
1946
+ <View style={styles.stats}>
1947
+ <Text style={styles.statsTitle}>Your Information</Text>
1948
+ <View style={styles.infoRow}>
1949
+ <Text style={styles.infoLabel}>Username:</Text>
1950
+ <Text style={styles.infoValue}>{user.username}</Text>
1951
+ </View>
1952
+ <View style={styles.infoRow}>
1953
+ <Text style={styles.infoLabel}>Burrito Considerations:</Text>
1954
+ <Text style={styles.infoValue}>{user.burritoConsiderations}</Text>
1955
+ </View>
1956
+ </View>
1957
+
1958
+ <View style={styles.journey}>
1959
+ <Text style={styles.journeyTitle}>Your Burrito Journey</Text>
1960
+ <Text style={styles.journeyText}>{getJourneyMessage()}</Text>
1961
+ </View>
1962
+ </View>
1963
+ </View>
1964
+ )
1965
+ }
1966
+
1967
+ const styles = StyleSheet.create({
1968
+ container: {
1969
+ flex: 1,
1970
+ backgroundColor: colors.background,
1971
+ padding: spacing.md,
1972
+ },
1973
+ card: {
1974
+ backgroundColor: colors.cardBackground,
1975
+ borderRadius: borderRadius.md,
1976
+ padding: spacing.lg,
1977
+ ...shadows.md,
1978
+ },
1979
+ title: {
1980
+ fontSize: typography.sizes.xl,
1981
+ fontWeight: typography.weights.bold,
1982
+ color: colors.text,
1983
+ marginBottom: spacing.md,
1984
+ },
1985
+ stats: {
1986
+ backgroundColor: colors.statsBackground,
1987
+ padding: spacing.md,
1988
+ borderRadius: borderRadius.sm,
1989
+ },
1990
+ statsTitle: {
1991
+ fontSize: typography.sizes.lg,
1992
+ fontWeight: typography.weights.semibold,
1993
+ color: colors.text,
1994
+ marginBottom: spacing.sm,
1995
+ },
1996
+ infoRow: {
1997
+ flexDirection: 'row',
1998
+ marginBottom: spacing.xs,
1999
+ },
2000
+ infoLabel: {
2001
+ fontSize: typography.sizes.md,
2002
+ fontWeight: typography.weights.bold,
2003
+ color: colors.text,
2004
+ marginRight: spacing.xs,
2005
+ },
2006
+ infoValue: {
2007
+ fontSize: typography.sizes.md,
2008
+ color: colors.text,
2009
+ },
2010
+ journey: {
2011
+ marginTop: spacing.lg,
2012
+ },
2013
+ journeyTitle: {
2014
+ fontSize: typography.sizes.lg,
2015
+ fontWeight: typography.weights.semibold,
2016
+ color: colors.text,
2017
+ marginBottom: spacing.sm,
2018
+ },
2019
+ journeyText: {
2020
+ fontSize: typography.sizes.md,
2021
+ color: colors.text,
2022
+ lineHeight: 24,
2023
+ },
2024
+ })
2025
+
2026
+ ```
2027
+
2028
+ ---
2029
+
2030
+ ## src/services/storage.ts
2031
+
2032
+ ```ts
2033
+ import AsyncStorage from '@react-native-async-storage/async-storage'
2034
+
2035
+ const CURRENT_USER_KEY = 'currentUser'
2036
+ const USERS_KEY = 'users'
2037
+
2038
+ export interface User {
2039
+ username: string
2040
+ burritoConsiderations: number
2041
+ }
2042
+
2043
+ /**
2044
+ * Storage service for persisting user data
2045
+ * Uses AsyncStorage (React Native's async key-value storage)
2046
+ */
2047
+ export const storage = {
2048
+ /**
2049
+ * Get the currently logged in user's username
2050
+ */
2051
+ getCurrentUser: async (): Promise<string | null> => {
2052
+ try {
2053
+ return await AsyncStorage.getItem(CURRENT_USER_KEY)
2054
+ } catch (error) {
2055
+ console.error('Error getting current user:', error)
2056
+ return null
2057
+ }
2058
+ },
2059
+
2060
+ /**
2061
+ * Set the currently logged in user's username
2062
+ */
2063
+ setCurrentUser: async (username: string): Promise<void> => {
2064
+ try {
2065
+ await AsyncStorage.setItem(CURRENT_USER_KEY, username)
2066
+ } catch (error) {
2067
+ console.error('Error setting current user:', error)
2068
+ }
2069
+ },
2070
+
2071
+ /**
2072
+ * Remove the current user (logout)
2073
+ */
2074
+ removeCurrentUser: async (): Promise<void> => {
2075
+ try {
2076
+ await AsyncStorage.removeItem(CURRENT_USER_KEY)
2077
+ } catch (error) {
2078
+ console.error('Error removing current user:', error)
2079
+ }
2080
+ },
2081
+
2082
+ /**
2083
+ * Get all stored users
2084
+ */
2085
+ getUsers: async (): Promise<Record<string, User>> => {
2086
+ try {
2087
+ const data = await AsyncStorage.getItem(USERS_KEY)
2088
+ return data ? JSON.parse(data) : {}
2089
+ } catch (error) {
2090
+ console.error('Error getting users:', error)
2091
+ return {}
2092
+ }
2093
+ },
2094
+
2095
+ /**
2096
+ * Get a specific user by username
2097
+ */
2098
+ getUser: async (username: string): Promise<User | null> => {
2099
+ try {
2100
+ const users = await storage.getUsers()
2101
+ return users[username] || null
2102
+ } catch (error) {
2103
+ console.error('Error getting user:', error)
2104
+ return null
2105
+ }
2106
+ },
2107
+
2108
+ /**
2109
+ * Save a user to storage
2110
+ */
2111
+ saveUser: async (user: User): Promise<void> => {
2112
+ try {
2113
+ const users = await storage.getUsers()
2114
+ users[user.username] = user
2115
+ await AsyncStorage.setItem(USERS_KEY, JSON.stringify(users))
2116
+ } catch (error) {
2117
+ console.error('Error saving user:', error)
2118
+ }
2119
+ },
2120
+
2121
+ /**
2122
+ * Clear all stored data (for testing/debugging)
2123
+ */
2124
+ clearAll: async (): Promise<void> => {
2125
+ try {
2126
+ await AsyncStorage.multiRemove([CURRENT_USER_KEY, USERS_KEY])
2127
+ } catch (error) {
2128
+ console.error('Error clearing storage:', error)
2129
+ }
2130
+ },
2131
+ }
2132
+
2133
+ ```
2134
+
2135
+ ---
2136
+
2137
+ ## src/styles/theme.ts
2138
+
2139
+ ```ts
2140
+ /**
2141
+ * Theme constants for consistent styling across the app
2142
+ * Matches the color scheme from the TanStack Start web version
2143
+ */
2144
+
2145
+ export const colors = {
2146
+ // Primary colors
2147
+ primary: '#0070f3',
2148
+ primaryDark: '#0051cc',
2149
+
2150
+ // Status colors
2151
+ success: '#28a745',
2152
+ successDark: '#218838',
2153
+ danger: '#dc3545',
2154
+ dangerDark: '#c82333',
2155
+
2156
+ // Feature colors
2157
+ burrito: '#e07c24',
2158
+ burritoDark: '#c96a1a',
2159
+
2160
+ // Neutral colors
2161
+ background: '#f5f5f5',
2162
+ white: '#ffffff',
2163
+ text: '#333333',
2164
+ textSecondary: '#666666',
2165
+ textLight: '#999999',
2166
+ border: '#dddddd',
2167
+ borderLight: '#eeeeee',
2168
+
2169
+ // Component-specific
2170
+ statsBackground: '#f8f9fa',
2171
+ headerBackground: '#333333',
2172
+ headerText: '#ffffff',
2173
+ inputBackground: '#ffffff',
2174
+ cardBackground: '#ffffff',
2175
+ }
2176
+
2177
+ export const spacing = {
2178
+ xs: 4,
2179
+ sm: 8,
2180
+ md: 16,
2181
+ lg: 24,
2182
+ xl: 32,
2183
+ xxl: 48,
2184
+ }
2185
+
2186
+ export const typography = {
2187
+ sizes: {
2188
+ xs: 12,
2189
+ sm: 14,
2190
+ md: 16,
2191
+ lg: 18,
2192
+ xl: 24,
2193
+ xxl: 32,
2194
+ },
2195
+ weights: {
2196
+ normal: '400' as const,
2197
+ medium: '500' as const,
2198
+ semibold: '600' as const,
2199
+ bold: '700' as const,
2200
+ },
2201
+ }
2202
+
2203
+ export const borderRadius = {
2204
+ sm: 4,
2205
+ md: 8,
2206
+ lg: 12,
2207
+ full: 9999,
2208
+ }
2209
+
2210
+ export const shadows = {
2211
+ sm: {
2212
+ shadowColor: '#000',
2213
+ shadowOffset: { width: 0, height: 1 },
2214
+ shadowOpacity: 0.05,
2215
+ shadowRadius: 2,
2216
+ elevation: 1,
2217
+ },
2218
+ md: {
2219
+ shadowColor: '#000',
2220
+ shadowOffset: { width: 0, height: 2 },
2221
+ shadowOpacity: 0.1,
2222
+ shadowRadius: 4,
2223
+ elevation: 3,
2224
+ },
2225
+ lg: {
2226
+ shadowColor: '#000',
2227
+ shadowOffset: { width: 0, height: 4 },
2228
+ shadowOpacity: 0.15,
2229
+ shadowRadius: 8,
2230
+ elevation: 5,
2231
+ },
2232
+ }
2233
+
2234
+ ```
2235
+
2236
+ ---
2237
+
2238
+ ## src/types/env.d.ts
2239
+
2240
+ ```ts
2241
+ declare module 'react-native-config' {
2242
+ export interface NativeConfig {
2243
+ AMPLITUDE_API_KEY?: string
2244
+ }
2245
+
2246
+ export const Config: NativeConfig
2247
+ export default Config
2248
+ }
2249
+
2250
+ ```
2251
+
2252
+ ---
2253
+