@salesforce/templates 66.1.1 → 66.2.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 (238) hide show
  1. package/lib/generators/projectGenerator.d.ts +6 -0
  2. package/lib/generators/projectGenerator.js +43 -4
  3. package/lib/generators/projectGenerator.js.map +1 -1
  4. package/lib/templates/project/react-b2e/.a4drules/README.md +35 -0
  5. package/lib/templates/project/react-b2e/.a4drules/a4d-webapp-generate.md +27 -0
  6. package/lib/templates/project/react-b2e/.a4drules/build-validation.md +78 -0
  7. package/lib/templates/project/react-b2e/.a4drules/code-quality.md +137 -0
  8. package/lib/templates/project/react-b2e/.a4drules/graphql/tools/knowledge/lds-explore-graphql-schema.md +227 -0
  9. package/lib/templates/project/react-b2e/.a4drules/graphql/tools/knowledge/lds-generate-graphql-mutationquery.md +212 -0
  10. package/lib/templates/project/react-b2e/.a4drules/graphql/tools/knowledge/lds-generate-graphql-readquery.md +185 -0
  11. package/lib/templates/project/react-b2e/.a4drules/graphql/tools/knowledge/lds-guide-graphql.md +205 -0
  12. package/lib/templates/project/react-b2e/.a4drules/graphql/tools/schemas/shared.graphqls +1150 -0
  13. package/lib/templates/project/react-b2e/.a4drules/graphql.md +409 -0
  14. package/lib/templates/project/react-b2e/.a4drules/images.md +13 -0
  15. package/lib/templates/project/react-b2e/.a4drules/react.md +387 -0
  16. package/lib/templates/project/react-b2e/.a4drules/react_image_processing.md +45 -0
  17. package/lib/templates/project/react-b2e/.a4drules/typescript.md +224 -0
  18. package/lib/templates/project/react-b2e/.a4drules/ui-layout.md +23 -0
  19. package/lib/templates/project/react-b2e/.a4drules/webapp-nav-and-placeholders.md +33 -0
  20. package/lib/templates/project/react-b2e/.a4drules/webapp-no-node-e.md +25 -0
  21. package/lib/templates/project/react-b2e/.a4drules/webapp-ui-first.md +32 -0
  22. package/lib/templates/project/react-b2e/.a4drules/webapp.md +75 -0
  23. package/lib/templates/project/react-b2e/.forceignore +15 -0
  24. package/lib/templates/project/react-b2e/.husky/pre-commit +4 -0
  25. package/lib/templates/project/react-b2e/.prettierignore +11 -0
  26. package/lib/templates/project/react-b2e/.prettierrc +17 -0
  27. package/lib/templates/project/react-b2e/AGENT.md +75 -0
  28. package/lib/templates/project/react-b2e/CHANGELOG.md +696 -0
  29. package/lib/templates/project/react-b2e/README.md +18 -0
  30. package/lib/templates/project/react-b2e/config/project-scratch-def.json +13 -0
  31. package/lib/templates/project/react-b2e/force-app/main/default/webapplications/appreacttemplateb2e/.graphqlrc.yml +2 -0
  32. package/lib/templates/project/react-b2e/force-app/main/default/webapplications/appreacttemplateb2e/.prettierignore +9 -0
  33. package/lib/templates/project/react-b2e/force-app/main/default/webapplications/appreacttemplateb2e/.prettierrc +11 -0
  34. package/lib/templates/project/react-b2e/force-app/main/default/webapplications/appreacttemplateb2e/appreacttemplateb2e.webapplication-meta.xml +7 -0
  35. package/lib/templates/project/react-b2e/force-app/main/default/webapplications/appreacttemplateb2e/build/vite.config.d.ts +2 -0
  36. package/lib/templates/project/react-b2e/force-app/main/default/webapplications/appreacttemplateb2e/build/vite.config.js +93 -0
  37. package/lib/templates/project/react-b2e/force-app/main/default/webapplications/appreacttemplateb2e/codegen.yml +94 -0
  38. package/lib/templates/project/react-b2e/force-app/main/default/webapplications/appreacttemplateb2e/e2e/app.spec.ts +17 -0
  39. package/lib/templates/project/react-b2e/force-app/main/default/webapplications/appreacttemplateb2e/eslint.config.js +141 -0
  40. package/lib/templates/project/react-b2e/force-app/main/default/webapplications/appreacttemplateb2e/index.html +13 -0
  41. package/lib/templates/project/react-b2e/force-app/main/default/webapplications/appreacttemplateb2e/package-lock.json +14392 -0
  42. package/lib/templates/project/react-b2e/force-app/main/default/webapplications/appreacttemplateb2e/package.json +58 -0
  43. package/lib/templates/project/react-b2e/force-app/main/default/webapplications/appreacttemplateb2e/playwright.config.ts +24 -0
  44. package/lib/templates/project/react-b2e/force-app/main/default/webapplications/appreacttemplateb2e/scripts/get-graphql-schema.mjs +68 -0
  45. package/lib/templates/project/react-b2e/force-app/main/default/webapplications/appreacttemplateb2e/scripts/rewrite-e2e-assets.mjs +23 -0
  46. package/lib/templates/project/react-b2e/force-app/main/default/webapplications/appreacttemplateb2e/src/api/graphql-operations-types.ts +116 -0
  47. package/lib/templates/project/react-b2e/force-app/main/default/webapplications/appreacttemplateb2e/src/api/utils/accounts.ts +33 -0
  48. package/lib/templates/project/react-b2e/force-app/main/default/webapplications/appreacttemplateb2e/src/api/utils/query/highRevenueAccountsQuery.graphql +29 -0
  49. package/lib/templates/project/react-b2e/force-app/main/default/webapplications/appreacttemplateb2e/src/app.tsx +22 -0
  50. package/lib/templates/project/react-b2e/force-app/main/default/webapplications/appreacttemplateb2e/src/appLayout.tsx +19 -0
  51. package/lib/templates/project/react-b2e/force-app/main/default/webapplications/appreacttemplateb2e/src/assets/icons/book.svg +3 -0
  52. package/lib/templates/project/react-b2e/force-app/main/default/webapplications/appreacttemplateb2e/src/assets/icons/copy.svg +4 -0
  53. package/lib/templates/project/react-b2e/force-app/main/default/webapplications/appreacttemplateb2e/src/assets/icons/rocket.svg +3 -0
  54. package/lib/templates/project/react-b2e/force-app/main/default/webapplications/appreacttemplateb2e/src/assets/icons/star.svg +3 -0
  55. package/lib/templates/project/react-b2e/force-app/main/default/webapplications/appreacttemplateb2e/src/assets/images/codey-1.png +0 -0
  56. package/lib/templates/project/react-b2e/force-app/main/default/webapplications/appreacttemplateb2e/src/assets/images/codey-2.png +0 -0
  57. package/lib/templates/project/react-b2e/force-app/main/default/webapplications/appreacttemplateb2e/src/assets/images/codey-3.png +0 -0
  58. package/lib/templates/project/react-b2e/force-app/main/default/webapplications/appreacttemplateb2e/src/assets/images/vibe-codey.svg +194 -0
  59. package/lib/templates/project/react-b2e/force-app/main/default/webapplications/appreacttemplateb2e/src/components/AgentforceConversationClient.tsx +127 -0
  60. package/lib/templates/project/react-b2e/force-app/main/default/webapplications/appreacttemplateb2e/src/index.ts +6 -0
  61. package/lib/templates/project/react-b2e/force-app/main/default/webapplications/appreacttemplateb2e/src/navigationMenu.tsx +80 -0
  62. package/lib/templates/project/react-b2e/force-app/main/default/webapplications/appreacttemplateb2e/src/pages/Home.tsx +12 -0
  63. package/lib/templates/project/react-b2e/force-app/main/default/webapplications/appreacttemplateb2e/src/pages/NotFound.tsx +18 -0
  64. package/lib/templates/project/react-b2e/force-app/main/default/webapplications/appreacttemplateb2e/src/router-utils.tsx +35 -0
  65. package/lib/templates/project/react-b2e/force-app/main/default/webapplications/appreacttemplateb2e/src/routes.tsx +22 -0
  66. package/lib/templates/project/react-b2e/force-app/main/default/webapplications/appreacttemplateb2e/src/styles/global.css +13 -0
  67. package/lib/templates/project/react-b2e/force-app/main/default/webapplications/appreacttemplateb2e/src/types/conversation.ts +21 -0
  68. package/lib/templates/project/react-b2e/force-app/main/default/webapplications/appreacttemplateb2e/tsconfig.json +36 -0
  69. package/lib/templates/project/react-b2e/force-app/main/default/webapplications/appreacttemplateb2e/tsconfig.node.json +13 -0
  70. package/lib/templates/project/react-b2e/force-app/main/default/webapplications/appreacttemplateb2e/vite-env.d.ts +1 -0
  71. package/lib/templates/project/react-b2e/force-app/main/default/webapplications/appreacttemplateb2e/vite.config.ts +102 -0
  72. package/lib/templates/project/react-b2e/force-app/main/default/webapplications/appreacttemplateb2e/vitest-env.d.ts +2 -0
  73. package/lib/templates/project/react-b2e/force-app/main/default/webapplications/appreacttemplateb2e/vitest.config.ts +11 -0
  74. package/lib/templates/project/react-b2e/force-app/main/default/webapplications/appreacttemplateb2e/vitest.setup.ts +1 -0
  75. package/lib/templates/project/react-b2e/force-app/main/default/webapplications/appreacttemplateb2e/webapplication.json +7 -0
  76. package/lib/templates/project/react-b2e/jest.config.js +6 -0
  77. package/lib/templates/project/react-b2e/package.json +38 -0
  78. package/lib/templates/project/react-b2e/scripts/apex/hello.apex +10 -0
  79. package/lib/templates/project/react-b2e/scripts/soql/account.soql +6 -0
  80. package/lib/templates/project/react-b2e/sfdx-project.json +12 -0
  81. package/lib/templates/project/react-b2x/.a4drules/README.md +35 -0
  82. package/lib/templates/project/react-b2x/.a4drules/a4d-webapp-generate.md +27 -0
  83. package/lib/templates/project/react-b2x/.a4drules/build-validation.md +78 -0
  84. package/lib/templates/project/react-b2x/.a4drules/code-quality.md +137 -0
  85. package/lib/templates/project/react-b2x/.a4drules/graphql/tools/knowledge/lds-explore-graphql-schema.md +227 -0
  86. package/lib/templates/project/react-b2x/.a4drules/graphql/tools/knowledge/lds-generate-graphql-mutationquery.md +212 -0
  87. package/lib/templates/project/react-b2x/.a4drules/graphql/tools/knowledge/lds-generate-graphql-readquery.md +185 -0
  88. package/lib/templates/project/react-b2x/.a4drules/graphql/tools/knowledge/lds-guide-graphql.md +205 -0
  89. package/lib/templates/project/react-b2x/.a4drules/graphql/tools/schemas/shared.graphqls +1150 -0
  90. package/lib/templates/project/react-b2x/.a4drules/graphql.md +409 -0
  91. package/lib/templates/project/react-b2x/.a4drules/images.md +13 -0
  92. package/lib/templates/project/react-b2x/.a4drules/react.md +387 -0
  93. package/lib/templates/project/react-b2x/.a4drules/react_image_processing.md +45 -0
  94. package/lib/templates/project/react-b2x/.a4drules/typescript.md +224 -0
  95. package/lib/templates/project/react-b2x/.a4drules/ui-layout.md +23 -0
  96. package/lib/templates/project/react-b2x/.a4drules/webapp-nav-and-placeholders.md +33 -0
  97. package/lib/templates/project/react-b2x/.a4drules/webapp-no-node-e.md +25 -0
  98. package/lib/templates/project/react-b2x/.a4drules/webapp-ui-first.md +32 -0
  99. package/lib/templates/project/react-b2x/.a4drules/webapp.md +75 -0
  100. package/lib/templates/project/react-b2x/.forceignore +15 -0
  101. package/lib/templates/project/react-b2x/.husky/pre-commit +4 -0
  102. package/lib/templates/project/react-b2x/.prettierignore +11 -0
  103. package/lib/templates/project/react-b2x/.prettierrc +17 -0
  104. package/lib/templates/project/react-b2x/AGENT.md +75 -0
  105. package/lib/templates/project/react-b2x/CHANGELOG.md +696 -0
  106. package/lib/templates/project/react-b2x/README.md +18 -0
  107. package/lib/templates/project/react-b2x/config/project-scratch-def.json +13 -0
  108. package/lib/templates/project/react-b2x/force-app/main/default/classes/WebAppAuthUtils.cls +68 -0
  109. package/lib/templates/project/react-b2x/force-app/main/default/classes/WebAppAuthUtils.cls-meta.xml +5 -0
  110. package/lib/templates/project/react-b2x/force-app/main/default/classes/WebAppChangePassword.cls +77 -0
  111. package/lib/templates/project/react-b2x/force-app/main/default/classes/WebAppChangePassword.cls-meta.xml +5 -0
  112. package/lib/templates/project/react-b2x/force-app/main/default/classes/WebAppForgotPassword.cls +71 -0
  113. package/lib/templates/project/react-b2x/force-app/main/default/classes/WebAppForgotPassword.cls-meta.xml +5 -0
  114. package/lib/templates/project/react-b2x/force-app/main/default/classes/WebAppLogin.cls +105 -0
  115. package/lib/templates/project/react-b2x/force-app/main/default/classes/WebAppLogin.cls-meta.xml +5 -0
  116. package/lib/templates/project/react-b2x/force-app/main/default/classes/WebAppRegistration.cls +162 -0
  117. package/lib/templates/project/react-b2x/force-app/main/default/classes/WebAppRegistration.cls-meta.xml +5 -0
  118. package/lib/templates/project/react-b2x/force-app/main/default/digitalExperienceConfigs/appreacttemplateb2x1.digitalExperienceConfig +8 -0
  119. package/lib/templates/project/react-b2x/force-app/main/default/digitalExperiences/site/appreacttemplateb2x1/appreacttemplateb2x1.digitalExperience-meta.xml +11 -0
  120. package/lib/templates/project/react-b2x/force-app/main/default/digitalExperiences/site/appreacttemplateb2x1/sfdc_cms__site/appreacttemplateb2x1/_meta.json +5 -0
  121. package/lib/templates/project/react-b2x/force-app/main/default/digitalExperiences/site/appreacttemplateb2x1/sfdc_cms__site/appreacttemplateb2x1/content.json +10 -0
  122. package/lib/templates/project/react-b2x/force-app/main/default/networks/appreacttemplateb2x.network +60 -0
  123. package/lib/templates/project/react-b2x/force-app/main/default/package.xml +20 -0
  124. package/lib/templates/project/react-b2x/force-app/main/default/sites/appreacttemplateb2x.site +31 -0
  125. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/.graphqlrc.yml +2 -0
  126. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/.prettierignore +9 -0
  127. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/.prettierrc +11 -0
  128. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/appreacttemplateb2x.webapplication-meta.xml +7 -0
  129. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/build/vite.config.d.ts +2 -0
  130. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/build/vite.config.js +93 -0
  131. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/codegen.yml +94 -0
  132. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/e2e/app.spec.ts +17 -0
  133. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/eslint.config.js +141 -0
  134. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/index.html +13 -0
  135. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/package-lock.json +18408 -0
  136. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/package.json +66 -0
  137. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/playwright.config.ts +24 -0
  138. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/scripts/get-graphql-schema.mjs +68 -0
  139. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/scripts/rewrite-e2e-assets.mjs +23 -0
  140. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/src/api/graphql-operations-types.ts +116 -0
  141. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/src/api/utils/accounts.ts +33 -0
  142. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/src/api/utils/query/highRevenueAccountsQuery.graphql +29 -0
  143. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/src/app.tsx +13 -0
  144. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/src/appLayout.tsx +11 -0
  145. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/src/assets/icons/book.svg +3 -0
  146. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/src/assets/icons/copy.svg +4 -0
  147. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/src/assets/icons/rocket.svg +3 -0
  148. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/src/assets/icons/star.svg +3 -0
  149. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/src/assets/images/codey-1.png +0 -0
  150. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/src/assets/images/codey-2.png +0 -0
  151. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/src/assets/images/codey-3.png +0 -0
  152. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/src/assets/images/vibe-codey.svg +194 -0
  153. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/src/components/alerts/status-alert.tsx +45 -0
  154. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/src/components/auth/authHelpers.ts +73 -0
  155. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/src/components/auth/authenticationConfig.ts +61 -0
  156. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/src/components/auth/authenticationRouteLayout.tsx +21 -0
  157. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/src/components/auth/privateRouteLayout.tsx +36 -0
  158. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/src/components/auth/sessionTimeout/SessionTimeoutValidator.tsx +616 -0
  159. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/src/components/auth/sessionTimeout/sessionTimeService.ts +161 -0
  160. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/src/components/auth/sessionTimeout/sessionTimeoutConfig.ts +77 -0
  161. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/src/components/footers/footer-link.tsx +36 -0
  162. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/src/components/forms/auth-form.tsx +81 -0
  163. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/src/components/forms/submit-button.tsx +49 -0
  164. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/src/components/layout/card-layout.tsx +23 -0
  165. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/src/components/layout/card-skeleton.tsx +38 -0
  166. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/src/components/layout/centered-page-layout.tsx +73 -0
  167. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/src/components/ui/alert.tsx +69 -0
  168. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/src/components/ui/button.tsx +67 -0
  169. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/src/components/ui/card.tsx +92 -0
  170. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/src/components/ui/dialog.tsx +143 -0
  171. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/src/components/ui/field.tsx +222 -0
  172. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/src/components/ui/index.ts +72 -0
  173. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/src/components/ui/input.tsx +19 -0
  174. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/src/components/ui/label.tsx +19 -0
  175. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/src/components/ui/pagination.tsx +112 -0
  176. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/src/components/ui/select.tsx +183 -0
  177. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/src/components/ui/separator.tsx +26 -0
  178. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/src/components/ui/skeleton.tsx +14 -0
  179. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/src/components/ui/spinner.tsx +15 -0
  180. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/src/components/ui/table.tsx +87 -0
  181. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/src/components/ui/tabs.tsx +78 -0
  182. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/src/components.json +18 -0
  183. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/src/context/AuthContext.tsx +95 -0
  184. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/src/hooks/form.tsx +116 -0
  185. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/src/hooks/useCountdownTimer.ts +266 -0
  186. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/src/hooks/useRetryWithBackoff.ts +109 -0
  187. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/src/layouts/AuthAppLayout.tsx +12 -0
  188. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/src/lib/data-sdk.ts +21 -0
  189. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/src/lib/utils.ts +6 -0
  190. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/src/navigationMenu.tsx +80 -0
  191. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/src/pages/ChangePassword.tsx +107 -0
  192. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/src/pages/ForgotPassword.tsx +73 -0
  193. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/src/pages/Home.tsx +12 -0
  194. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/src/pages/Login.tsx +97 -0
  195. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/src/pages/NotFound.tsx +18 -0
  196. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/src/pages/Profile.tsx +178 -0
  197. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/src/pages/Register.tsx +138 -0
  198. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/src/pages/ResetPassword.tsx +107 -0
  199. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/src/router-utils.tsx +35 -0
  200. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/src/routes.tsx +71 -0
  201. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/src/styles/global.css +135 -0
  202. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/src/utils/helpers.ts +121 -0
  203. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/tsconfig.json +36 -0
  204. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/tsconfig.node.json +13 -0
  205. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/vite-env.d.ts +1 -0
  206. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/vite.config.ts +102 -0
  207. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/vitest-env.d.ts +2 -0
  208. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/vitest.config.ts +11 -0
  209. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/vitest.setup.ts +1 -0
  210. package/lib/templates/project/react-b2x/force-app/main/default/webapplications/appreacttemplateb2x/webapplication.json +7 -0
  211. package/lib/templates/project/react-b2x/jest.config.js +6 -0
  212. package/lib/templates/project/react-b2x/package.json +38 -0
  213. package/lib/templates/project/react-b2x/scripts/apex/hello.apex +10 -0
  214. package/lib/templates/project/react-b2x/scripts/soql/account.soql +6 -0
  215. package/lib/templates/project/react-b2x/sfdx-project.json +12 -0
  216. package/lib/templates/webapplication/reactbasic/.graphqlrc.yml +2 -0
  217. package/lib/templates/webapplication/reactbasic/build/vite.config.js +20 -1
  218. package/lib/templates/webapplication/reactbasic/codegen.yml +94 -0
  219. package/lib/templates/webapplication/reactbasic/e2e/app.spec.ts +0 -7
  220. package/lib/templates/webapplication/reactbasic/eslint.config.js +28 -0
  221. package/lib/templates/webapplication/reactbasic/package-lock.json +10090 -2874
  222. package/lib/templates/webapplication/reactbasic/package.json +16 -4
  223. package/lib/templates/webapplication/reactbasic/scripts/get-graphql-schema.mjs +68 -0
  224. package/lib/templates/webapplication/reactbasic/src/api/graphql-operations-types.ts +23 -34
  225. package/lib/templates/webapplication/reactbasic/src/api/utils/accounts.ts +33 -0
  226. package/lib/templates/webapplication/reactbasic/src/app.tsx +10 -1
  227. package/lib/templates/webapplication/reactbasic/src/appLayout.tsx +2 -0
  228. package/lib/templates/webapplication/reactbasic/src/navigationMenu.tsx +80 -0
  229. package/lib/templates/webapplication/reactbasic/src/router-utils.tsx +35 -0
  230. package/lib/templates/webapplication/reactbasic/src/routes.tsx +1 -7
  231. package/lib/templates/webapplication/reactbasic/vite.config.ts +20 -1
  232. package/lib/tsconfig.tsbuildinfo +1 -1
  233. package/lib/utils/types.d.ts +1 -1
  234. package/lib/utils/webappTemplateUtils.d.ts +49 -0
  235. package/lib/utils/webappTemplateUtils.js +210 -0
  236. package/lib/utils/webappTemplateUtils.js.map +1 -0
  237. package/package.json +7 -5
  238. package/lib/templates/webapplication/reactbasic/src/pages/About.tsx +0 -12
