saafe-redirection-flow 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (225) hide show
  1. package/.github/workflows/build-and-deploy.yml +41 -0
  2. package/.gitlab-ci.yml +108 -0
  3. package/.releaserc.json +18 -0
  4. package/.storybook/main.ts +28 -0
  5. package/.storybook/preview.ts +16 -0
  6. package/.storybook/vitest.setup.ts +9 -0
  7. package/.vite/deps/@radix-ui_react-avatar.js +230 -0
  8. package/.vite/deps/@radix-ui_react-avatar.js.map +7 -0
  9. package/.vite/deps/@radix-ui_react-slot.js +12 -0
  10. package/.vite/deps/@radix-ui_react-slot.js.map +7 -0
  11. package/.vite/deps/_metadata.json +79 -0
  12. package/.vite/deps/chunk-5VGQBUCU.js +597 -0
  13. package/.vite/deps/chunk-5VGQBUCU.js.map +7 -0
  14. package/.vite/deps/chunk-DC5AMYBS.js +38 -0
  15. package/.vite/deps/chunk-DC5AMYBS.js.map +7 -0
  16. package/.vite/deps/chunk-HUIEPYH7.js +11265 -0
  17. package/.vite/deps/chunk-HUIEPYH7.js.map +7 -0
  18. package/.vite/deps/chunk-TKHB4QMX.js +281 -0
  19. package/.vite/deps/chunk-TKHB4QMX.js.map +7 -0
  20. package/.vite/deps/chunk-YLDSBLSF.js +1139 -0
  21. package/.vite/deps/chunk-YLDSBLSF.js.map +7 -0
  22. package/.vite/deps/class-variance-authority.js +63 -0
  23. package/.vite/deps/class-variance-authority.js.map +7 -0
  24. package/.vite/deps/lucide-react.js +36984 -0
  25. package/.vite/deps/lucide-react.js.map +7 -0
  26. package/.vite/deps/package.json +3 -0
  27. package/.vite/deps/react-dom_client.js +17917 -0
  28. package/.vite/deps/react-dom_client.js.map +7 -0
  29. package/.vite/deps/react-router-dom.js +452 -0
  30. package/.vite/deps/react-router-dom.js.map +7 -0
  31. package/.vite/deps/react-router.js +234 -0
  32. package/.vite/deps/react-router.js.map +7 -0
  33. package/.vite/deps/react.js +5 -0
  34. package/.vite/deps/react.js.map +7 -0
  35. package/.vite/deps/react_jsx-dev-runtime.js +470 -0
  36. package/.vite/deps/react_jsx-dev-runtime.js.map +7 -0
  37. package/CHANGELOG.md +420 -0
  38. package/LICENSE +21 -0
  39. package/README.md +129 -0
  40. package/RELEASE_CHEATSHEET.md +93 -0
  41. package/RELEASE_NOTES.md +120 -0
  42. package/components.json +21 -0
  43. package/docs/DEPLOYMENT_WORKFLOW.md +262 -0
  44. package/docs/RELEASE_GUIDE.md +591 -0
  45. package/docs/architecture.md +432 -0
  46. package/docs/components.md +199 -0
  47. package/docs/index.md +69 -0
  48. package/docs/local-release-workflow.md +234 -0
  49. package/docs/routes.md +118 -0
  50. package/docs/sdk-integration.md +325 -0
  51. package/docs/semantic-release.md +124 -0
  52. package/docs/user-flow.md +206 -0
  53. package/eslint.config.js +28 -0
  54. package/index.html +19 -0
  55. package/install.sh +198 -0
  56. package/package.json +115 -0
  57. package/public/images/bank-logo.png +0 -0
  58. package/public/saafe-icon.svg +9 -0
  59. package/src/App.tsx +171 -0
  60. package/src/__tests__/url-parameters.test.ts +82 -0
  61. package/src/assets/brand/applestore.svg +13 -0
  62. package/src/assets/brand/playstore.svg +23 -0
  63. package/src/assets/brand/saafe-color-white-logo.svg +14 -0
  64. package/src/assets/brand/saafe-icon.svg +9 -0
  65. package/src/assets/brand/saafe-logo.svg +18 -0
  66. package/src/assets/icons/check-icon-dark.svg +27 -0
  67. package/src/assets/icons/check-icon.svg +23 -0
  68. package/src/components/ErrorBoundary.tsx +132 -0
  69. package/src/components/alert/alert.tsx +27 -0
  70. package/src/components/auth/AuthGuard.tsx +76 -0
  71. package/src/components/cards/BankCard.stories.tsx +69 -0
  72. package/src/components/cards/BankCard.tsx +227 -0
  73. package/src/components/cards/OuterCard.tsx +109 -0
  74. package/src/components/cards/WrapperCard.tsx +64 -0
  75. package/src/components/documents/PrivacyContent.tsx +1 -0
  76. package/src/components/dummyFooter.tsx +29 -0
  77. package/src/components/icons/github.tsx +12 -0
  78. package/src/components/language/LanguageSwitcher.tsx +44 -0
  79. package/src/components/layouts/FrostedLayout.stories.tsx +42 -0
  80. package/src/components/layouts/FrostedLayout.tsx +333 -0
  81. package/src/components/layouts/MobileLayout.tsx +403 -0
  82. package/src/components/mobile-background.tsx +136 -0
  83. package/src/components/mobileAppDownload.tsx +30 -0
  84. package/src/components/modal/ModalComp.tsx +27 -0
  85. package/src/components/mode-toggle.tsx +36 -0
  86. package/src/components/page-header.tsx +50 -0
  87. package/src/components/session/SessionTimeoutScreen.tsx +134 -0
  88. package/src/components/session/SessionTimer.tsx +173 -0
  89. package/src/components/step-navigation.tsx +87 -0
  90. package/src/components/title/AppBar.stories.tsx +50 -0
  91. package/src/components/title/AppBar.tsx +150 -0
  92. package/src/components/title/SectionTitle.tsx +31 -0
  93. package/src/components/ui/AnimatedButton.module.css +13 -0
  94. package/src/components/ui/alert.tsx +66 -0
  95. package/src/components/ui/animatedButton.tsx +111 -0
  96. package/src/components/ui/avatar.tsx +51 -0
  97. package/src/components/ui/badge.tsx +36 -0
  98. package/src/components/ui/bottom-sheet.tsx +122 -0
  99. package/src/components/ui/button.tsx +59 -0
  100. package/src/components/ui/calendar.tsx +86 -0
  101. package/src/components/ui/card.tsx +92 -0
  102. package/src/components/ui/checkbox.stories.tsx +49 -0
  103. package/src/components/ui/checkbox.tsx +67 -0
  104. package/src/components/ui/collapsible.tsx +45 -0
  105. package/src/components/ui/dialog.tsx +134 -0
  106. package/src/components/ui/document-link.tsx +26 -0
  107. package/src/components/ui/dot-stepper.tsx +57 -0
  108. package/src/components/ui/dropdown-menu.tsx +255 -0
  109. package/src/components/ui/form.tsx +165 -0
  110. package/src/components/ui/frosted-panel.stories.tsx +86 -0
  111. package/src/components/ui/frosted-panel.tsx +276 -0
  112. package/src/components/ui/input.tsx +39 -0
  113. package/src/components/ui/label.stories.tsx +67 -0
  114. package/src/components/ui/label.tsx +23 -0
  115. package/src/components/ui/mobile-footer.tsx +54 -0
  116. package/src/components/ui/modal.tsx +90 -0
  117. package/src/components/ui/otp-input.stories.tsx +62 -0
  118. package/src/components/ui/otp-input.tsx +221 -0
  119. package/src/components/ui/platform-specific-behavior.tsx +28 -0
  120. package/src/components/ui/popover.tsx +46 -0
  121. package/src/components/ui/progress.tsx +103 -0
  122. package/src/components/ui/radio-group.tsx +45 -0
  123. package/src/components/ui/scroll-area.tsx +56 -0
  124. package/src/components/ui/sdk-params-docs.tsx +53 -0
  125. package/src/components/ui/select.tsx +159 -0
  126. package/src/components/ui/separator.tsx +28 -0
  127. package/src/components/ui/sheet.tsx +137 -0
  128. package/src/components/ui/sidebar.tsx +724 -0
  129. package/src/components/ui/skeleton.stories.tsx +50 -0
  130. package/src/components/ui/skeleton.tsx +15 -0
  131. package/src/components/ui/sonner.tsx +23 -0
  132. package/src/components/ui/step.stories.tsx +132 -0
  133. package/src/components/ui/step.tsx +234 -0
  134. package/src/components/ui/stepper-progress.tsx +136 -0
  135. package/src/components/ui/stepper.tsx +259 -0
  136. package/src/components/ui/tabs.tsx +55 -0
  137. package/src/components/ui/tooltip.tsx +61 -0
  138. package/src/components/ui/url-decode-loader.tsx +36 -0
  139. package/src/components/ui/version-display.tsx +104 -0
  140. package/src/components/ui/web-footer.tsx +36 -0
  141. package/src/config/environments.ts +99 -0
  142. package/src/config/urls.ts +53 -0
  143. package/src/const/fiTypeCategoryMap.ts +19 -0
  144. package/src/contexts/LanguageContext.tsx +41 -0
  145. package/src/contexts/RTLContext.tsx +42 -0
  146. package/src/contexts/ThemeContext.tsx +93 -0
  147. package/src/hooks/use-account-discovery.ts +205 -0
  148. package/src/hooks/use-auth-query.ts +141 -0
  149. package/src/hooks/use-fip-query.ts +72 -0
  150. package/src/hooks/use-media-query.ts +32 -0
  151. package/src/hooks/use-mobile.ts +24 -0
  152. package/src/hooks/use-page-title.tsx +48 -0
  153. package/src/hooks/use-platform.ts +52 -0
  154. package/src/hooks/use-trusted-count.ts +21 -0
  155. package/src/hooks/use-url-decode.ts +90 -0
  156. package/src/hooks/useStep.ts +170 -0
  157. package/src/index.css +154 -0
  158. package/src/interfaces/app.interfaces.ts +39 -0
  159. package/src/interfaces/services.interfaces.ts +65 -0
  160. package/src/lib/i18n.ts +68 -0
  161. package/src/lib/utils.ts +6 -0
  162. package/src/locales/en/common.json +167 -0
  163. package/src/locales/hi/common.json +137 -0
  164. package/src/locales/kn/common.json +137 -0
  165. package/src/locales/ml/common.json +137 -0
  166. package/src/locales/ta/common.json +137 -0
  167. package/src/locales/te/common.json +137 -0
  168. package/src/locales/ur/common.json +138 -0
  169. package/src/main.tsx +46 -0
  170. package/src/pages/Login.tsx +363 -0
  171. package/src/pages/accounts/AccountsToProceed.tsx +396 -0
  172. package/src/pages/accounts/Discover.tsx +76 -0
  173. package/src/pages/accounts/DiscoverAccount.tsx +751 -0
  174. package/src/pages/accounts/LinkSelectedAccounts.tsx +638 -0
  175. package/src/pages/accounts/OldUser.tsx +329 -0
  176. package/src/pages/accounts/link-accounts.tsx +913 -0
  177. package/src/pages/consent/ReviewConsent.tsx +836 -0
  178. package/src/pages/consent/rejected.tsx +253 -0
  179. package/src/pages/consent/success.tsx +220 -0
  180. package/src/providers/query-provider.tsx +24 -0
  181. package/src/providers/toast-provider.tsx +26 -0
  182. package/src/services/api/account.service.ts +296 -0
  183. package/src/services/api/auth.service.ts +206 -0
  184. package/src/services/api/axios.ts +138 -0
  185. package/src/services/api/consent.service.ts +142 -0
  186. package/src/services/api/decode.service.ts +53 -0
  187. package/src/services/api/feedback.service.ts +34 -0
  188. package/src/services/api/fip.service.ts +187 -0
  189. package/src/services/api/index.ts +9 -0
  190. package/src/services/api/public.service.ts +18 -0
  191. package/src/services/api.ts +2 -0
  192. package/src/services/postMessage.service.ts +179 -0
  193. package/src/store/NavigationBlockContext.tsx +34 -0
  194. package/src/store/auth.store.ts +79 -0
  195. package/src/store/fip.store.ts +396 -0
  196. package/src/store/mandatoryConsent.store.ts +24 -0
  197. package/src/store/redirect.store.ts +73 -0
  198. package/src/store/step.store.ts +124 -0
  199. package/src/stories/Button.stories.ts +53 -0
  200. package/src/stories/Button.tsx +37 -0
  201. package/src/stories/Configure.mdx +364 -0
  202. package/src/stories/Header.stories.ts +33 -0
  203. package/src/stories/Header.tsx +56 -0
  204. package/src/stories/Page.stories.ts +32 -0
  205. package/src/stories/Page.tsx +73 -0
  206. package/src/stories/button.css +30 -0
  207. package/src/stories/header.css +32 -0
  208. package/src/stories/page.css +68 -0
  209. package/src/styles/rtl-utils.css +90 -0
  210. package/src/styles/rtl.css +105 -0
  211. package/src/utils/api-error.ts +26 -0
  212. package/src/utils/cn.ts +10 -0
  213. package/src/utils/error-callback.ts +116 -0
  214. package/src/utils/formatAccountNumber.ts +9 -0
  215. package/src/utils/handleIdentifiers.ts +90 -0
  216. package/src/utils/posthog.ts +67 -0
  217. package/src/utils/toast-helpers.ts +61 -0
  218. package/src/vite-env.d.ts +1 -0
  219. package/stage-aa-2506251021.zip +0 -0
  220. package/tsconfig.app.json +33 -0
  221. package/tsconfig.json +13 -0
  222. package/tsconfig.node.json +24 -0
  223. package/vite.config.ts +45 -0
  224. package/vitest.shims.d.ts +1 -0
  225. package/vitest.workspace.ts +46 -0
