@salesforce/ui-bundle-template-app-angular-template-b2x 11.30.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 (211) hide show
  1. package/LICENSE.txt +82 -0
  2. package/dist/.forceignore +15 -0
  3. package/dist/.husky/pre-commit +4 -0
  4. package/dist/.prettierignore +11 -0
  5. package/dist/.prettierrc +17 -0
  6. package/dist/CHANGELOG.md +3966 -0
  7. package/dist/README.md +77 -0
  8. package/dist/config/project-scratch-def.json +13 -0
  9. package/dist/eslint.config.js +7 -0
  10. package/dist/force-app/main/default/classes/UIBundleAuthUtils.cls +68 -0
  11. package/dist/force-app/main/default/classes/UIBundleAuthUtils.cls-meta.xml +5 -0
  12. package/dist/force-app/main/default/classes/UIBundleChangePassword.cls +77 -0
  13. package/dist/force-app/main/default/classes/UIBundleChangePassword.cls-meta.xml +5 -0
  14. package/dist/force-app/main/default/classes/UIBundleForgotPassword.cls +71 -0
  15. package/dist/force-app/main/default/classes/UIBundleForgotPassword.cls-meta.xml +5 -0
  16. package/dist/force-app/main/default/classes/UIBundleLogin.cls +105 -0
  17. package/dist/force-app/main/default/classes/UIBundleLogin.cls-meta.xml +5 -0
  18. package/dist/force-app/main/default/classes/UIBundleRegistration.cls +162 -0
  19. package/dist/force-app/main/default/classes/UIBundleRegistration.cls-meta.xml +5 -0
  20. package/dist/force-app/main/default/digitalExperienceConfigs/angularexternalapp1.digitalExperienceConfig-meta.xml +8 -0
  21. package/dist/force-app/main/default/digitalExperiences/site/angularexternalapp1/angularexternalapp1.digitalExperience-meta.xml +11 -0
  22. package/dist/force-app/main/default/digitalExperiences/site/angularexternalapp1/sfdc_cms__site/angularexternalapp1/_meta.json +5 -0
  23. package/dist/force-app/main/default/digitalExperiences/site/angularexternalapp1/sfdc_cms__site/angularexternalapp1/content.json +10 -0
  24. package/dist/force-app/main/default/networks/angularexternalapp.network-meta.xml +60 -0
  25. package/dist/force-app/main/default/package.xml +24 -0
  26. package/dist/force-app/main/default/permissionsets/angularexternalapp_Guest_User_Api_Access.permissionset-meta.xml +9 -0
  27. package/dist/force-app/main/default/sites/angularexternalapp.site-meta.xml +31 -0
  28. package/dist/force-app/main/default/uiBundles/angularexternalapp/.forceignore +15 -0
  29. package/dist/force-app/main/default/uiBundles/angularexternalapp/.postcssrc.json +5 -0
  30. package/dist/force-app/main/default/uiBundles/angularexternalapp/.prettierignore +8 -0
  31. package/dist/force-app/main/default/uiBundles/angularexternalapp/.prettierrc +12 -0
  32. package/dist/force-app/main/default/uiBundles/angularexternalapp/CHANGELOG.md +4 -0
  33. package/dist/force-app/main/default/uiBundles/angularexternalapp/README.md +85 -0
  34. package/dist/force-app/main/default/uiBundles/angularexternalapp/angular.json +98 -0
  35. package/dist/force-app/main/default/uiBundles/angularexternalapp/angularexternalapp.uibundle-meta.xml +8 -0
  36. package/dist/force-app/main/default/uiBundles/angularexternalapp/e2e/app.spec.ts +15 -0
  37. package/dist/force-app/main/default/uiBundles/angularexternalapp/esbuild/api-version.mjs +17 -0
  38. package/dist/force-app/main/default/uiBundles/angularexternalapp/eslint.config.js +60 -0
  39. package/dist/force-app/main/default/uiBundles/angularexternalapp/middleware/html.mjs +3 -0
  40. package/dist/force-app/main/default/uiBundles/angularexternalapp/middleware/proxy.mjs +12 -0
  41. package/dist/force-app/main/default/uiBundles/angularexternalapp/package.json +56 -0
  42. package/dist/force-app/main/default/uiBundles/angularexternalapp/playwright.config.ts +25 -0
  43. package/dist/force-app/main/default/uiBundles/angularexternalapp/public/favicon.ico +0 -0
  44. package/dist/force-app/main/default/uiBundles/angularexternalapp/scripts/rewrite-e2e-assets.mjs +30 -0
  45. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/api/account/account-search.service.ts +196 -0
  46. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/api/account/distinctAccountIndustries.ts +26 -0
  47. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/api/account/distinctAccountTypes.ts +26 -0
  48. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/api/account/getAccountDetail.ts +128 -0
  49. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/api/account/searchAccounts.ts +58 -0
  50. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/api/data-client.service.spec.ts +184 -0
  51. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/api/data-client.service.ts +74 -0
  52. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/api/user-profile.service.ts +126 -0
  53. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/app.config.ts +22 -0
  54. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/app.html +1 -0
  55. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/app.routes.ts +77 -0
  56. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/app.spec.ts +18 -0
  57. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/app.ts +15 -0
  58. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/layout/app-layout/app-layout.component.html +53 -0
  59. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/layout/app-layout/app-layout.component.spec.ts +89 -0
  60. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/layout/app-layout/app-layout.component.ts +81 -0
  61. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/_field-size.scss +42 -0
  62. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/alert/alert.component.html +31 -0
  63. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/alert/alert.component.ts +53 -0
  64. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/button/button.component.html +18 -0
  65. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/button/button.component.scss +112 -0
  66. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/button/button.component.ts +57 -0
  67. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/card/card.component.scss +34 -0
  68. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/card/card.component.ts +110 -0
  69. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/collapsible/collapsible.component.html +10 -0
  70. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/collapsible/collapsible.component.ts +26 -0
  71. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/date-picker/date-picker.component.html +25 -0
  72. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/date-picker/date-picker.component.scss +36 -0
  73. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/date-picker/date-picker.component.ts +41 -0
  74. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/date-range-picker/date-range-picker.component.html +34 -0
  75. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/date-range-picker/date-range-picker.component.scss +33 -0
  76. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/date-range-picker/date-range-picker.component.ts +66 -0
  77. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/dialog/dialog.component.html +37 -0
  78. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/dialog/dialog.component.ts +55 -0
  79. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/field/field.component.html +21 -0
  80. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/field/field.component.ts +36 -0
  81. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/field-size.ts +8 -0
  82. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/input/input.component.html +19 -0
  83. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/input/input.component.scss +35 -0
  84. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/input/input.component.ts +36 -0
  85. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/label/label.component.html +3 -0
  86. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/label/label.component.ts +17 -0
  87. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/paginator/paginator.component.html +10 -0
  88. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/paginator/paginator.component.ts +37 -0
  89. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/popover/popover.component.html +41 -0
  90. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/popover/popover.component.ts +40 -0
  91. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/select/select.component.html +24 -0
  92. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/select/select.component.scss +35 -0
  93. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/select/select.component.ts +72 -0
  94. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/separator/separator.component.html +1 -0
  95. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/separator/separator.component.scss +23 -0
  96. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/separator/separator.component.ts +56 -0
  97. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/skeleton/skeleton.component.html +1 -0
  98. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/skeleton/skeleton.component.scss +28 -0
  99. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/skeleton/skeleton.component.ts +24 -0
  100. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/components/ui/spinner/spinner.component.ts +35 -0
  101. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/authentication/auth/auth.guard.ts +50 -0
  102. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/authentication/auth/auth.service.ts +126 -0
  103. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/authentication/components/status-alert/status-alert.component.html +7 -0
  104. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/authentication/components/status-alert/status-alert.component.ts +52 -0
  105. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/authentication/config/authentication.config.ts +75 -0
  106. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/authentication/forms/auth-form/auth-form.component.html +38 -0
  107. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/authentication/forms/auth-form/auth-form.component.ts +94 -0
  108. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/authentication/forms/footer-link/footer-link.component.html +11 -0
  109. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/authentication/forms/footer-link/footer-link.component.ts +26 -0
  110. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/authentication/forms/reactive-form-page.base.ts +50 -0
  111. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/authentication/forms/submit-button/submit-button.component.html +8 -0
  112. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/authentication/forms/submit-button/submit-button.component.scss +17 -0
  113. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/authentication/forms/submit-button/submit-button.component.ts +35 -0
  114. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/authentication/layouts/auth-app-layout/auth-app-layout.component.html +2 -0
  115. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/authentication/layouts/auth-app-layout/auth-app-layout.component.ts +30 -0
  116. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/authentication/layouts/card-layout/card-layout.component.html +17 -0
  117. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/authentication/layouts/card-layout/card-layout.component.ts +40 -0
  118. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/authentication/menu/auth-menu/auth-menu.component.html +26 -0
  119. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/authentication/menu/auth-menu/auth-menu.component.ts +46 -0
  120. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/authentication/session-timeout/session-time-servlet.ts +130 -0
  121. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/authentication/session-timeout/session-timeout-validator/session-timeout-validator.component.html +57 -0
  122. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/authentication/session-timeout/session-timeout-validator/session-timeout-validator.component.ts +205 -0
  123. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/authentication/session-timeout/session-timeout.config.ts +83 -0
  124. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/authentication/session-timeout/session-timeout.service.ts +201 -0
  125. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/authentication/utils/auth-helpers.ts +68 -0
  126. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/authentication/utils/auth-validators.ts +72 -0
  127. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/authentication/utils/helpers.ts +85 -0
  128. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/object-search/components/active-filters/active-filters.component.html +23 -0
  129. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/object-search/components/active-filters/active-filters.component.ts +78 -0
  130. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/object-search/components/filters/date-filter/date-filter.component.html +18 -0
  131. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/object-search/components/filters/date-filter/date-filter.component.ts +137 -0
  132. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/object-search/components/filters/date-range-filter/date-range-filter.component.html +11 -0
  133. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/object-search/components/filters/date-range-filter/date-range-filter.component.ts +69 -0
  134. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/object-search/components/filters/filter-field-wrapper/filter-field-wrapper.component.html +11 -0
  135. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/object-search/components/filters/filter-field-wrapper/filter-field-wrapper.component.ts +36 -0
  136. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/object-search/components/filters/multi-select-filter/multi-select-filter.component.html +10 -0
  137. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/object-search/components/filters/multi-select-filter/multi-select-filter.component.ts +58 -0
  138. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/object-search/components/filters/numeric-range-filter/numeric-range-filter.component.html +22 -0
  139. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/object-search/components/filters/numeric-range-filter/numeric-range-filter.component.ts +146 -0
  140. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/object-search/components/filters/search-filter/search-filter.component.html +8 -0
  141. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/object-search/components/filters/search-filter/search-filter.component.ts +82 -0
  142. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/object-search/components/filters/select-filter/select-filter.component.html +12 -0
  143. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/object-search/components/filters/select-filter/select-filter.component.ts +65 -0
  144. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/object-search/components/filters/text-filter/text-filter.component.html +12 -0
  145. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/object-search/components/filters/text-filter/text-filter.component.ts +90 -0
  146. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/object-search/components/object-breadcrumb/object-breadcrumb.component.html +55 -0
  147. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/object-search/components/object-breadcrumb/object-breadcrumb.component.ts +40 -0
  148. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/object-search/components/pagination-controls/pagination-controls.component.html +8 -0
  149. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/object-search/components/pagination-controls/pagination-controls.component.ts +61 -0
  150. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/object-search/components/search-bar/search-bar.component.html +59 -0
  151. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/object-search/components/search-bar/search-bar.component.ts +108 -0
  152. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/object-search/components/sort-control/sort-control.component.html +50 -0
  153. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/object-search/components/sort-control/sort-control.component.ts +72 -0
  154. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/object-search/object-search-state.service.ts +232 -0
  155. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/object-search/utils/debounce.ts +31 -0
  156. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/object-search/utils/field-utils.ts +54 -0
  157. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/object-search/utils/filter-utils.ts +354 -0
  158. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/object-search/utils/index.ts +12 -0
  159. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/features/object-search/utils/sort-utils.ts +46 -0
  160. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/pages/account-detail/account-detail-page.component.html +174 -0
  161. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/pages/account-detail/account-detail-page.component.scss +7 -0
  162. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/pages/account-detail/account-detail-page.component.ts +199 -0
  163. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/pages/account-search/account-search-page.component.html +111 -0
  164. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/pages/account-search/account-search-page.component.ts +217 -0
  165. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/pages/change-password/change-password-page.component.html +68 -0
  166. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/pages/change-password/change-password-page.component.ts +82 -0
  167. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/pages/forgot-password/forgot-password-page.component.html +35 -0
  168. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/pages/forgot-password/forgot-password-page.component.ts +87 -0
  169. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/pages/home/home-page.component.html +18 -0
  170. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/pages/home/home-page.component.ts +47 -0
  171. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/pages/home/home.component.html +6 -0
  172. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/pages/home/home.component.spec.ts +23 -0
  173. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/pages/home/home.component.ts +13 -0
  174. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/pages/login/login-page.component.html +47 -0
  175. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/pages/login/login-page.component.ts +89 -0
  176. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/pages/not-found/not-found.component.html +12 -0
  177. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/pages/not-found/not-found.component.spec.ts +33 -0
  178. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/pages/not-found/not-found.component.ts +15 -0
  179. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/pages/profile/profile-page.component.html +126 -0
  180. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/pages/profile/profile-page.component.ts +194 -0
  181. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/pages/register/register-page.component.html +80 -0
  182. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/pages/register/register-page.component.ts +93 -0
  183. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/pages/reset-password/reset-password-page.component.html +60 -0
  184. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/pages/reset-password/reset-password-page.component.ts +96 -0
  185. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/app/utils/async-data.ts +99 -0
  186. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/index.html +14 -0
  187. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/main.ts +5 -0
  188. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/styles.scss +170 -0
  189. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/theme.scss +39 -0
  190. package/dist/force-app/main/default/uiBundles/angularexternalapp/src/types/sf-globals.d.ts +9 -0
  191. package/dist/force-app/main/default/uiBundles/angularexternalapp/tsconfig.app.json +11 -0
  192. package/dist/force-app/main/default/uiBundles/angularexternalapp/tsconfig.json +33 -0
  193. package/dist/force-app/main/default/uiBundles/angularexternalapp/tsconfig.spec.json +10 -0
  194. package/dist/force-app/main/default/uiBundles/angularexternalapp/ui-bundle.json +7 -0
  195. package/dist/jest.config.js +6 -0
  196. package/dist/package-lock.json +10066 -0
  197. package/dist/package.json +46 -0
  198. package/dist/scripts/apex/hello.apex +10 -0
  199. package/dist/scripts/gitignore-templates.json +4 -0
  200. package/dist/scripts/graphql-search.sh +191 -0
  201. package/dist/scripts/org-setup-config-schema.mjs +103 -0
  202. package/dist/scripts/org-setup-dev.mjs +87 -0
  203. package/dist/scripts/org-setup-utils.mjs +369 -0
  204. package/dist/scripts/org-setup-xml.mjs +182 -0
  205. package/dist/scripts/org-setup.config.json +9 -0
  206. package/dist/scripts/org-setup.mjs +1702 -0
  207. package/dist/scripts/sf-project-setup.mjs +103 -0
  208. package/dist/scripts/soql/account.soql +6 -0
  209. package/dist/scripts/validate-org-setup-config.mjs +38 -0
  210. package/dist/sfdx-project.json +12 -0
  211. package/package.json +40 -0
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Copyright (c) 2026, Salesforce, Inc.,
3
+ * All rights reserved.
4
+ * For full license text, see the LICENSE.txt file
5
+ */
6
+ import { ChangeDetectionStrategy, Component, inject, signal } from "@angular/core";
7
+ import { FormBuilder } from "@angular/forms";
8
+ import { ActivatedRoute, Router, RouterLink } from "@angular/router";
9
+ import { DataClient } from "../../api/data-client.service";
10
+ import { AuthFormComponent } from "../../features/authentication/forms/auth-form/auth-form.component";
11
+ import { ReactiveFormPageBase } from "../../features/authentication/forms/reactive-form-page.base";
12
+ import { FieldComponent } from "../../components/ui/field/field.component";
13
+ import { InputComponent } from "../../components/ui/input/input.component";
14
+ import {
15
+ API_ROUTES,
16
+ AUTH_PLACEHOLDERS,
17
+ ROUTES,
18
+ } from "../../features/authentication/config/authentication.config";
19
+ import { getStartUrl, type AuthResponse } from "../../features/authentication/utils/auth-helpers";
20
+ import { ApiError, handleApiResponse } from "../../features/authentication/utils/helpers";
21
+ import {
22
+ emailValidator,
23
+ requiredWithMessage,
24
+ } from "../../features/authentication/utils/auth-validators";
25
+
26
+ /**
27
+ * Login page — Angular port of the React `Login`. Reactive Forms replace
28
+ * `@tanstack/react-form` + zod; the login POST + redirect logic is identical.
29
+ * On success with a `redirectUrl` it hard-navigates (establishes the server
30
+ * session cookie); otherwise it client-navigates to `/`.
31
+ */
32
+ @Component({
33
+ selector: "app-login-page",
34
+ changeDetection: ChangeDetectionStrategy.OnPush,
35
+ imports: [RouterLink, AuthFormComponent, FieldComponent, InputComponent],
36
+ templateUrl: "./login-page.component.html",
37
+ })
38
+ export class LoginPageComponent extends ReactiveFormPageBase {
39
+ private readonly fb = inject(FormBuilder);
40
+ private readonly router = inject(Router);
41
+ private readonly route = inject(ActivatedRoute);
42
+ private readonly dataClient = inject(DataClient);
43
+
44
+ protected readonly placeholders = AUTH_PLACEHOLDERS;
45
+ protected readonly routes = ROUTES;
46
+
47
+ protected override readonly form = this.fb.group({
48
+ email: ["", [emailValidator]],
49
+ password: ["", [requiredWithMessage("Password is required")]],
50
+ });
51
+
52
+ protected readonly submitError = signal<string | string[] | null>(null);
53
+ protected readonly submitting = signal<boolean>(false);
54
+
55
+ protected async onSubmit(): Promise<void> {
56
+ this.form.markAllAsTouched();
57
+ if (this.form.invalid) {
58
+ return;
59
+ }
60
+ this.submitError.set(null);
61
+ this.submitting.set(true);
62
+ try {
63
+ const { email, password } = this.form.getRawValue();
64
+ const startUrl = getStartUrl(this.route.snapshot.queryParamMap);
65
+ const response = await this.dataClient.fetch(API_ROUTES.LOGIN, {
66
+ method: "POST",
67
+ body: JSON.stringify({
68
+ email: (email ?? "").trim().toLowerCase(),
69
+ password: password ?? "",
70
+ startUrl,
71
+ }),
72
+ headers: { "Content-Type": "application/json", Accept: "application/json" },
73
+ });
74
+ const result = await handleApiResponse<AuthResponse>(response);
75
+ if (result?.redirectUrl) {
76
+ // Hard navigate to the URL which establishes the server session cookie.
77
+ window.location.replace(result.redirectUrl);
78
+ } else {
79
+ // In case redirectUrl is null, navigate to home.
80
+ void this.router.navigate(["/"], { replaceUrl: true });
81
+ }
82
+ } catch (err) {
83
+ console.error("Login failed", err);
84
+ this.submitError.set(err instanceof ApiError ? err.errors : "Login failed");
85
+ } finally {
86
+ this.submitting.set(false);
87
+ }
88
+ }
89
+ }
@@ -0,0 +1,12 @@
1
+ <main class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
2
+ <div class="text-center">
3
+ <h1 class="text-4xl font-bold text-gray-900 mb-4">404</h1>
4
+ <p class="text-lg text-gray-600 mb-8">Page not found</p>
5
+ <a
6
+ routerLink="/"
7
+ class="inline-block px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition-colors"
8
+ >
9
+ Go to Home
10
+ </a>
11
+ </div>
12
+ </main>
@@ -0,0 +1,33 @@
1
+ import { TestBed } from '@angular/core/testing';
2
+ import { provideRouter } from '@angular/router';
3
+ import { NotFoundComponent } from './not-found.component';
4
+
5
+ describe('NotFoundComponent', () => {
6
+ beforeEach(async () => {
7
+ await TestBed.configureTestingModule({
8
+ imports: [NotFoundComponent],
9
+ providers: [provideRouter([])],
10
+ }).compileComponents();
11
+ });
12
+
13
+ it('should create the component', () => {
14
+ const fixture = TestBed.createComponent(NotFoundComponent);
15
+ const component = fixture.componentInstance;
16
+ expect(component).toBeTruthy();
17
+ });
18
+
19
+ it('should render main landmark', async () => {
20
+ const fixture = TestBed.createComponent(NotFoundComponent);
21
+ await fixture.whenStable();
22
+ const compiled = fixture.nativeElement as HTMLElement;
23
+ expect(compiled.querySelector('main')).toBeTruthy();
24
+ });
25
+
26
+ it('should have a link to home', async () => {
27
+ const fixture = TestBed.createComponent(NotFoundComponent);
28
+ await fixture.whenStable();
29
+ const compiled = fixture.nativeElement as HTMLElement;
30
+ const link = compiled.querySelector('a');
31
+ expect(link?.getAttribute('href')).toBe('/');
32
+ });
33
+ });
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Copyright (c) 2026, Salesforce, Inc.,
3
+ * All rights reserved.
4
+ * For full license text, see the LICENSE.txt file
5
+ */
6
+ import { ChangeDetectionStrategy, Component } from '@angular/core';
7
+ import { RouterLink } from '@angular/router';
8
+
9
+ @Component({
10
+ selector: 'app-not-found',
11
+ changeDetection: ChangeDetectionStrategy.OnPush,
12
+ imports: [RouterLink],
13
+ templateUrl: './not-found.component.html',
14
+ })
15
+ export class NotFoundComponent {}
@@ -0,0 +1,126 @@
1
+ <main class="flex min-h-svh w-full justify-center p-6 md:p-10 items-start">
2
+ <div class="w-full max-w-md">
3
+ @if (loadError()) {
4
+ <app-status-alert variant="error" [message]="loadError()!" />
5
+ } @else {
6
+ <app-auth-form
7
+ title="Profile"
8
+ description="Update your account information"
9
+ [showAlreadyLoggedIn]="false"
10
+ [error]="submitError()"
11
+ [success]="success() ? 'Profile updated!' : null"
12
+ submitText="Save Changes"
13
+ submitLoadingText="Saving…"
14
+ [submitting]="submitting()"
15
+ [submitDisabled]="loading()"
16
+ [footer]="{ link: routes.CHANGE_PASSWORD.PATH, linkText: 'Change password' }"
17
+ (submitted)="onSubmit()"
18
+ >
19
+ @if (loading()) {
20
+ <div role="status" aria-live="polite">
21
+ <span class="sr-only">Loading profile…</span>
22
+ <app-field label="Email"><app-skeleton class="h-9 w-full rounded-md" /></app-field>
23
+ <div class="grid grid-cols-1 gap-4 sm:grid-cols-2 items-start">
24
+ <app-field label="First name"
25
+ ><app-skeleton class="h-9 w-full rounded-md"
26
+ /></app-field>
27
+ <app-field label="Last name"
28
+ ><app-skeleton class="h-9 w-full rounded-md"
29
+ /></app-field>
30
+ </div>
31
+ <app-field label="Phone"><app-skeleton class="h-9 w-full rounded-md" /></app-field>
32
+ <app-field label="Street"><app-skeleton class="h-9 w-full rounded-md" /></app-field>
33
+ <div class="grid grid-cols-1 gap-4 sm:grid-cols-2 items-start">
34
+ <app-field label="City"><app-skeleton class="h-9 w-full rounded-md" /></app-field>
35
+ <app-field label="State"><app-skeleton class="h-9 w-full rounded-md" /></app-field>
36
+ </div>
37
+ <div class="grid grid-cols-1 gap-4 sm:grid-cols-2 items-start">
38
+ <app-field label="Postal Code"
39
+ ><app-skeleton class="h-9 w-full rounded-md"
40
+ /></app-field>
41
+ <app-field label="Country"><app-skeleton class="h-9 w-full rounded-md" /></app-field>
42
+ </div>
43
+ </div>
44
+ } @else {
45
+ <div class="mt-4 flex flex-col gap-4">
46
+ <app-field
47
+ label="Email"
48
+ htmlFor="profile-email"
49
+ [error]="controlError('Email', 'email')"
50
+ >
51
+ <app-input type="email" [value]="form.controls.Email.value ?? ''" [disabled]="true" />
52
+ </app-field>
53
+
54
+ <div class="grid grid-cols-1 gap-4 sm:grid-cols-2 items-start">
55
+ <app-field
56
+ label="First name"
57
+ htmlFor="profile-first-name"
58
+ [error]="controlError('FirstName', 'required')"
59
+ >
60
+ <app-input
61
+ [value]="form.controls.FirstName.value ?? ''"
62
+ (valueChange)="setControl('FirstName', $event)"
63
+ />
64
+ </app-field>
65
+ <app-field
66
+ label="Last name"
67
+ htmlFor="profile-last-name"
68
+ [error]="controlError('LastName', 'required')"
69
+ >
70
+ <app-input
71
+ [value]="form.controls.LastName.value ?? ''"
72
+ (valueChange)="setControl('LastName', $event)"
73
+ />
74
+ </app-field>
75
+ </div>
76
+
77
+ <app-field label="Phone" htmlFor="profile-phone">
78
+ <app-input
79
+ type="tel"
80
+ [value]="form.controls.Phone.value ?? ''"
81
+ (valueChange)="setControl('Phone', $event)"
82
+ />
83
+ </app-field>
84
+
85
+ <app-field label="Street" htmlFor="profile-street">
86
+ <app-input
87
+ [value]="form.controls.Street.value ?? ''"
88
+ (valueChange)="setControl('Street', $event)"
89
+ />
90
+ </app-field>
91
+
92
+ <div class="grid grid-cols-1 gap-4 sm:grid-cols-2 items-start">
93
+ <app-field label="City" htmlFor="profile-city">
94
+ <app-input
95
+ [value]="form.controls.City.value ?? ''"
96
+ (valueChange)="setControl('City', $event)"
97
+ />
98
+ </app-field>
99
+ <app-field label="State" htmlFor="profile-state">
100
+ <app-input
101
+ [value]="form.controls.State.value ?? ''"
102
+ (valueChange)="setControl('State', $event)"
103
+ />
104
+ </app-field>
105
+ </div>
106
+
107
+ <div class="grid grid-cols-1 gap-4 sm:grid-cols-2 items-start">
108
+ <app-field label="Postal Code" htmlFor="profile-postal-code">
109
+ <app-input
110
+ [value]="form.controls.PostalCode.value ?? ''"
111
+ (valueChange)="setControl('PostalCode', $event)"
112
+ />
113
+ </app-field>
114
+ <app-field label="Country" htmlFor="profile-country">
115
+ <app-input
116
+ [value]="form.controls.Country.value ?? ''"
117
+ (valueChange)="setControl('Country', $event)"
118
+ />
119
+ </app-field>
120
+ </div>
121
+ </div>
122
+ }
123
+ </app-auth-form>
124
+ }
125
+ </div>
126
+ </main>
@@ -0,0 +1,194 @@
1
+ /**
2
+ * Copyright (c) 2026, Salesforce, Inc.,
3
+ * All rights reserved.
4
+ * For full license text, see the LICENSE.txt file
5
+ */
6
+ import {
7
+ ChangeDetectionStrategy,
8
+ Component,
9
+ computed,
10
+ inject,
11
+ OnInit,
12
+ signal,
13
+ } from "@angular/core";
14
+ import { FormBuilder } from "@angular/forms";
15
+ import { AuthFormComponent } from "../../features/authentication/forms/auth-form/auth-form.component";
16
+ import { ReactiveFormPageBase } from "../../features/authentication/forms/reactive-form-page.base";
17
+ import { StatusAlertComponent } from "../../features/authentication/components/status-alert/status-alert.component";
18
+ import { FieldComponent } from "../../components/ui/field/field.component";
19
+ import { InputComponent } from "../../components/ui/input/input.component";
20
+ import { SkeletonComponent } from "../../components/ui/skeleton/skeleton.component";
21
+ import { AuthService } from "../../features/authentication/auth/auth.service";
22
+ import { UserProfileService } from "../../api/user-profile.service";
23
+ import { ROUTES } from "../../features/authentication/config/authentication.config";
24
+ import {
25
+ emailValidator,
26
+ requiredWithMessage,
27
+ } from "../../features/authentication/utils/auth-validators";
28
+
29
+ /**
30
+ * The profile form value shape (mirrors the React `ProfileFormValues`).
31
+ *
32
+ * Declared as a `type` (not an `interface`) so it is assignable to
33
+ * `Record<string, unknown>` when passed to `UserProfileService.updateUserProfile`:
34
+ * an interface is not index-signature-assignable (it can be augmented via
35
+ * declaration merging), whereas a type-literal is.
36
+ */
37
+ type ProfileFormValues = {
38
+ FirstName: string;
39
+ LastName: string;
40
+ Email: string;
41
+ Phone: string | null;
42
+ Street: string | null;
43
+ City: string | null;
44
+ State: string | null;
45
+ PostalCode: string | null;
46
+ Country: string | null;
47
+ };
48
+
49
+ /**
50
+ * Profile page — Angular port of the React `Profile`. Protected route.
51
+ *
52
+ * Loads the current user's profile via GraphQL (`UserProfileService`) on init,
53
+ * showing a skeleton while loading. Email is read-only. On submit it updates
54
+ * via GraphQL and merges the returned record with the submitted values so
55
+ * FLS-hidden fields don't blank the form — identical to the React merge logic.
56
+ * `showAlreadyLoggedIn` is false.
57
+ */
58
+ @Component({
59
+ selector: "app-profile-page",
60
+ changeDetection: ChangeDetectionStrategy.OnPush,
61
+ imports: [
62
+ AuthFormComponent,
63
+ StatusAlertComponent,
64
+ FieldComponent,
65
+ InputComponent,
66
+ SkeletonComponent,
67
+ ],
68
+ templateUrl: "./profile-page.component.html",
69
+ })
70
+ export class ProfilePageComponent extends ReactiveFormPageBase implements OnInit {
71
+ private readonly fb = inject(FormBuilder);
72
+ private readonly authService = inject(AuthService);
73
+ private readonly profileService = inject(UserProfileService);
74
+
75
+ protected readonly routes = ROUTES;
76
+ private readonly user = this.authService.requireUser();
77
+
78
+ protected override readonly form = this.fb.group({
79
+ FirstName: ["", [requiredWithMessage("First name is required")]],
80
+ LastName: ["", [requiredWithMessage("Last name is required")]],
81
+ Email: [{ value: "", disabled: true }, [emailValidator]],
82
+ Phone: [""],
83
+ Street: [""],
84
+ City: [""],
85
+ State: [""],
86
+ PostalCode: [""],
87
+ Country: [""],
88
+ });
89
+
90
+ protected readonly loadError = signal<string | null>(null);
91
+ protected readonly submitError = signal<string | null>(null);
92
+ protected readonly submitting = signal<boolean>(false);
93
+ protected readonly success = signal<boolean>(false);
94
+ private readonly loaded = signal<boolean>(false);
95
+
96
+ /** True until the profile has loaded and no load error occurred. */
97
+ protected readonly loading = computed(() => !this.loaded() && this.loadError() === null);
98
+
99
+ ngOnInit(): void {
100
+ void this.loadProfile();
101
+ }
102
+
103
+ private async loadProfile(): Promise<void> {
104
+ try {
105
+ const data = await this.profileService.fetchUserProfile<Partial<ProfileFormValues>>(
106
+ this.user.id,
107
+ );
108
+ // Merge with defaults so missing fields (e.g. due to FLS) don't break the form.
109
+ this.applyProfile({
110
+ FirstName: data.FirstName ?? "",
111
+ LastName: data.LastName ?? "",
112
+ Email: data.Email ?? "",
113
+ Phone: data.Phone ?? null,
114
+ Street: data.Street ?? null,
115
+ City: data.City ?? null,
116
+ State: data.State ?? null,
117
+ PostalCode: data.PostalCode ?? null,
118
+ Country: data.Country ?? null,
119
+ });
120
+ this.loaded.set(true);
121
+ } catch (err) {
122
+ console.error("Failed to load profile", err);
123
+ this.loadError.set("Failed to load profile");
124
+ }
125
+ }
126
+
127
+ private applyProfile(profile: ProfileFormValues): void {
128
+ this.form.reset({
129
+ FirstName: profile.FirstName,
130
+ LastName: profile.LastName,
131
+ Email: profile.Email,
132
+ Phone: profile.Phone ?? "",
133
+ Street: profile.Street ?? "",
134
+ City: profile.City ?? "",
135
+ State: profile.State ?? "",
136
+ PostalCode: profile.PostalCode ?? "",
137
+ Country: profile.Country ?? "",
138
+ });
139
+ }
140
+
141
+ protected async onSubmit(): Promise<void> {
142
+ this.form.markAllAsTouched();
143
+ if (this.form.invalid) {
144
+ return;
145
+ }
146
+ this.submitError.set(null);
147
+ this.success.set(false);
148
+ this.submitting.set(true);
149
+ try {
150
+ // getRawValue includes the disabled Email control.
151
+ const raw = this.form.getRawValue();
152
+ const value: ProfileFormValues = {
153
+ FirstName: (raw.FirstName ?? "").trim(),
154
+ LastName: (raw.LastName ?? "").trim(),
155
+ Email: (raw.Email ?? "").trim(),
156
+ Phone: this.optional(raw.Phone),
157
+ Street: this.optional(raw.Street),
158
+ City: this.optional(raw.City),
159
+ State: this.optional(raw.State),
160
+ PostalCode: this.optional(raw.PostalCode),
161
+ Country: this.optional(raw.Country),
162
+ };
163
+ const updated = await this.profileService.updateUserProfile<Partial<ProfileFormValues>>(
164
+ this.user.id,
165
+ value,
166
+ );
167
+ // Merge with submitted values so missing fields (e.g. FLS) don't break the form.
168
+ this.applyProfile({
169
+ FirstName: updated.FirstName ?? value.FirstName ?? "",
170
+ LastName: updated.LastName ?? value.LastName ?? "",
171
+ Email: updated.Email ?? value.Email ?? "",
172
+ Phone: updated.Phone ?? value.Phone ?? null,
173
+ Street: updated.Street ?? value.Street ?? null,
174
+ City: updated.City ?? value.City ?? null,
175
+ State: updated.State ?? value.State ?? null,
176
+ PostalCode: updated.PostalCode ?? value.PostalCode ?? null,
177
+ Country: updated.Country ?? value.Country ?? null,
178
+ });
179
+ this.success.set(true);
180
+ window.scrollTo({ top: 0, behavior: "smooth" });
181
+ } catch (err) {
182
+ console.error("Failed to update profile", err);
183
+ this.submitError.set("Failed to update profile");
184
+ } finally {
185
+ this.submitting.set(false);
186
+ }
187
+ }
188
+
189
+ /** Mirrors the React `optionalString`: trim and coerce empty to null. */
190
+ private optional(value: string | null | undefined): string | null {
191
+ const trimmed = (value ?? "").trim();
192
+ return trimmed === "" ? null : trimmed;
193
+ }
194
+ }
@@ -0,0 +1,80 @@
1
+ <main class="flex min-h-svh w-full justify-center p-6 md:p-10 items-start">
2
+ <div class="w-full max-w-2xl">
3
+ <app-auth-form
4
+ title="Sign Up"
5
+ description="Enter your information to create an account"
6
+ [error]="submitError()"
7
+ submitText="Create an account"
8
+ submitLoadingText="Creating account…"
9
+ [submitting]="submitting()"
10
+ [footer]="{ text: 'Already have an account?', link: routes.LOGIN.PATH, linkText: 'Sign in' }"
11
+ (submitted)="onSubmit()"
12
+ >
13
+ <div class="mt-4 flex flex-col gap-4">
14
+ <div class="grid grid-cols-1 gap-4 sm:grid-cols-2 items-start">
15
+ <app-field
16
+ label="First name"
17
+ htmlFor="register-first-name"
18
+ [error]="controlError('firstName', 'required')"
19
+ >
20
+ <app-input
21
+ [value]="form.controls.firstName.value ?? ''"
22
+ (valueChange)="setControl('firstName', $event)"
23
+ [placeholder]="placeholders.FIRST_NAME"
24
+ />
25
+ </app-field>
26
+
27
+ <app-field
28
+ label="Last name"
29
+ htmlFor="register-last-name"
30
+ [error]="controlError('lastName', 'required')"
31
+ >
32
+ <app-input
33
+ [value]="form.controls.lastName.value ?? ''"
34
+ (valueChange)="setControl('lastName', $event)"
35
+ [placeholder]="placeholders.LAST_NAME"
36
+ />
37
+ </app-field>
38
+ </div>
39
+
40
+ <app-field label="Email" htmlFor="register-email" [error]="controlError('email', 'email')">
41
+ <app-input
42
+ type="email"
43
+ [value]="form.controls.email.value ?? ''"
44
+ (valueChange)="setControl('email', $event)"
45
+ [placeholder]="placeholders.EMAIL"
46
+ />
47
+ </app-field>
48
+
49
+ <app-field
50
+ label="Password"
51
+ htmlFor="register-password"
52
+ [error]="controlError('password', 'password')"
53
+ >
54
+ <app-input
55
+ type="password"
56
+ [value]="form.controls.password.value ?? ''"
57
+ (valueChange)="setControl('password', $event)"
58
+ [placeholder]="placeholders.PASSWORD_CREATE"
59
+ />
60
+ </app-field>
61
+
62
+ <app-field
63
+ label="Confirm Password"
64
+ htmlFor="register-confirm-password"
65
+ [error]="
66
+ controlError('confirmPassword', 'passwordMismatch') ??
67
+ controlError('confirmPassword', 'required')
68
+ "
69
+ >
70
+ <app-input
71
+ type="password"
72
+ [value]="form.controls.confirmPassword.value ?? ''"
73
+ (valueChange)="setControl('confirmPassword', $event)"
74
+ [placeholder]="placeholders.PASSWORD_CONFIRM"
75
+ />
76
+ </app-field>
77
+ </div>
78
+ </app-auth-form>
79
+ </div>
80
+ </main>
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Copyright (c) 2026, Salesforce, Inc.,
3
+ * All rights reserved.
4
+ * For full license text, see the LICENSE.txt file
5
+ */
6
+ import { ChangeDetectionStrategy, Component, inject, signal } from "@angular/core";
7
+ import { FormBuilder } from "@angular/forms";
8
+ import { ActivatedRoute, Router } from "@angular/router";
9
+ import { DataClient } from "../../api/data-client.service";
10
+ import { AuthFormComponent } from "../../features/authentication/forms/auth-form/auth-form.component";
11
+ import { ReactiveFormPageBase } from "../../features/authentication/forms/reactive-form-page.base";
12
+ import { FieldComponent } from "../../components/ui/field/field.component";
13
+ import { InputComponent } from "../../components/ui/input/input.component";
14
+ import {
15
+ API_ROUTES,
16
+ AUTH_PLACEHOLDERS,
17
+ ROUTES,
18
+ } from "../../features/authentication/config/authentication.config";
19
+ import { getStartUrl, type AuthResponse } from "../../features/authentication/utils/auth-helpers";
20
+ import { ApiError, handleApiResponse } from "../../features/authentication/utils/helpers";
21
+ import {
22
+ emailValidator,
23
+ passwordMinValidator,
24
+ passwordsMatchValidator,
25
+ requiredWithMessage,
26
+ } from "../../features/authentication/utils/auth-validators";
27
+
28
+ /**
29
+ * Register page — Angular port of the React `Register`. Same field set, same
30
+ * cross-field password-match rule, same POST body shape (`{ request }` with
31
+ * `confirmPassword` stripped) and same success handling (redirectUrl hard-nav,
32
+ * else navigate to login).
33
+ */
34
+ @Component({
35
+ selector: "app-register-page",
36
+ changeDetection: ChangeDetectionStrategy.OnPush,
37
+ imports: [AuthFormComponent, FieldComponent, InputComponent],
38
+ templateUrl: "./register-page.component.html",
39
+ })
40
+ export class RegisterPageComponent extends ReactiveFormPageBase {
41
+ private readonly fb = inject(FormBuilder);
42
+ private readonly router = inject(Router);
43
+ private readonly route = inject(ActivatedRoute);
44
+ private readonly dataClient = inject(DataClient);
45
+
46
+ protected readonly placeholders = AUTH_PLACEHOLDERS;
47
+ protected readonly routes = ROUTES;
48
+
49
+ protected override readonly form = this.fb.group(
50
+ {
51
+ firstName: ["", [requiredWithMessage("First name is required")]],
52
+ lastName: ["", [requiredWithMessage("Last name is required")]],
53
+ email: ["", [emailValidator]],
54
+ password: ["", [passwordMinValidator]],
55
+ confirmPassword: ["", [requiredWithMessage("Please confirm your password")]],
56
+ startUrl: [getStartUrl(this.route.snapshot.queryParamMap) || ""],
57
+ },
58
+ { validators: [passwordsMatchValidator("password", "confirmPassword")] },
59
+ );
60
+
61
+ protected readonly submitError = signal<string | string[] | null>(null);
62
+ protected readonly submitting = signal<boolean>(false);
63
+
64
+ protected async onSubmit(): Promise<void> {
65
+ this.form.markAllAsTouched();
66
+ if (this.form.invalid) {
67
+ return;
68
+ }
69
+ this.submitError.set(null);
70
+ this.submitting.set(true);
71
+ try {
72
+ const { confirmPassword: _confirmPassword, ...request } = this.form.getRawValue();
73
+ const response = await this.dataClient.fetch(API_ROUTES.REGISTER, {
74
+ method: "POST",
75
+ body: JSON.stringify({ request }),
76
+ headers: { "Content-Type": "application/json", Accept: "application/json" },
77
+ });
78
+ const result = await handleApiResponse<AuthResponse>(response);
79
+ if (result?.redirectUrl) {
80
+ // Hard navigate to the URL which logs the new user in.
81
+ window.location.replace(result.redirectUrl);
82
+ } else {
83
+ // In case redirectUrl is null, redirect to the login page.
84
+ void this.router.navigate([ROUTES.LOGIN.PATH], { replaceUrl: true });
85
+ }
86
+ } catch (err) {
87
+ console.error("Registration failed", err);
88
+ this.submitError.set(err instanceof ApiError ? err.errors : "Registration failed");
89
+ } finally {
90
+ this.submitting.set(false);
91
+ }
92
+ }
93
+ }