@@ -0,0 +1,97 @@
1
+ import { useState } from "react";
2
+ import { useNavigate, useSearchParams, Link } from "react-router";
3
+ import { z } from "zod";
4
+ import { CenteredPageLayout } from "../components/layout/centered-page-layout";
5
+ import { AuthForm } from "../components/forms/auth-form";
6
+ import { useAppForm } from "../hooks/form";
7
+ import { getDataSDK } from "../lib/data-sdk";
8
+ import { ROUTES } from "../components/auth/authenticationConfig";
9
+ import { emailSchema, getStartUrl, type AuthResponse } from "../components/auth/authHelpers";
10
+ import { handleApiResponse, getErrorMessage } from "../utils/helpers";
11
+
12
+ const loginSchema = z.object({
13
+ email: emailSchema,
14
+ password: z.string().min(1, "Password is required"),
15
+ });
16
+
17
+ export default function Login() {
18
+ const navigate = useNavigate();
19
+ const [searchParams] = useSearchParams();
20
+ const [submitError, setSubmitError] = useState<string | null>(null);
21
+
22
+ const form = useAppForm({
23
+ defaultValues: { email: "", password: "" },
24
+ validators: { onChange: loginSchema, onSubmit: loginSchema },
25
+ onSubmit: async ({ value }) => {
26
+ setSubmitError(null);
27
+ try {
28
+ // [Dev Note] Salesforce Integration:
29
+ // We use the Data SDK fetch to make an authenticated (or guest) call to Salesforce.
30
+ // "/sfdcapi/services/apexrest/auth/login" refers to a custom Apex REST resource.
31
+ // You must ensure this Apex class exists in your org and handles the login logic
32
+ // (e.g., creating a session or returning a token).
33
+ const sdk = await getDataSDK();
34
+ const response = await sdk.fetch("/sfdcapi/services/apexrest/auth/login", {
35
+ method: "POST",
36
+ body: JSON.stringify({
37
+ email: value.email.trim().toLowerCase(),
38
+ password: value.password,
39
+ startUrl: getStartUrl(searchParams),
40
+ }),
41
+ headers: {
42
+ "Content-Type": "application/json",
43
+ Accept: "application/json",
44
+ },
45
+ });
46
+ const result = await handleApiResponse<AuthResponse>(response, "Login failed");
47
+ if (result?.redirectUrl) {
48
+ // Hard navigate to the URL which establishes the server session cookie
49
+ window.location.replace(result.redirectUrl);
50
+ } else {
51
+ // In case redirectUrl is null, navigate to home
52
+ navigate("/", { replace: true });
53
+ }
54
+ } catch (err) {
55
+ setSubmitError(getErrorMessage(err, "Login failed"));
56
+ }
57
+ },
58
+ onSubmitInvalid: () => {},
59
+ });
60
+
61
+ return (
62
+ <CenteredPageLayout title={ROUTES.LOGIN.TITLE}>
63
+ <form.AppForm>
64
+ <AuthForm
65
+ title="Login"
66
+ description="Enter your email below to login to your account"
67
+ error={submitError}
68
+ submit={{ text: "Login", loadingText: "Logging in…" }}
69
+ footer={{
70
+ text: "Don't have an account?",
71
+ link: ROUTES.REGISTER.PATH,
72
+ linkText: "Sign up",
73
+ }}
74
+ >
75
+ <form.AppField name="email">
76
+ {(field) => <field.EmailField label="Email" />}
77
+ </form.AppField>
78
+ <form.AppField name="password">
79
+ {(field) => (
80
+ <field.PasswordField
81
+ label="Password"
82
+ labelAction={
83
+ <Link
84
+ to={ROUTES.FORGOT_PASSWORD.PATH}
85
+ className="text-sm underline-offset-4 hover:underline"
86
+ >
87
+ Forgot your password?
88
+ </Link>
89
+ }
90
+ />
91
+ )}
92
+ </form.AppField>
93
+ </AuthForm>
94
+ </form.AppForm>
95
+ </CenteredPageLayout>
96
+ );
97
+ }
@@ -0,0 +1,18 @@
1
+ import { Link } from 'react-router';
2
+
3
+ export default function NotFound() {
4
+ return (
5
+ <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
6
+ <div className="text-center">
7
+ <h1 className="text-4xl font-bold text-gray-900 mb-4">404</h1>
8
+ <p className="text-lg text-gray-600 mb-8">Page not found</p>
9
+ <Link
10
+ to="/"
11
+ className="inline-block px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition-colors"
12
+ >
13
+ Go to Home
14
+ </Link>
15
+ </div>
16
+ </div>
17
+ );
18
+ }
@@ -0,0 +1,178 @@
1
+ import { useState, useEffect } from "react";
2
+ import { z } from "zod";
3
+
4
+ import { executeGraphQL } from "@salesforce/webapp-experimental/api";
5
+
6
+ import { CenteredPageLayout } from "../components/layout/centered-page-layout";
7
+ import { CardSkeleton } from "../components/layout/card-skeleton";
8
+ import { AuthForm } from "../components/forms/auth-form";
9
+ import { useAppForm } from "../hooks/form";
10
+ import { ROUTES } from "../components/auth/authenticationConfig";
11
+ import { emailSchema } from "../components/auth/authHelpers";
12
+ import { flattenGraphQLRecord, getErrorMessage } from "../utils/helpers";
13
+ import { getUser } from "../context/AuthContext";
14
+
15
+ const GRAPHQL_USER_PROFILE_FIELDS = `
16
+ Id
17
+ FirstName { value }
18
+ LastName { value }
19
+ Email { value }
20
+ Phone { value }
21
+ Street { value }
22
+ City { value }
23
+ State { value }
24
+ PostalCode { value }
25
+ Country { value }`;
26
+
27
+ const QUERY_PROFILE_GRAPHQL = `
28
+ query GetUserProfile($userId: ID) {
29
+ uiapi {
30
+ query {
31
+ User(where: { Id: { eq: $userId } }) {
32
+ edges {
33
+ node {${GRAPHQL_USER_PROFILE_FIELDS}}
34
+ }
35
+ }
36
+ }
37
+ }
38
+ }`;
39
+
40
+ const MUTATE_PROFILE_GRAPHQL = `
41
+ mutation UpdateUserProfile($input: UserUpdateInput!) {
42
+ uiapi {
43
+ UserUpdate(input: $input) {
44
+ Record {${GRAPHQL_USER_PROFILE_FIELDS}}
45
+ }
46
+ }
47
+ }`;
48
+
49
+ const optionalString = z
50
+ .string()
51
+ .trim()
52
+ .transform((val) => (val === "" ? null : val))
53
+ .nullable()
54
+ .optional();
55
+
56
+ const profileSchema = z.object({
57
+ FirstName: z.string().trim().min(1, "First name is required"),
58
+ LastName: z.string().trim().min(1, "Last name is required"),
59
+ Email: emailSchema,
60
+ Phone: optionalString,
61
+ Street: optionalString,
62
+ City: optionalString,
63
+ State: optionalString,
64
+ PostalCode: optionalString,
65
+ Country: optionalString,
66
+ });
67
+
68
+ type ProfileFormValues = z.infer<typeof profileSchema>;
69
+
70
+ export default function Profile() {
71
+ const user = getUser();
72
+ const [profile, setProfile] = useState<ProfileFormValues | null>(null);
73
+ const [loadError, setLoadError] = useState<string | null>(null);
74
+ const [success, setSuccess] = useState(false);
75
+ const [submitError, setSubmitError] = useState<string | null>(null);
76
+
77
+ const form = useAppForm({
78
+ defaultValues: {} as ProfileFormValues,
79
+ validators: { onChange: profileSchema, onSubmit: profileSchema },
80
+ onSubmit: async ({ value }) => {
81
+ setSubmitError(null);
82
+ setSuccess(false);
83
+ try {
84
+ const result: any = await executeGraphQL(MUTATE_PROFILE_GRAPHQL, {
85
+ input: { Id: user.id, User: { ...value } },
86
+ });
87
+ setProfile(flattenGraphQLRecord(result?.uiapi?.UserUpdate?.Record));
88
+
89
+ setSuccess(true);
90
+ // Scroll to top of page after successful update so user sees it
91
+ window.scrollTo({ top: 0, behavior: "smooth" });
92
+ } catch (err) {
93
+ setSubmitError(getErrorMessage(err, "Failed to update profile"));
94
+ }
95
+ },
96
+ onSubmitInvalid: () => {},
97
+ });
98
+
99
+ useEffect(() => {
100
+ let mounted = true;
101
+
102
+ executeGraphQL(QUERY_PROFILE_GRAPHQL, { userId: user.id })
103
+ .then(
104
+ (result: any) =>
105
+ mounted && setProfile(flattenGraphQLRecord(result?.uiapi?.query?.User?.edges?.[0]?.node)),
106
+ )
107
+ .catch((err: any) => {
108
+ if (mounted) {
109
+ setLoadError(getErrorMessage(err, "Failed to load profile"));
110
+ } else {
111
+ console.error("Failed to load profile", err);
112
+ }
113
+ });
114
+ return () => {
115
+ mounted = false;
116
+ };
117
+ }, [user.id]);
118
+
119
+ useEffect(() => {
120
+ if (profile) {
121
+ const formData = profileSchema.parse(profile);
122
+ form.reset(formData);
123
+ }
124
+ }, [profile]);
125
+
126
+ if (!profile && !loadError) {
127
+ return <CardSkeleton contentMaxWidth="md" loadingText="Loading profile…" />;
128
+ }
129
+
130
+ return (
131
+ <CenteredPageLayout contentMaxWidth="md" title={ROUTES.PROFILE.TITLE}>
132
+ <form.AppForm>
133
+ <AuthForm
134
+ title="Profile"
135
+ description="Update your account information"
136
+ error={loadError ?? submitError}
137
+ success={success && "Profile updated!"}
138
+ submit={{ text: "Save Changes", loadingText: "Saving…" }}
139
+ footer={{ link: ROUTES.CHANGE_PASSWORD.PATH, linkText: "Change password" }}
140
+ >
141
+ <form.AppField name="Email">
142
+ {(field) => <field.EmailField label="Email" disabled />}
143
+ </form.AppField>
144
+ <div className="grid grid-cols-1 gap-4 sm:grid-cols-2 items-start">
145
+ <form.AppField name="FirstName">
146
+ {(field) => <field.TextField label="First name" autoComplete="given-name" />}
147
+ </form.AppField>
148
+ <form.AppField name="LastName">
149
+ {(field) => <field.TextField label="Last name" autoComplete="family-name" />}
150
+ </form.AppField>
151
+ </div>
152
+ <form.AppField name="Phone">
153
+ {(field) => <field.TextField label="Phone" type="tel" autoComplete="tel" />}
154
+ </form.AppField>
155
+ <form.AppField name="Street">
156
+ {(field) => <field.TextField label="Street" autoComplete="street-address" />}
157
+ </form.AppField>
158
+ <div className="grid grid-cols-1 gap-4 sm:grid-cols-2 items-start">
159
+ <form.AppField name="City">
160
+ {(field) => <field.TextField label="City" autoComplete="address-level2" />}
161
+ </form.AppField>
162
+ <form.AppField name="State">
163
+ {(field) => <field.TextField label="State" autoComplete="address-level1" />}
164
+ </form.AppField>
165
+ </div>
166
+ <div className="grid grid-cols-1 gap-4 sm:grid-cols-2 items-start">
167
+ <form.AppField name="PostalCode">
168
+ {(field) => <field.TextField label="Postal Code" autoComplete="postal-code" />}
169
+ </form.AppField>
170
+ <form.AppField name="Country">
171
+ {(field) => <field.TextField label="Country" autoComplete="country-name" />}
172
+ </form.AppField>
173
+ </div>
174
+ </AuthForm>
175
+ </form.AppForm>
176
+ </CenteredPageLayout>
177
+ );
178
+ }
@@ -0,0 +1,138 @@
1
+ import { useState } from "react";
2
+ import { useNavigate, useSearchParams } from "react-router";
3
+ import { z } from "zod";
4
+ import { CenteredPageLayout } from "../components/layout/centered-page-layout";
5
+ import { AuthForm } from "../components/forms/auth-form";
6
+ import { useAppForm } from "../hooks/form";
7
+ import { getDataSDK } from "../lib/data-sdk";
8
+ import { ROUTES, AUTH_PLACEHOLDERS } from "../components/auth/authenticationConfig";
9
+ import {
10
+ emailSchema,
11
+ passwordSchema,
12
+ getStartUrl,
13
+ type AuthResponse,
14
+ } from "../components/auth/authHelpers";
15
+ import { handleApiResponse, getErrorMessage } from "../utils/helpers";
16
+
17
+ const registerSchema = z
18
+ .object({
19
+ firstName: z.string().trim().min(1, "First name is required"),
20
+ lastName: z.string().trim().min(1, "Last name is required"),
21
+ email: emailSchema,
22
+ password: passwordSchema,
23
+ confirmPassword: z.string().min(1, "Please confirm your password"),
24
+ startUrl: z.string(),
25
+ })
26
+ .refine((data) => data.password === data.confirmPassword, {
27
+ message: "Passwords do not match",
28
+ path: ["confirmPassword"],
29
+ });
30
+
31
+ export default function Register() {
32
+ const navigate = useNavigate();
33
+ const [searchParams] = useSearchParams();
34
+ const [submitError, setSubmitError] = useState<string | null>(null);
35
+
36
+ const form = useAppForm({
37
+ defaultValues: {
38
+ firstName: "",
39
+ lastName: "",
40
+ email: "",
41
+ password: "",
42
+ confirmPassword: "",
43
+ startUrl: getStartUrl(searchParams) || "",
44
+ },
45
+ validators: { onChange: registerSchema, onSubmit: registerSchema },
46
+ onSubmit: async ({ value: formFieldValues }) => {
47
+ setSubmitError(null);
48
+ try {
49
+ // [Dev Note] Salesforce Integration:
50
+ // We use the Data SDK fetch to make an authenticated (or guest) call to Salesforce.
51
+ // "/sfdcapi/services/apexrest/auth/register" refers to a custom Apex Class exposed as a REST resource.
52
+ // You must ensure this Apex class exists in your org and handles registration
53
+ // (e.g., duplicate checks and user creation such as Site.createExternalUser).
54
+ const { confirmPassword, ...request } = formFieldValues;
55
+ const sdk = await getDataSDK();
56
+ const response = await sdk.fetch("/sfdcapi/services/apexrest/auth/register", {
57
+ method: "POST",
58
+ body: JSON.stringify({ request }),
59
+ headers: {
60
+ "Content-Type": "application/json",
61
+ Accept: "application/json",
62
+ },
63
+ });
64
+ const result = await handleApiResponse<AuthResponse>(response, "Registration failed");
65
+ if (result?.redirectUrl) {
66
+ // Hard navigate to the URL which logs the new user in
67
+ window.location.replace(result.redirectUrl);
68
+ } else {
69
+ // In case redirectUrl is null, redirect to the login page
70
+ navigate(ROUTES.LOGIN.PATH, { replace: true });
71
+ }
72
+ } catch (err) {
73
+ setSubmitError(getErrorMessage(err, "Registration failed"));
74
+ }
75
+ },
76
+ onSubmitInvalid: () => {},
77
+ });
78
+
79
+ return (
80
+ <CenteredPageLayout title={ROUTES.REGISTER.TITLE}>
81
+ <form.AppForm>
82
+ <AuthForm
83
+ title="Sign Up"
84
+ description="Enter your information to create an account"
85
+ error={submitError}
86
+ submit={{ text: "Create an account", loadingText: "Creating account…" }}
87
+ footer={{
88
+ text: "Already have an account?",
89
+ link: ROUTES.LOGIN.PATH,
90
+ linkText: "Sign in",
91
+ }}
92
+ >
93
+ <div className="grid grid-cols-1 gap-4 sm:grid-cols-2 items-start">
94
+ <form.AppField name="firstName">
95
+ {(field) => (
96
+ <field.TextField
97
+ label="First name"
98
+ placeholder={AUTH_PLACEHOLDERS.FIRST_NAME}
99
+ autoComplete="given-name"
100
+ />
101
+ )}
102
+ </form.AppField>
103
+ <form.AppField name="lastName">
104
+ {(field) => (
105
+ <field.TextField
106
+ label="Last name"
107
+ placeholder={AUTH_PLACEHOLDERS.LAST_NAME}
108
+ autoComplete="family-name"
109
+ />
110
+ )}
111
+ </form.AppField>
112
+ </div>
113
+ <form.AppField name="email">
114
+ {(field) => <field.EmailField label="Email" />}
115
+ </form.AppField>
116
+ <form.AppField name="password">
117
+ {(field) => (
118
+ <field.PasswordField
119
+ label="Password"
120
+ placeholder={AUTH_PLACEHOLDERS.PASSWORD_CREATE}
121
+ autoComplete="new-password"
122
+ />
123
+ )}
124
+ </form.AppField>
125
+ <form.AppField name="confirmPassword">
126
+ {(field) => (
127
+ <field.PasswordField
128
+ label="Confirm Password"
129
+ placeholder={AUTH_PLACEHOLDERS.PASSWORD_CONFIRM}
130
+ autoComplete="new-password"
131
+ />
132
+ )}
133
+ </form.AppField>
134
+ </AuthForm>
135
+ </form.AppForm>
136
+ </CenteredPageLayout>
137
+ );
138
+ }
@@ -0,0 +1,107 @@
1
+ import { useState } from "react";
2
+ import { Link, useSearchParams } from "react-router";
3
+ import { CardLayout } from "../components/layout/card-layout";
4
+ import { CenteredPageLayout } from "../components/layout/centered-page-layout";
5
+ import { AuthForm } from "../components/forms/auth-form";
6
+ import { StatusAlert } from "../components/alerts/status-alert";
7
+ import { useAppForm } from "../hooks/form";
8
+ import { getDataSDK } from "../lib/data-sdk";
9
+ import { ROUTES, AUTH_PLACEHOLDERS } from "../components/auth/authenticationConfig";
10
+ import { newPasswordSchema } from "../components/auth/authHelpers";
11
+ import { handleApiResponse, getErrorMessage } from "../utils/helpers";
12
+
13
+ export default function ResetPassword() {
14
+ const [searchParams] = useSearchParams();
15
+ const token = searchParams.get("token");
16
+ const [success, setSuccess] = useState(false);
17
+ const [submitError, setSubmitError] = useState<string | null>(null);
18
+
19
+ const form = useAppForm({
20
+ defaultValues: { newPassword: "", confirmPassword: "" },
21
+ validators: { onChange: newPasswordSchema, onSubmit: newPasswordSchema },
22
+ onSubmit: async ({ value }) => {
23
+ setSubmitError(null);
24
+ setSuccess(false);
25
+ try {
26
+ // [Dev Note] Custom Apex Endpoint: /auth/reset-password
27
+ // You must ensure this Apex class exists in your org
28
+ const sdk = await getDataSDK();
29
+ const response = await sdk.fetch("/sfdcapi/services/apexrest/auth/reset-password", {
30
+ method: "POST",
31
+ body: JSON.stringify({ token, newPassword: value.newPassword }),
32
+ headers: {
33
+ "Content-Type": "application/json",
34
+ Accept: "application/json",
35
+ },
36
+ });
37
+ await handleApiResponse(response, "Password reset failed");
38
+ setSuccess(true);
39
+ // Scroll to top of page after successful submission so user sees it
40
+ window.scrollTo({ top: 0, behavior: "smooth" });
41
+ } catch (err) {
42
+ setSubmitError(getErrorMessage(err, "Password reset failed"));
43
+ }
44
+ },
45
+ onSubmitInvalid: () => {},
46
+ });
47
+
48
+ if (!token) {
49
+ return (
50
+ <CenteredPageLayout title={ROUTES.RESET_PASSWORD.TITLE}>
51
+ <CardLayout title="Reset Password">
52
+ <StatusAlert>
53
+ Reset token is invalid or expired.{" "}
54
+ <Link to={ROUTES.FORGOT_PASSWORD.PATH} className="underline underline-offset-4">
55
+ Request a new password reset link.
56
+ </Link>
57
+ </StatusAlert>
58
+ </CardLayout>
59
+ </CenteredPageLayout>
60
+ );
61
+ }
62
+
63
+ return (
64
+ <CenteredPageLayout title={ROUTES.RESET_PASSWORD.TITLE}>
65
+ <form.AppForm>
66
+ <AuthForm
67
+ title="Reset Password"
68
+ description="Enter your new password below"
69
+ error={submitError}
70
+ success={
71
+ success && (
72
+ <>
73
+ Password reset successfully!{" "}
74
+ <Link to={ROUTES.LOGIN.PATH} className="underline">
75
+ Sign in
76
+ </Link>
77
+ </>
78
+ )
79
+ }
80
+ submit={{ text: "Reset Password", loadingText: "Resetting…" }}
81
+ footer={{ text: "Remember your password?", link: ROUTES.LOGIN.PATH, linkText: "Sign in" }}
82
+ >
83
+ <form.AppField name="newPassword">
84
+ {(field) => (
85
+ <field.PasswordField
86
+ label="New Password"
87
+ placeholder={AUTH_PLACEHOLDERS.PASSWORD_NEW}
88
+ autoComplete="new-password"
89
+ disabled={success}
90
+ />
91
+ )}
92
+ </form.AppField>
93
+ <form.AppField name="confirmPassword">
94
+ {(field) => (
95
+ <field.PasswordField
96
+ label="Confirm Password"
97
+ placeholder={AUTH_PLACEHOLDERS.PASSWORD_NEW_CONFIRM}
98
+ autoComplete="new-password"
99
+ disabled={success}
100
+ />
101
+ )}
102
+ </form.AppField>
103
+ </AuthForm>
104
+ </form.AppForm>
105
+ </CenteredPageLayout>
106
+ );
107
+ }
@@ -0,0 +1,35 @@
1
+ import type { RouteObject } from 'react-router';
2
+ import { routes } from './routes';
3
+
4
+ export type RouteWithFullPath = RouteObject & { fullPath: string };
5
+
6
+ const flatMapRoutes = (
7
+ route: RouteObject,
8
+ parentPath: string = ''
9
+ ): RouteWithFullPath[] => {
10
+ let fullPath: string;
11
+
12
+ if (route.index) {
13
+ fullPath = parentPath || '/';
14
+ } else if (route.path) {
15
+ if (route.path.startsWith('/')) {
16
+ fullPath = route.path;
17
+ } else {
18
+ fullPath =
19
+ parentPath === '/' ? `/${route.path}` : `${parentPath}/${route.path}`;
20
+ }
21
+ } else {
22
+ fullPath = parentPath;
23
+ }
24
+
25
+ const routeWithPath = { ...route, fullPath };
26
+
27
+ const childRoutes =
28
+ route.children?.flatMap(child => flatMapRoutes(child, fullPath)) || [];
29
+
30
+ return [routeWithPath, ...childRoutes];
31
+ };
32
+
33
+ export const getAllRoutes = (): RouteWithFullPath[] => {
34
+ return routes.flatMap(route => flatMapRoutes(route));
35
+ };
@@ -0,0 +1,71 @@
1
+ import type { RouteObject } from 'react-router';
2
+ import Home from './pages/Home';
3
+ import NotFound from './pages/NotFound';
4
+ import Login from "./pages/Login";
5
+ import Register from "./pages/Register";
6
+ import ForgotPassword from "./pages/ForgotPassword";
7
+ import ResetPassword from "./pages/ResetPassword";
8
+ import Profile from "./pages/Profile";
9
+ import ChangePassword from "./pages/ChangePassword";
10
+ import AuthenticationRoute from "./components/auth/authenticationRouteLayout";
11
+ import PrivateRoute from "./components/auth/privateRouteLayout";
12
+ import { ROUTES } from "./components/auth/authenticationConfig";
13
+ import AppLayout from "./appLayout";
14
+
15
+ export const routes: RouteObject[] = [
16
+ {
17
+ path: "/",
18
+ element: <AppLayout />,
19
+ children: [
20
+ {
21
+ index: true,
22
+ element: <Home />,
23
+ handle: { showInNavigation: true, label: 'Home' }
24
+ },
25
+ {
26
+ path: '*',
27
+ element: <NotFound />
28
+ },
29
+ {
30
+ element: <AuthenticationRoute />,
31
+ children: [
32
+ {
33
+ path: ROUTES.LOGIN.PATH,
34
+ element: <Login />,
35
+ handle: { showInNavigation: true, label: "Login", title: ROUTES.LOGIN.TITLE }
36
+ },
37
+ {
38
+ path: ROUTES.REGISTER.PATH,
39
+ element: <Register />,
40
+ handle: { showInNavigation: false, title: ROUTES.REGISTER.TITLE }
41
+ },
42
+ {
43
+ path: ROUTES.FORGOT_PASSWORD.PATH,
44
+ element: <ForgotPassword />,
45
+ handle: { showInNavigation: false, title: ROUTES.FORGOT_PASSWORD.TITLE }
46
+ },
47
+ {
48
+ path: ROUTES.RESET_PASSWORD.PATH,
49
+ element: <ResetPassword />,
50
+ handle: { showInNavigation: false, title: ROUTES.RESET_PASSWORD.TITLE }
51
+ }
52
+ ]
53
+ },
54
+ {
55
+ element: <PrivateRoute />,
56
+ children: [
57
+ {
58
+ path: ROUTES.PROFILE.PATH,
59
+ element: <Profile />,
60
+ handle: { showInNavigation: true, label: "Profile", title: ROUTES.PROFILE.TITLE }
61
+ },
62
+ {
63
+ path: ROUTES.CHANGE_PASSWORD.PATH,
64
+ element: <ChangePassword />,
65
+ handle: { showInNavigation: false, title: ROUTES.CHANGE_PASSWORD.TITLE }
66
+ }
67
+ ]
68
+ }
69
+ ]
70
+ }
71
+ ];