@@ -0,0 +1,432 @@
1
+ # SAAFE Redirection Flow - Technical Architecture
2
+
3
+ This document outlines the technical architecture of the SAAFE Redirection Flow application, including its structure, state management, and key technical decisions.
4
+
5
+ ## Application Architecture
6
+
7
+ The SAAFE Redirection Flow follows a modern React application architecture with the following key characteristics:
8
+
9
+ - **Component-Based Architecture**: UI elements are broken down into reusable components
10
+ - **Custom Hooks**: Business logic is encapsulated in custom hooks
11
+ - **Context API**: Used for theme management and global state that doesn't require complex updates
12
+ - **Store Management**: Zustand for state that requires more complex updates
13
+ - **Routing**: React Router for navigation between screens
14
+
15
+ ```
16
+ SAAFE Redirection Flow
17
+
18
+ ├── Core
19
+ │ ├── Routing (React Router)
20
+ │ ├── API Integration (Axios + React Query)
21
+ │ └── State Management (Zustand + Context API)
22
+
23
+ ├── Features
24
+ │ ├── Authentication
25
+ │ ├── Account Discovery
26
+ │ ├── Consent Management
27
+ │ └── Platform-Specific Behavior
28
+
29
+ └── UI Layer
30
+ ├── Components
31
+ ├── Pages
32
+ └── Theming
33
+ ```
34
+
35
+ ## Folder Structure
36
+
37
+ The application follows a feature-based folder structure:
38
+
39
+ ```
40
+ src/
41
+ ├── assets/ # Static assets like images and icons
42
+ ├── components/ # Reusable UI components
43
+ │ ├── auth/ # Authentication-related components
44
+ │ ├── ui/ # Base UI components (buttons, inputs, etc.)
45
+ │ └── ...
46
+ ├── config/ # Configuration files and constants
47
+ ├── contexts/ # React context providers
48
+ ├── hooks/ # Custom React hooks
49
+ ├── interfaces/ # TypeScript interfaces and type definitions
50
+ ├── lib/ # Core utilities and helper functions
51
+ ├── locales/ # Internationalization resources
52
+ ├── pages/ # Page components
53
+ │ ├── accounts/ # Account-related pages
54
+ │ ├── consent/ # Consent flow pages
55
+ │ └── ...
56
+ ├── providers/ # Service providers (Query, Toast, etc.)
57
+ ├── services/ # API services
58
+ ├── store/ # Zustand stores
59
+ ├── styles/ # Global styles and theme definitions
60
+ ├── utils/ # Utility functions
61
+ ├── App.tsx # Main app component with routing
62
+ └── main.tsx # Entry point
63
+ ```
64
+
65
+ ## State Management
66
+
67
+ The application uses a hybrid state management approach:
68
+
69
+ ### Local Component State
70
+
71
+ Used for component-specific state that doesn't need to be shared.
72
+
73
+ ```tsx
74
+ function Counter() {
75
+ const [count, setCount] = useState(0);
76
+
77
+ return (
78
+ <button onClick={() => setCount(count + 1)}>
79
+ Count: {count}
80
+ </button>
81
+ );
82
+ }
83
+ ```
84
+
85
+ ### Context API
86
+
87
+ Used for theme management and other global states that don't require complex updates.
88
+
89
+ ```tsx
90
+ // src/contexts/ThemeContext.tsx
91
+ export const ThemeProvider: React.FC<ThemeProviderProps> = ({
92
+ children,
93
+ defaultTheme = "system"
94
+ }) => {
95
+ // Implementation details
96
+
97
+ return (
98
+ <ThemeContext.Provider value={{ theme, setTheme }}>
99
+ {children}
100
+ </ThemeContext.Provider>
101
+ );
102
+ };
103
+ ```
104
+
105
+ ### Zustand Stores
106
+
107
+ Used for more complex state management needs, particularly for data that needs to be accessed across multiple components.
108
+
109
+ ```tsx
110
+ // src/store/redirect.store.ts
111
+ export const useRedirectStore = create<RedirectStore>((set, get) => ({
112
+ decodedInfo: null,
113
+ setDecodedInfo: (info) => set({ decodedInfo: info }),
114
+ getCustomStyle: () => {
115
+ const { decodedInfo } = get();
116
+ if (!decodedInfo?.styleOptions) return null;
117
+ return decodedInfo.styleOptions;
118
+ }
119
+ }));
120
+ ```
121
+
122
+ ## Data Fetching
123
+
124
+ The application uses React Query for data fetching and caching:
125
+
126
+ ```tsx
127
+ // Example of a query hook
128
+ export function useAccounts() {
129
+ const { decodedInfo } = useRedirectStore();
130
+
131
+ return useQuery({
132
+ queryKey: ['accounts', decodedInfo?.userId],
133
+ queryFn: () => fetchAccounts(decodedInfo?.userId),
134
+ enabled: !!decodedInfo?.userId,
135
+ });
136
+ }
137
+ ```
138
+
139
+ ## Routing and Navigation
140
+
141
+ React Router v7 is used for routing, with route protection provided by an `AuthGuard` component:
142
+
143
+ ```tsx
144
+ // Protected route example from App.tsx
145
+ <Route
146
+ path="link-accounts/discovery"
147
+ element={
148
+ <AuthGuard>
149
+ <Discover />
150
+ </AuthGuard>
151
+ }
152
+ />
153
+ ```
154
+
155
+ ## Theming
156
+
157
+ The application supports multiple themes (light, dark, system) using CSS variables and the Context API:
158
+
159
+ ```tsx
160
+ // Theme switching logic
161
+ const switchTheme = (newTheme: Theme) => {
162
+ // Update theme in context
163
+ setTheme(newTheme);
164
+
165
+ // Apply theme to document
166
+ const root = document.documentElement;
167
+ if (newTheme === 'dark' || (newTheme === 'system' && prefersDarkMode)) {
168
+ root.classList.add('dark');
169
+ } else {
170
+ root.classList.remove('dark');
171
+ }
172
+ };
173
+ ```
174
+
175
+ ## Internationalization
176
+
177
+ The application uses i18next for internationalization:
178
+
179
+ ```tsx
180
+ // i18n setup
181
+ import i18n from 'i18next';
182
+ import { initReactI18next } from 'react-i18next';
183
+ import LanguageDetector from 'i18next-browser-languagedetector';
184
+
185
+ i18n
186
+ .use(LanguageDetector)
187
+ .use(initReactI18next)
188
+ .init({
189
+ resources: {
190
+ en: { translation: enTranslation },
191
+ hi: { translation: hiTranslation },
192
+ // other languages...
193
+ },
194
+ fallbackLng: 'en',
195
+ interpolation: {
196
+ escapeValue: false,
197
+ },
198
+ });
199
+ ```
200
+
201
+ ## Form Handling
202
+
203
+ The application uses React Hook Form with Zod validation:
204
+
205
+ ```tsx
206
+ // Form with validation example
207
+ const formSchema = z.object({
208
+ username: z.string().min(3, "Username must be at least 3 characters"),
209
+ password: z.string().min(8, "Password must be at least 8 characters"),
210
+ });
211
+
212
+ function LoginForm() {
213
+ const form = useForm<z.infer<typeof formSchema>>({
214
+ resolver: zodResolver(formSchema),
215
+ defaultValues: {
216
+ username: "",
217
+ password: "",
218
+ },
219
+ });
220
+
221
+ // Form handling logic...
222
+ }
223
+ ```
224
+
225
+ ## Analytics
226
+
227
+ The application integrates with PostHog for analytics:
228
+
229
+ ```tsx
230
+ // Analytics tracking example
231
+ import { trackEvent, EVENTS } from "@/utils/posthog";
232
+
233
+ // In component
234
+ useEffect(() => {
235
+ trackEvent(EVENTS.PAGE_VIEW, {
236
+ page: "login",
237
+ timestamp: new Date().toISOString()
238
+ });
239
+ }, []);
240
+ ```
241
+
242
+ ## Security Features
243
+
244
+ ### URL Parameter Decoding
245
+
246
+ The application securely decodes URL parameters to extract information:
247
+
248
+ ```tsx
249
+ // URL decoding hook
250
+ export function useUrlDecode() {
251
+ const [isLoading, setIsLoading] = useState(true);
252
+ const [isError, setIsError] = useState(false);
253
+ const [error, setError] = useState<Error | null>(null);
254
+ const { setDecodedInfo } = useRedirectStore();
255
+
256
+ useEffect(() => {
257
+ const decodeUrlParams = async () => {
258
+ try {
259
+ // Get URL parameters
260
+ const params = new URLSearchParams(window.location.search);
261
+ const fi = params.get('fi');
262
+ const ecreq = params.get('ecreq');
263
+ const reqdate = params.get('reqdate');
264
+
265
+ // Validate required parameters
266
+ if (!fi || !ecreq || !reqdate) {
267
+ throw new Error('Missing required URL parameters');
268
+ }
269
+
270
+ // Decode encrypted request
271
+ const decodedInfo = await decodeRequest(fi, ecreq, reqdate);
272
+ setDecodedInfo(decodedInfo);
273
+
274
+ } catch (err) {
275
+ setIsError(true);
276
+ setError(err instanceof Error ? err : new Error('Unknown error'));
277
+ } finally {
278
+ setIsLoading(false);
279
+ }
280
+ };
281
+
282
+ decodeUrlParams();
283
+ }, [setDecodedInfo]);
284
+
285
+ return { isLoading, isError, error };
286
+ }
287
+ ```
288
+
289
+ ### Navigation Protection
290
+
291
+ The application prevents accidental navigation away from the flow:
292
+
293
+ ```tsx
294
+ // Navigation block logic
295
+ useEffect(() => {
296
+ const handleBeforeUnload = (e: BeforeUnloadEvent) => {
297
+ e.preventDefault();
298
+ e.returnValue = '';
299
+ };
300
+
301
+ window.addEventListener('beforeunload', handleBeforeUnload);
302
+ return () => {
303
+ window.removeEventListener('beforeunload', handleBeforeUnload);
304
+ };
305
+ }, []);
306
+ ```
307
+
308
+ ## Platform-Specific Behavior
309
+
310
+ The application adapts its behavior based on the platform parameter:
311
+
312
+ ```tsx
313
+ // Platform detection hook
314
+ export function usePlatform() {
315
+ const { decodedInfo } = useRedirectStore();
316
+ const platform = decodedInfo?.platform || 'web';
317
+
318
+ const isNativeSDK = ['ios', 'android', 'react-native', 'flutter'].includes(platform);
319
+
320
+ return {
321
+ platform,
322
+ isNativeSDK,
323
+ isIOS: platform === 'ios',
324
+ isAndroid: platform === 'android',
325
+ isReactNative: platform === 'react-native',
326
+ isFlutter: platform === 'flutter',
327
+ isWeb: platform === 'web',
328
+ };
329
+ }
330
+ ```
331
+
332
+ ## Performance Optimizations
333
+
334
+ ### Code Splitting
335
+
336
+ React's lazy loading is used for code splitting:
337
+
338
+ ```tsx
339
+ // Lazy loaded components
340
+ const ReviewConsent = React.lazy(() => import('./pages/consent/ReviewConsent'));
341
+ const Success = React.lazy(() => import('./pages/consent/success'));
342
+ ```
343
+
344
+ ### Memoization
345
+
346
+ React.memo and useMemo/useCallback are used to prevent unnecessary re-renders:
347
+
348
+ ```tsx
349
+ // Memoized component example
350
+ const MemoizedComponent = React.memo(({ value }) => {
351
+ return <div>{value}</div>;
352
+ });
353
+
354
+ // In parent component
355
+ const handleClick = useCallback(() => {
356
+ // Handle click
357
+ }, []);
358
+
359
+ const computedValue = useMemo(() => {
360
+ return expensiveComputation(value);
361
+ }, [value]);
362
+ ```
363
+
364
+ ## Testing Strategy
365
+
366
+ The application is set up for comprehensive testing:
367
+
368
+ - **Unit Tests**: For individual components and hooks
369
+ - **Integration Tests**: For feature workflows
370
+ - **Visual Tests**: Using Storybook
371
+ - **E2E Tests**: Using Playwright
372
+
373
+ ```tsx
374
+ // Example test
375
+ import { render, screen } from '@testing-library/react';
376
+ import userEvent from '@testing-library/user-event';
377
+ import Button from './Button';
378
+
379
+ test('button calls onClick when clicked', async () => {
380
+ const handleClick = vi.fn();
381
+ render(<Button onClick={handleClick}>Click me</Button>);
382
+
383
+ await userEvent.click(screen.getByText('Click me'));
384
+
385
+ expect(handleClick).toHaveBeenCalledTimes(1);
386
+ });
387
+ ```
388
+
389
+ ## Build and Deployment
390
+
391
+ The application uses Vite for fast development and optimized production builds:
392
+
393
+ ```js
394
+ // vite.config.ts
395
+ import { defineConfig } from 'vite';
396
+ import react from '@vitejs/plugin-react';
397
+
398
+ export default defineConfig({
399
+ plugins: [react()],
400
+ build: {
401
+ minify: 'terser',
402
+ sourcemap: true,
403
+ },
404
+ resolve: {
405
+ alias: {
406
+ '@': '/src',
407
+ },
408
+ },
409
+ });
410
+ ```
411
+
412
+ ## Technical Decisions and Tradeoffs
413
+
414
+ ### Why React Router v7?
415
+
416
+ React Router v7 was chosen for its declarative routing and improved performance over previous versions. The application benefits from nested routes and route-level code splitting.
417
+
418
+ ### Why Zustand over Redux?
419
+
420
+ Zustand was selected for its simplicity and minimal boilerplate compared to Redux, while still providing powerful state management capabilities. It integrates well with React's hooks and has a smaller bundle size.
421
+
422
+ ### Why React Query?
423
+
424
+ React Query simplifies data fetching with built-in caching, loading and error states, and automatic refetching. It helps keep components clean by separating data fetching concerns.
425
+
426
+ ### Why CSS-in-JS Approach?
427
+
428
+ The application uses a CSS-in-JS approach for styling to:
429
+ - Keep styles close to components
430
+ - Enable theme variables to be accessed in JavaScript
431
+ - Allow dynamic styling based on props
432
+ - Prevent style conflicts through scoped CSS
@@ -0,0 +1,199 @@
1
+ # SAAFE Components Documentation
2
+
3
+ This document provides an overview of the UI components used throughout the SAAFE Redirection Flow application.
4
+
5
+ ## Core Components
6
+
7
+ ### Layout Components
8
+
9
+ - **FrostedPanel**: A glass-like container with backdrop blur effect for modern UI elements
10
+ - **Card**: Basic container with shadow and rounded corners for content grouping
11
+ - **Dialog**: Modal dialog component for displaying information that requires user attention
12
+ - **BottomSheet**: Mobile-first slide-up panel for displaying contextual content
13
+ - **Sheet**: Slide-in panel from the side of the screen
14
+ - **Modal**: Centered modal dialog with backdrop
15
+ - **Sidebar**: Navigation sidebar with collapsible sections
16
+
17
+ ### Input Components
18
+
19
+ - **Button**: Primary action component with multiple variants (primary, secondary, ghost, etc.)
20
+ - **AnimatedButton**: Button with loading animation states
21
+ - **Input**: Text input field with validation support
22
+ - **Checkbox**: Selectable checkbox input component
23
+ - **RadioGroup**: Group of radio button inputs for mutually exclusive selection
24
+ - **Select**: Dropdown select component for choosing from a list of options
25
+ - **OTPInput**: One-time password input with individual character fields
26
+ - **Calendar**: Date picker component with day/month/year selection
27
+
28
+ ### Navigation Components
29
+
30
+ - **Step**: Step component for multi-step flows with progress indicators
31
+ - **Stepper**: Container for multi-step processes with navigation controls
32
+ - **DotStepper**: Minimal stepper with dots for indicating progress
33
+ - **StepperProgress**: Progress bar for multi-step flows
34
+ - **Tabs**: Tabbed navigation interface for switching between content sections
35
+
36
+ ### Feedback Components
37
+
38
+ - **Alert**: Alert component for displaying information, warnings, or errors
39
+ - **Skeleton**: Loading placeholder for content that is being loaded
40
+ - **Tooltip**: Informational tooltip that appears on hover
41
+ - **Progress**: Progress indicator for operations
42
+
43
+ ### Document Components
44
+
45
+ - **DocumentLink**: Component for linking to external documents with platform-specific handling
46
+ - **ScrollArea**: Scrollable container with custom scrollbar styling
47
+
48
+ ### Utility Components
49
+
50
+ - **Separator**: Visual divider between content sections
51
+ - **Avatar**: User avatar component with fallback support
52
+ - **Label**: Form label component with accessibility features
53
+ - **Popover**: Floating content that appears relative to a trigger element
54
+ - **Collapsible**: Expandable/collapsible content section
55
+ - **DropdownMenu**: Menu that appears relative to a trigger element
56
+
57
+ ## Platform-Specific Components
58
+
59
+ - **MobileFooter**: Footer component optimized for mobile devices
60
+ - **WebFooter**: Footer component optimized for web browsers
61
+ - **PlatformSpecificBehavior**: Component that renders different content based on the platform
62
+ - **MobileBackground**: Background component with mobile-specific styling
63
+ - **UrlDecodeLoader**: Loading component displayed during URL parameter decoding
64
+
65
+ ## Form Components
66
+
67
+ - **Form**: Form container with validation and submission handling
68
+ - **FormField**: Field wrapper with label and error handling
69
+ - **FormItem**: Individual form item container
70
+ - **FormLabel**: Accessible form label
71
+ - **FormControl**: Form control wrapper with accessibility attributes
72
+ - **FormDescription**: Descriptive text for form fields
73
+ - **FormMessage**: Error or validation message for form fields
74
+
75
+ ## Authentication Components
76
+
77
+ - **AuthGuard**: Component that restricts access to protected routes
78
+
79
+ ## Specialized Components
80
+
81
+ - **ModeToggle**: Theme toggle switch between light and dark modes
82
+ - **PageHeader**: Header component with title and optional back button
83
+ - **StepNavigation**: Navigation component for multi-step flows
84
+ - **SDKParamsDocs**: Documentation component for SDK parameters
85
+ - **DummyFooter**: Simple footer component for demo purposes
86
+ - **MobileAppDownload**: Component for promoting mobile app downloads
87
+
88
+ ## Usage Examples
89
+
90
+ ### Basic Button
91
+
92
+ ```tsx
93
+ import { Button } from "@/components/ui/button";
94
+
95
+ export function MyComponent() {
96
+ return (
97
+ <Button variant="primary" size="default" onClick={() => console.log("Clicked")}>
98
+ Click Me
99
+ </Button>
100
+ );
101
+ }
102
+ ```
103
+
104
+ ### Form with Validation
105
+
106
+ ```tsx
107
+ import { Form, FormField, FormItem, FormLabel, FormControl, FormMessage } from "@/components/ui/form";
108
+ import { Input } from "@/components/ui/input";
109
+ import { useForm } from "react-hook-form";
110
+ import { z } from "zod";
111
+ import { zodResolver } from "@hookform/resolvers/zod";
112
+
113
+ const formSchema = z.object({
114
+ email: z.string().email("Invalid email address"),
115
+ });
116
+
117
+ export function LoginForm() {
118
+ const form = useForm({
119
+ resolver: zodResolver(formSchema),
120
+ defaultValues: {
121
+ email: "",
122
+ },
123
+ });
124
+
125
+ const onSubmit = (data) => {
126
+ console.log(data);
127
+ };
128
+
129
+ return (
130
+ <Form {...form}>
131
+ <form onSubmit={form.handleSubmit(onSubmit)}>
132
+ <FormField
133
+ control={form.control}
134
+ name="email"
135
+ render={({ field }) => (
136
+ <FormItem>
137
+ <FormLabel>Email</FormLabel>
138
+ <FormControl>
139
+ <Input placeholder="Enter your email" {...field} />
140
+ </FormControl>
141
+ <FormMessage />
142
+ </FormItem>
143
+ )}
144
+ />
145
+ <Button type="submit">Submit</Button>
146
+ </form>
147
+ </Form>
148
+ );
149
+ }
150
+ ```
151
+
152
+ ### Multi-step Flow
153
+
154
+ ```tsx
155
+ import { Stepper, Step } from "@/components/ui/stepper";
156
+
157
+ export function OnboardingFlow() {
158
+ const [currentStep, setCurrentStep] = useState(0);
159
+
160
+ return (
161
+ <Stepper currentStep={currentStep} totalSteps={3}>
162
+ <Step
163
+ title="Personal Details"
164
+ description="Enter your personal information"
165
+ isActive={currentStep === 0}
166
+ >
167
+ {/* Step 1 content */}
168
+ </Step>
169
+ <Step
170
+ title="Account Setup"
171
+ description="Set up your account"
172
+ isActive={currentStep === 1}
173
+ >
174
+ {/* Step 2 content */}
175
+ </Step>
176
+ <Step
177
+ title="Confirmation"
178
+ description="Confirm your details"
179
+ isActive={currentStep === 2}
180
+ >
181
+ {/* Step 3 content */}
182
+ </Step>
183
+ </Stepper>
184
+ );
185
+ }
186
+ ```
187
+
188
+ ## Component Customization
189
+
190
+ Most components support customization through props. Common customization options include:
191
+
192
+ - **variant**: Changes the visual style (primary, secondary, ghost, etc.)
193
+ - **size**: Changes the size (sm, md, lg, etc.)
194
+ - **disabled**: Disables the component
195
+ - **className**: Allows for additional CSS classes for custom styling
196
+
197
+ ## Theming
198
+
199
+ Components automatically adapt to the current theme (light/dark) based on the ThemeProvider configuration. Custom themes can be applied by modifying CSS variables in the root document element.
package/docs/index.md ADDED
@@ -0,0 +1,69 @@
1
+ # SAAFE Redirection Flow Documentation
2
+
3
+ Welcome to the SAAFE Redirection Flow documentation. This documentation provides comprehensive information about the application's features, components, and integration options.
4
+
5
+ ## Table of Contents
6
+
7
+ - [Architecture](./architecture.md) - Technical architecture and design decisions
8
+ - [Components](./components.md) - UI components library documentation
9
+ - [Routes](./routes.md) - Available routes and pages
10
+ - [SDK Integration](./sdk-integration.md) - Guide for integrating the SAAFE Redirection Flow into your applications
11
+ - [User Journey](./user-flow.md) - Detailed explanation of the end-to-end user flow
12
+
13
+ ## Project Overview
14
+
15
+ The SAAFE Redirection Flow is a modern React application that provides a secure account linking experience for the SAAFE (Secure Account Access Financial Environment) platform. It is designed to be embedded in mobile and web applications via an SDK.
16
+
17
+ The application facilitates secure account linking between financial institutions and third-party applications through a user-friendly interface, with features including:
18
+
19
+ - Multi-platform support (iOS, Android, React Native, Flutter, Web)
20
+ - Theming options (light, dark, system)
21
+ - Internationalization
22
+ - Responsive design
23
+ - Secure authentication
24
+ - Account discovery and linking
25
+ - Consent management
26
+
27
+ ## Getting Started
28
+
29
+ Before diving into specific sections, we recommend understanding the basic flow of the application:
30
+
31
+ 1. **Integration**: Embed the application in your platform using the appropriate integration method
32
+ 2. **Configuration**: Configure the application using URL parameters
33
+ 3. **Authentication**: Users authenticate with their financial institution
34
+ 4. **Account Discovery**: Users select accounts to link
35
+ 5. **Consent**: Users review and approve data sharing
36
+ 6. **Completion**: The flow completes with success or rejection
37
+
38
+ ## Core Features
39
+
40
+ ### Multi-platform Support
41
+
42
+ The application is designed to work seamlessly across different platforms:
43
+
44
+ - **iOS/Android**: Optimized for mobile WebViews with adjusted UI elements
45
+ - **React Native/Flutter**: Suitable configurations for cross-platform SDKs
46
+ - **Web**: Default desktop experience with navigation safeguards
47
+
48
+ ### Theming
49
+
50
+ The application supports multiple themes:
51
+
52
+ - **Light**: Bright interface with dark text
53
+ - **Dark**: Dark interface with light text
54
+ - **System**: Adapts to the user's system preferences
55
+
56
+ ### Document Handling
57
+
58
+ The application handles document displays differently based on the platform:
59
+
60
+ - **Web**: Terms and conditions, privacy policy and other documents open in new tabs
61
+ - **Mobile/SDK platforms**: Documents are displayed in a modern, centered modal dialog with local React components
62
+
63
+ ### Navigation Protection
64
+
65
+ To prevent accidental exits, the application implements navigation protection that warns users before leaving the flow.
66
+
67
+ ## Contributing
68
+
69
+ For information on contributing to the SAAFE Redirection Flow, please contact the development team.