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.
- package/.github/workflows/build-and-deploy.yml +41 -0
- package/.gitlab-ci.yml +108 -0
- package/.releaserc.json +18 -0
- package/.storybook/main.ts +28 -0
- package/.storybook/preview.ts +16 -0
- package/.storybook/vitest.setup.ts +9 -0
- package/.vite/deps/@radix-ui_react-avatar.js +230 -0
- package/.vite/deps/@radix-ui_react-avatar.js.map +7 -0
- package/.vite/deps/@radix-ui_react-slot.js +12 -0
- package/.vite/deps/@radix-ui_react-slot.js.map +7 -0
- package/.vite/deps/_metadata.json +79 -0
- package/.vite/deps/chunk-5VGQBUCU.js +597 -0
- package/.vite/deps/chunk-5VGQBUCU.js.map +7 -0
- package/.vite/deps/chunk-DC5AMYBS.js +38 -0
- package/.vite/deps/chunk-DC5AMYBS.js.map +7 -0
- package/.vite/deps/chunk-HUIEPYH7.js +11265 -0
- package/.vite/deps/chunk-HUIEPYH7.js.map +7 -0
- package/.vite/deps/chunk-TKHB4QMX.js +281 -0
- package/.vite/deps/chunk-TKHB4QMX.js.map +7 -0
- package/.vite/deps/chunk-YLDSBLSF.js +1139 -0
- package/.vite/deps/chunk-YLDSBLSF.js.map +7 -0
- package/.vite/deps/class-variance-authority.js +63 -0
- package/.vite/deps/class-variance-authority.js.map +7 -0
- package/.vite/deps/lucide-react.js +36984 -0
- package/.vite/deps/lucide-react.js.map +7 -0
- package/.vite/deps/package.json +3 -0
- package/.vite/deps/react-dom_client.js +17917 -0
- package/.vite/deps/react-dom_client.js.map +7 -0
- package/.vite/deps/react-router-dom.js +452 -0
- package/.vite/deps/react-router-dom.js.map +7 -0
- package/.vite/deps/react-router.js +234 -0
- package/.vite/deps/react-router.js.map +7 -0
- package/.vite/deps/react.js +5 -0
- package/.vite/deps/react.js.map +7 -0
- package/.vite/deps/react_jsx-dev-runtime.js +470 -0
- package/.vite/deps/react_jsx-dev-runtime.js.map +7 -0
- package/CHANGELOG.md +420 -0
- package/LICENSE +21 -0
- package/README.md +129 -0
- package/RELEASE_CHEATSHEET.md +93 -0
- package/RELEASE_NOTES.md +120 -0
- package/components.json +21 -0
- package/docs/DEPLOYMENT_WORKFLOW.md +262 -0
- package/docs/RELEASE_GUIDE.md +591 -0
- package/docs/architecture.md +432 -0
- package/docs/components.md +199 -0
- package/docs/index.md +69 -0
- package/docs/local-release-workflow.md +234 -0
- package/docs/routes.md +118 -0
- package/docs/sdk-integration.md +325 -0
- package/docs/semantic-release.md +124 -0
- package/docs/user-flow.md +206 -0
- package/eslint.config.js +28 -0
- package/index.html +19 -0
- package/install.sh +198 -0
- package/package.json +115 -0
- package/public/images/bank-logo.png +0 -0
- package/public/saafe-icon.svg +9 -0
- package/src/App.tsx +171 -0
- package/src/__tests__/url-parameters.test.ts +82 -0
- package/src/assets/brand/applestore.svg +13 -0
- package/src/assets/brand/playstore.svg +23 -0
- package/src/assets/brand/saafe-color-white-logo.svg +14 -0
- package/src/assets/brand/saafe-icon.svg +9 -0
- package/src/assets/brand/saafe-logo.svg +18 -0
- package/src/assets/icons/check-icon-dark.svg +27 -0
- package/src/assets/icons/check-icon.svg +23 -0
- package/src/components/ErrorBoundary.tsx +132 -0
- package/src/components/alert/alert.tsx +27 -0
- package/src/components/auth/AuthGuard.tsx +76 -0
- package/src/components/cards/BankCard.stories.tsx +69 -0
- package/src/components/cards/BankCard.tsx +227 -0
- package/src/components/cards/OuterCard.tsx +109 -0
- package/src/components/cards/WrapperCard.tsx +64 -0
- package/src/components/documents/PrivacyContent.tsx +1 -0
- package/src/components/dummyFooter.tsx +29 -0
- package/src/components/icons/github.tsx +12 -0
- package/src/components/language/LanguageSwitcher.tsx +44 -0
- package/src/components/layouts/FrostedLayout.stories.tsx +42 -0
- package/src/components/layouts/FrostedLayout.tsx +333 -0
- package/src/components/layouts/MobileLayout.tsx +403 -0
- package/src/components/mobile-background.tsx +136 -0
- package/src/components/mobileAppDownload.tsx +30 -0
- package/src/components/modal/ModalComp.tsx +27 -0
- package/src/components/mode-toggle.tsx +36 -0
- package/src/components/page-header.tsx +50 -0
- package/src/components/session/SessionTimeoutScreen.tsx +134 -0
- package/src/components/session/SessionTimer.tsx +173 -0
- package/src/components/step-navigation.tsx +87 -0
- package/src/components/title/AppBar.stories.tsx +50 -0
- package/src/components/title/AppBar.tsx +150 -0
- package/src/components/title/SectionTitle.tsx +31 -0
- package/src/components/ui/AnimatedButton.module.css +13 -0
- package/src/components/ui/alert.tsx +66 -0
- package/src/components/ui/animatedButton.tsx +111 -0
- package/src/components/ui/avatar.tsx +51 -0
- package/src/components/ui/badge.tsx +36 -0
- package/src/components/ui/bottom-sheet.tsx +122 -0
- package/src/components/ui/button.tsx +59 -0
- package/src/components/ui/calendar.tsx +86 -0
- package/src/components/ui/card.tsx +92 -0
- package/src/components/ui/checkbox.stories.tsx +49 -0
- package/src/components/ui/checkbox.tsx +67 -0
- package/src/components/ui/collapsible.tsx +45 -0
- package/src/components/ui/dialog.tsx +134 -0
- package/src/components/ui/document-link.tsx +26 -0
- package/src/components/ui/dot-stepper.tsx +57 -0
- package/src/components/ui/dropdown-menu.tsx +255 -0
- package/src/components/ui/form.tsx +165 -0
- package/src/components/ui/frosted-panel.stories.tsx +86 -0
- package/src/components/ui/frosted-panel.tsx +276 -0
- package/src/components/ui/input.tsx +39 -0
- package/src/components/ui/label.stories.tsx +67 -0
- package/src/components/ui/label.tsx +23 -0
- package/src/components/ui/mobile-footer.tsx +54 -0
- package/src/components/ui/modal.tsx +90 -0
- package/src/components/ui/otp-input.stories.tsx +62 -0
- package/src/components/ui/otp-input.tsx +221 -0
- package/src/components/ui/platform-specific-behavior.tsx +28 -0
- package/src/components/ui/popover.tsx +46 -0
- package/src/components/ui/progress.tsx +103 -0
- package/src/components/ui/radio-group.tsx +45 -0
- package/src/components/ui/scroll-area.tsx +56 -0
- package/src/components/ui/sdk-params-docs.tsx +53 -0
- package/src/components/ui/select.tsx +159 -0
- package/src/components/ui/separator.tsx +28 -0
- package/src/components/ui/sheet.tsx +137 -0
- package/src/components/ui/sidebar.tsx +724 -0
- package/src/components/ui/skeleton.stories.tsx +50 -0
- package/src/components/ui/skeleton.tsx +15 -0
- package/src/components/ui/sonner.tsx +23 -0
- package/src/components/ui/step.stories.tsx +132 -0
- package/src/components/ui/step.tsx +234 -0
- package/src/components/ui/stepper-progress.tsx +136 -0
- package/src/components/ui/stepper.tsx +259 -0
- package/src/components/ui/tabs.tsx +55 -0
- package/src/components/ui/tooltip.tsx +61 -0
- package/src/components/ui/url-decode-loader.tsx +36 -0
- package/src/components/ui/version-display.tsx +104 -0
- package/src/components/ui/web-footer.tsx +36 -0
- package/src/config/environments.ts +99 -0
- package/src/config/urls.ts +53 -0
- package/src/const/fiTypeCategoryMap.ts +19 -0
- package/src/contexts/LanguageContext.tsx +41 -0
- package/src/contexts/RTLContext.tsx +42 -0
- package/src/contexts/ThemeContext.tsx +93 -0
- package/src/hooks/use-account-discovery.ts +205 -0
- package/src/hooks/use-auth-query.ts +141 -0
- package/src/hooks/use-fip-query.ts +72 -0
- package/src/hooks/use-media-query.ts +32 -0
- package/src/hooks/use-mobile.ts +24 -0
- package/src/hooks/use-page-title.tsx +48 -0
- package/src/hooks/use-platform.ts +52 -0
- package/src/hooks/use-trusted-count.ts +21 -0
- package/src/hooks/use-url-decode.ts +90 -0
- package/src/hooks/useStep.ts +170 -0
- package/src/index.css +154 -0
- package/src/interfaces/app.interfaces.ts +39 -0
- package/src/interfaces/services.interfaces.ts +65 -0
- package/src/lib/i18n.ts +68 -0
- package/src/lib/utils.ts +6 -0
- package/src/locales/en/common.json +167 -0
- package/src/locales/hi/common.json +137 -0
- package/src/locales/kn/common.json +137 -0
- package/src/locales/ml/common.json +137 -0
- package/src/locales/ta/common.json +137 -0
- package/src/locales/te/common.json +137 -0
- package/src/locales/ur/common.json +138 -0
- package/src/main.tsx +46 -0
- package/src/pages/Login.tsx +363 -0
- package/src/pages/accounts/AccountsToProceed.tsx +396 -0
- package/src/pages/accounts/Discover.tsx +76 -0
- package/src/pages/accounts/DiscoverAccount.tsx +751 -0
- package/src/pages/accounts/LinkSelectedAccounts.tsx +638 -0
- package/src/pages/accounts/OldUser.tsx +329 -0
- package/src/pages/accounts/link-accounts.tsx +913 -0
- package/src/pages/consent/ReviewConsent.tsx +836 -0
- package/src/pages/consent/rejected.tsx +253 -0
- package/src/pages/consent/success.tsx +220 -0
- package/src/providers/query-provider.tsx +24 -0
- package/src/providers/toast-provider.tsx +26 -0
- package/src/services/api/account.service.ts +296 -0
- package/src/services/api/auth.service.ts +206 -0
- package/src/services/api/axios.ts +138 -0
- package/src/services/api/consent.service.ts +142 -0
- package/src/services/api/decode.service.ts +53 -0
- package/src/services/api/feedback.service.ts +34 -0
- package/src/services/api/fip.service.ts +187 -0
- package/src/services/api/index.ts +9 -0
- package/src/services/api/public.service.ts +18 -0
- package/src/services/api.ts +2 -0
- package/src/services/postMessage.service.ts +179 -0
- package/src/store/NavigationBlockContext.tsx +34 -0
- package/src/store/auth.store.ts +79 -0
- package/src/store/fip.store.ts +396 -0
- package/src/store/mandatoryConsent.store.ts +24 -0
- package/src/store/redirect.store.ts +73 -0
- package/src/store/step.store.ts +124 -0
- package/src/stories/Button.stories.ts +53 -0
- package/src/stories/Button.tsx +37 -0
- package/src/stories/Configure.mdx +364 -0
- package/src/stories/Header.stories.ts +33 -0
- package/src/stories/Header.tsx +56 -0
- package/src/stories/Page.stories.ts +32 -0
- package/src/stories/Page.tsx +73 -0
- package/src/stories/button.css +30 -0
- package/src/stories/header.css +32 -0
- package/src/stories/page.css +68 -0
- package/src/styles/rtl-utils.css +90 -0
- package/src/styles/rtl.css +105 -0
- package/src/utils/api-error.ts +26 -0
- package/src/utils/cn.ts +10 -0
- package/src/utils/error-callback.ts +116 -0
- package/src/utils/formatAccountNumber.ts +9 -0
- package/src/utils/handleIdentifiers.ts +90 -0
- package/src/utils/posthog.ts +67 -0
- package/src/utils/toast-helpers.ts +61 -0
- package/src/vite-env.d.ts +1 -0
- package/stage-aa-2506251021.zip +0 -0
- package/tsconfig.app.json +33 -0
- package/tsconfig.json +13 -0
- package/tsconfig.node.json +24 -0
- package/vite.config.ts +45 -0
- package/vitest.shims.d.ts +1 -0
- package/vitest.workspace.ts +46 -0
@@ -0,0 +1,234 @@
|
|
1
|
+
# Local Release Workflow Guide
|
2
|
+
|
3
|
+
This guide explains how to use the semantic release setup for local development and deployment without GitHub Actions.
|
4
|
+
|
5
|
+
## Quick Start
|
6
|
+
|
7
|
+
### 1. Check Current Status
|
8
|
+
```bash
|
9
|
+
# Check current version
|
10
|
+
npm run version:check
|
11
|
+
|
12
|
+
# List environment files
|
13
|
+
npm run env:list
|
14
|
+
|
15
|
+
# Check environment variables
|
16
|
+
npm run env:check
|
17
|
+
```
|
18
|
+
|
19
|
+
### 2. Test Release (Dry Run)
|
20
|
+
```bash
|
21
|
+
# Test what version would be released
|
22
|
+
npm run release:dry
|
23
|
+
```
|
24
|
+
|
25
|
+
### 3. Actual Release
|
26
|
+
```bash
|
27
|
+
# Create actual release
|
28
|
+
npm run release
|
29
|
+
```
|
30
|
+
|
31
|
+
## Environment-Based Builds
|
32
|
+
|
33
|
+
### Build for Specific Environments
|
34
|
+
```bash
|
35
|
+
# Build for production
|
36
|
+
npm run build:production
|
37
|
+
|
38
|
+
# Build for staging
|
39
|
+
npm run build:stage
|
40
|
+
|
41
|
+
# Build for sandbox
|
42
|
+
npm run build:sandbox
|
43
|
+
|
44
|
+
# Build for all environments
|
45
|
+
npm run build:all
|
46
|
+
```
|
47
|
+
|
48
|
+
### Preview Builds
|
49
|
+
```bash
|
50
|
+
# Preview production build
|
51
|
+
npm run preview:production
|
52
|
+
|
53
|
+
# Preview stage build
|
54
|
+
npm run preview:stage
|
55
|
+
|
56
|
+
# Preview sandbox build
|
57
|
+
npm run preview:sandbox
|
58
|
+
```
|
59
|
+
|
60
|
+
## Commit Convention
|
61
|
+
|
62
|
+
Use conventional commits for automatic version bumping:
|
63
|
+
|
64
|
+
### Patch Releases (1.0.0 → 1.0.1)
|
65
|
+
```bash
|
66
|
+
git commit -m "fix: resolve login issue"
|
67
|
+
git commit -m "fix(auth): handle token expiration"
|
68
|
+
```
|
69
|
+
|
70
|
+
### Minor Releases (1.0.0 → 1.1.0)
|
71
|
+
```bash
|
72
|
+
git commit -m "feat: add new authentication flow"
|
73
|
+
git commit -m "feat(dashboard): implement account selection"
|
74
|
+
```
|
75
|
+
|
76
|
+
### Major Releases (1.0.0 → 2.0.0)
|
77
|
+
```bash
|
78
|
+
git commit -m "feat!: redesign authentication system"
|
79
|
+
git commit -m "feat(api)!: change response format"
|
80
|
+
```
|
81
|
+
|
82
|
+
### Other Commit Types (No Release)
|
83
|
+
```bash
|
84
|
+
git commit -m "docs: update readme"
|
85
|
+
git commit -m "refactor: improve code structure"
|
86
|
+
git commit -m "style: fix formatting"
|
87
|
+
git commit -m "test: add unit tests"
|
88
|
+
git commit -m "chore: update dependencies"
|
89
|
+
```
|
90
|
+
|
91
|
+
## Branch-Based Versioning
|
92
|
+
|
93
|
+
### Main Branch (Production)
|
94
|
+
- Creates stable releases: `1.0.0`, `1.1.0`, `2.0.0`
|
95
|
+
- Used for production deployments
|
96
|
+
|
97
|
+
### Stage Branch
|
98
|
+
- Creates pre-releases: `1.0.0-stage.1`, `1.0.0-stage.2`
|
99
|
+
- Used for staging environment testing
|
100
|
+
|
101
|
+
### Sandbox Branch
|
102
|
+
- Creates pre-releases: `1.0.0-sandbox.1`, `1.0.0-sandbox.2`
|
103
|
+
- Used for sandbox environment testing
|
104
|
+
|
105
|
+
### Develop Branch
|
106
|
+
- Creates pre-releases: `1.0.0-dev.1`, `1.0.0-dev.2`
|
107
|
+
- Used for development environment testing
|
108
|
+
|
109
|
+
## Release Process
|
110
|
+
|
111
|
+
### 1. Development Workflow
|
112
|
+
```bash
|
113
|
+
# Switch to appropriate branch
|
114
|
+
git checkout sandbox
|
115
|
+
|
116
|
+
# Make changes with conventional commits
|
117
|
+
git add .
|
118
|
+
git commit -m "feat: add new feature"
|
119
|
+
|
120
|
+
# Test release
|
121
|
+
npm run release:dry
|
122
|
+
|
123
|
+
# Create release
|
124
|
+
npm run release
|
125
|
+
```
|
126
|
+
|
127
|
+
### 2. Build and Deploy
|
128
|
+
```bash
|
129
|
+
# Build for the environment
|
130
|
+
npm run build:sandbox
|
131
|
+
|
132
|
+
# Deploy the dist/ folder to your hosting service
|
133
|
+
```
|
134
|
+
|
135
|
+
### 3. Promotion Workflow
|
136
|
+
```bash
|
137
|
+
# Promote sandbox to stage
|
138
|
+
git checkout stage
|
139
|
+
git merge sandbox
|
140
|
+
npm run release
|
141
|
+
|
142
|
+
# Build for stage
|
143
|
+
npm run build:stage
|
144
|
+
|
145
|
+
# Promote stage to production
|
146
|
+
git checkout main
|
147
|
+
git merge stage
|
148
|
+
npm run release
|
149
|
+
|
150
|
+
# Build for production
|
151
|
+
npm run build:production
|
152
|
+
```
|
153
|
+
|
154
|
+
## What Semantic Release Does
|
155
|
+
|
156
|
+
### Automatic Actions:
|
157
|
+
1. **Analyzes commits** since last release
|
158
|
+
2. **Determines version bump** based on commit types
|
159
|
+
3. **Generates release notes** from commit messages
|
160
|
+
4. **Updates package.json** version
|
161
|
+
5. **Updates CHANGELOG.md** with new release notes
|
162
|
+
6. **Creates git tag** for the new version
|
163
|
+
7. **Commits changes** back to repository
|
164
|
+
|
165
|
+
### Generated Files:
|
166
|
+
- `CHANGELOG.md` - Automatically updated with release notes
|
167
|
+
- `package.json` - Version field updated
|
168
|
+
- `package-lock.json` - Version field updated
|
169
|
+
|
170
|
+
## Environment Configuration
|
171
|
+
|
172
|
+
### Environment Variables Available:
|
173
|
+
- `VITE_API_BASE_URL` - API endpoint for current environment
|
174
|
+
- `VITE_IMAGE_BASE_URL` - Image CDN URL
|
175
|
+
- `VITE_APP_NAME` - Application name
|
176
|
+
- `VITE_PUBLIC_POSTHOG_KEY` - Analytics key
|
177
|
+
- `VITE_SESSION_TIMEOUT` - Session timeout duration
|
178
|
+
|
179
|
+
### Environment Files:
|
180
|
+
- `.env.production` - Production settings
|
181
|
+
- `.env.stage` - Stage settings
|
182
|
+
- `.env.sandbox` - Sandbox settings
|
183
|
+
- `.env.development` - Development settings
|
184
|
+
|
185
|
+
## Troubleshooting
|
186
|
+
|
187
|
+
### No Release Created
|
188
|
+
- Check if commits follow conventional format
|
189
|
+
- Ensure you're on the correct branch
|
190
|
+
- Run `npm run release:dry` to see what would happen
|
191
|
+
|
192
|
+
### Build Failures
|
193
|
+
- Check TypeScript errors: `npm run lint`
|
194
|
+
- Verify environment variables are set
|
195
|
+
- Ensure all dependencies are installed: `npm install`
|
196
|
+
|
197
|
+
### Version Conflicts
|
198
|
+
- Always pull latest changes before releasing
|
199
|
+
- Use `git status` to check for uncommitted changes
|
200
|
+
- Resolve any merge conflicts before releasing
|
201
|
+
|
202
|
+
## Useful Commands
|
203
|
+
|
204
|
+
```bash
|
205
|
+
# Check what would be released
|
206
|
+
npm run release:dry
|
207
|
+
|
208
|
+
# Check current version
|
209
|
+
npm run version:check
|
210
|
+
|
211
|
+
# List all environment files
|
212
|
+
npm run env:list
|
213
|
+
|
214
|
+
# Check environment variables
|
215
|
+
npm run env:check
|
216
|
+
|
217
|
+
# Build all environments
|
218
|
+
npm run build:all
|
219
|
+
|
220
|
+
# Run development server
|
221
|
+
npm run dev
|
222
|
+
|
223
|
+
# Preview production build locally
|
224
|
+
npm run preview:production
|
225
|
+
```
|
226
|
+
|
227
|
+
## Best Practices
|
228
|
+
|
229
|
+
1. **Always test with dry run** before actual release
|
230
|
+
2. **Use descriptive commit messages** for better release notes
|
231
|
+
3. **Build and test** before releasing
|
232
|
+
4. **Use branch-specific environments** for testing
|
233
|
+
5. **Keep environment files** updated with correct settings
|
234
|
+
6. **Review generated CHANGELOG.md** after releases
|
package/docs/routes.md
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
# SAAFE Routes Documentation
|
2
|
+
|
3
|
+
This document provides information about the routes and pages available in the SAAFE Redirection Flow application.
|
4
|
+
|
5
|
+
## Route Structure
|
6
|
+
|
7
|
+
The application uses React Router v7 for route management. The main route structure is defined in `App.tsx`.
|
8
|
+
|
9
|
+
## Available Routes
|
10
|
+
|
11
|
+
### Public Routes
|
12
|
+
|
13
|
+
| Route | Component | Description |
|
14
|
+
|-------|-----------|-------------|
|
15
|
+
| `/` | Redirect to `/login` | Redirects to the login page |
|
16
|
+
| `/login` | `Login` | Initial entry point for user authentication |
|
17
|
+
|
18
|
+
### Protected Routes
|
19
|
+
|
20
|
+
These routes require authentication via the `AuthGuard` component:
|
21
|
+
|
22
|
+
| Route | Component | Description |
|
23
|
+
|-------|-----------|-------------|
|
24
|
+
| `/link-accounts` | Redirect to `/link-accounts/banks` | Default redirect for account linking |
|
25
|
+
| `/link-accounts/discovery` | `Discover` | Account discovery page |
|
26
|
+
| `/link-accounts/proceed` | `Discover` | Proceed with discovered accounts |
|
27
|
+
| `/link-accounts/link` | `Discover` | Link selected accounts |
|
28
|
+
| `/link-accounts/discover-account` | `Discover` | Discover specific account details |
|
29
|
+
| `/link-accounts/old-user` | `OldUser` | Page for returning users with existing linked accounts |
|
30
|
+
| `/link-accounts/:category` | `Discover` | Category-specific financial institution listing |
|
31
|
+
| `/review` | `ReviewConsent` | Review and confirm data sharing consent |
|
32
|
+
| `/success` | `Success` | Successful account linking confirmation |
|
33
|
+
| `/rejected` | `Rejected` | Consent rejection confirmation |
|
34
|
+
|
35
|
+
## Page Components
|
36
|
+
|
37
|
+
### Login Page
|
38
|
+
|
39
|
+
**Path:** `/login`
|
40
|
+
**Component:** `Login.tsx`
|
41
|
+
|
42
|
+
The initial entry point for users. This page:
|
43
|
+
- Decodes and validates URL parameters
|
44
|
+
- Authenticates the user with their financial institution
|
45
|
+
- Supports OTP verification if enabled
|
46
|
+
- Adapts UI based on the specified platform
|
47
|
+
- Handles theme preferences
|
48
|
+
|
49
|
+
### Discover Page
|
50
|
+
|
51
|
+
**Path:** `/link-accounts/discovery` (and related paths)
|
52
|
+
**Component:** `Discover.tsx`
|
53
|
+
|
54
|
+
Multi-purpose page that handles various aspects of account discovery:
|
55
|
+
- Lists available financial institutions by category
|
56
|
+
- Discovers accounts associated with a user
|
57
|
+
- Allows selection of accounts to link
|
58
|
+
- Shows detailed account information
|
59
|
+
|
60
|
+
### ReviewConsent Page
|
61
|
+
|
62
|
+
**Path:** `/review`
|
63
|
+
**Component:** `ReviewConsent.tsx`
|
64
|
+
|
65
|
+
Page for reviewing and providing consent for data sharing:
|
66
|
+
- Displays detailed information about what data will be shared
|
67
|
+
- Shows the third-party requestor details
|
68
|
+
- Explains the purpose of data sharing
|
69
|
+
- Provides clear accept/reject options
|
70
|
+
|
71
|
+
### Success Page
|
72
|
+
|
73
|
+
**Path:** `/success`
|
74
|
+
**Component:** `Success.tsx`
|
75
|
+
|
76
|
+
Confirmation page shown after successful account linking:
|
77
|
+
- Displays success message and next steps
|
78
|
+
- Provides options to return to the originating application
|
79
|
+
- Shows linked account details (if configured)
|
80
|
+
|
81
|
+
### Rejected Page
|
82
|
+
|
83
|
+
**Path:** `/rejected`
|
84
|
+
**Component:** `Rejected.tsx`
|
85
|
+
|
86
|
+
Confirmation page shown after rejecting consent:
|
87
|
+
- Confirms the user's rejection of data sharing
|
88
|
+
- Explains implications of rejection
|
89
|
+
- Provides options to return to the originating application
|
90
|
+
|
91
|
+
### Old User Page
|
92
|
+
|
93
|
+
**Path:** `/link-accounts/old-user`
|
94
|
+
**Component:** `OldUser.tsx`
|
95
|
+
|
96
|
+
Special page for returning users with previously linked accounts:
|
97
|
+
- Shows existing linked accounts
|
98
|
+
- Provides options to add more accounts
|
99
|
+
- Allows unlinking of existing accounts
|
100
|
+
|
101
|
+
## Navigation Flow
|
102
|
+
|
103
|
+
The typical user journey follows this flow:
|
104
|
+
|
105
|
+
1. User arrives at `/login` with required URL parameters
|
106
|
+
2. After successful authentication, user is directed to `/link-accounts/discovery`
|
107
|
+
3. User selects accounts to link and proceeds to `/review`
|
108
|
+
4. User reviews consent details and either:
|
109
|
+
- Accepts, leading to `/success`
|
110
|
+
- Rejects, leading to `/rejected`
|
111
|
+
|
112
|
+
## Route Protection
|
113
|
+
|
114
|
+
All routes except `/login` are protected by the `AuthGuard` component, which:
|
115
|
+
- Verifies that the user is authenticated
|
116
|
+
- Redirects unauthenticated users to the login page
|
117
|
+
- Maintains session state across page navigation
|
118
|
+
- Handles session timeouts
|
@@ -0,0 +1,325 @@
|
|
1
|
+
# SAAFE SDK Integration Guide
|
2
|
+
|
3
|
+
This document provides detailed information on how to integrate the SAAFE Redirection Flow into your applications via the SDK.
|
4
|
+
|
5
|
+
## Overview
|
6
|
+
|
7
|
+
The SAAFE Redirection Flow is designed to be embedded within mobile and web applications using a WebView (iOS, Android) or iframe (Web) approach. This allows your users to securely link their financial accounts without leaving your application.
|
8
|
+
|
9
|
+
## Integration Methods
|
10
|
+
|
11
|
+
### Mobile SDK Integration
|
12
|
+
|
13
|
+
#### iOS (Swift) WebView Integration
|
14
|
+
|
15
|
+
```swift
|
16
|
+
import UIKit
|
17
|
+
import WebKit
|
18
|
+
|
19
|
+
class SAFERedirectionViewController: UIViewController, WKNavigationDelegate {
|
20
|
+
|
21
|
+
private var webView: WKWebView!
|
22
|
+
private let financialInstitutionId: String
|
23
|
+
private let encryptedRequest: String
|
24
|
+
private let requestDate: String
|
25
|
+
|
26
|
+
init(financialInstitutionId: String, encryptedRequest: String, requestDate: String) {
|
27
|
+
self.financialInstitutionId = financialInstitutionId
|
28
|
+
self.encryptedRequest = encryptedRequest
|
29
|
+
self.requestDate = requestDate
|
30
|
+
super.init(nibName: nil, bundle: nil)
|
31
|
+
}
|
32
|
+
|
33
|
+
required init?(coder: NSCoder) {
|
34
|
+
fatalError("init(coder:) has not been implemented")
|
35
|
+
}
|
36
|
+
|
37
|
+
override func viewDidLoad() {
|
38
|
+
super.viewDidLoad()
|
39
|
+
|
40
|
+
setupWebView()
|
41
|
+
loadSAAFERedirection()
|
42
|
+
}
|
43
|
+
|
44
|
+
private func setupWebView() {
|
45
|
+
let configuration = WKWebViewConfiguration()
|
46
|
+
webView = WKWebView(frame: view.bounds, configuration: configuration)
|
47
|
+
webView.navigationDelegate = self
|
48
|
+
webView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
49
|
+
view.addSubview(webView)
|
50
|
+
}
|
51
|
+
|
52
|
+
private func loadSAAFERedirection() {
|
53
|
+
let baseUrl = "https://saafe-app.com/login"
|
54
|
+
var urlComponents = URLComponents(string: baseUrl)!
|
55
|
+
|
56
|
+
urlComponents.queryItems = [
|
57
|
+
URLQueryItem(name: "fi", value: financialInstitutionId),
|
58
|
+
URLQueryItem(name: "ecreq", value: encryptedRequest),
|
59
|
+
URLQueryItem(name: "reqdate", value: requestDate),
|
60
|
+
URLQueryItem(name: "platform", value: "ios"),
|
61
|
+
URLQueryItem(name: "theme", value: "system")
|
62
|
+
]
|
63
|
+
|
64
|
+
if let url = urlComponents.url {
|
65
|
+
let request = URLRequest(url: url)
|
66
|
+
webView.load(request)
|
67
|
+
}
|
68
|
+
}
|
69
|
+
|
70
|
+
// MARK: - WKNavigationDelegate
|
71
|
+
|
72
|
+
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
|
73
|
+
// Handle successful page load
|
74
|
+
}
|
75
|
+
|
76
|
+
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
|
77
|
+
// Intercept navigation if needed
|
78
|
+
|
79
|
+
// Example: Detect success/rejection callbacks
|
80
|
+
if let url = navigationAction.request.url?.absoluteString {
|
81
|
+
if url.contains("/success") {
|
82
|
+
// Handle success scenario
|
83
|
+
self.dismiss(animated: true, completion: nil)
|
84
|
+
decisionHandler(.cancel)
|
85
|
+
return
|
86
|
+
} else if url.contains("/rejected") {
|
87
|
+
// Handle rejection scenario
|
88
|
+
self.dismiss(animated: true, completion: nil)
|
89
|
+
decisionHandler(.cancel)
|
90
|
+
return
|
91
|
+
}
|
92
|
+
}
|
93
|
+
|
94
|
+
decisionHandler(.allow)
|
95
|
+
}
|
96
|
+
}
|
97
|
+
```
|
98
|
+
|
99
|
+
#### Android (Kotlin) WebView Integration
|
100
|
+
|
101
|
+
```kotlin
|
102
|
+
import android.os.Bundle
|
103
|
+
import android.webkit.WebView
|
104
|
+
import android.webkit.WebViewClient
|
105
|
+
import androidx.appcompat.app.AppCompatActivity
|
106
|
+
import java.net.URLEncoder
|
107
|
+
|
108
|
+
class SAFERedirectionActivity : AppCompatActivity() {
|
109
|
+
|
110
|
+
private lateinit var webView: WebView
|
111
|
+
|
112
|
+
override fun onCreate(savedInstanceState: Bundle?) {
|
113
|
+
super.onCreate(savedInstanceState)
|
114
|
+
|
115
|
+
// Get parameters from intent
|
116
|
+
val financialInstitutionId = intent.getStringExtra("fi") ?: ""
|
117
|
+
val encryptedRequest = intent.getStringExtra("ecreq") ?: ""
|
118
|
+
val requestDate = intent.getStringExtra("reqdate") ?: ""
|
119
|
+
|
120
|
+
// Set up WebView
|
121
|
+
webView = WebView(this)
|
122
|
+
webView.settings.javaScriptEnabled = true
|
123
|
+
webView.settings.domStorageEnabled = true
|
124
|
+
|
125
|
+
webView.webViewClient = object : WebViewClient() {
|
126
|
+
override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean {
|
127
|
+
// Detect success/rejection URLs
|
128
|
+
url?.let {
|
129
|
+
when {
|
130
|
+
it.contains("/success") -> {
|
131
|
+
// Handle success
|
132
|
+
finish()
|
133
|
+
return true
|
134
|
+
}
|
135
|
+
it.contains("/rejected") -> {
|
136
|
+
// Handle rejection
|
137
|
+
finish()
|
138
|
+
return true
|
139
|
+
}
|
140
|
+
}
|
141
|
+
}
|
142
|
+
return false
|
143
|
+
}
|
144
|
+
}
|
145
|
+
|
146
|
+
setContentView(webView)
|
147
|
+
|
148
|
+
// Load SAAFE Redirection Flow
|
149
|
+
val baseUrl = "https://saafe-app.com/login"
|
150
|
+
val urlParams = "?fi=$financialInstitutionId&ecreq=$encryptedRequest&reqdate=$requestDate&platform=android&theme=system"
|
151
|
+
webView.loadUrl(baseUrl + urlParams)
|
152
|
+
}
|
153
|
+
|
154
|
+
override fun onBackPressed() {
|
155
|
+
if (webView.canGoBack()) {
|
156
|
+
webView.goBack()
|
157
|
+
} else {
|
158
|
+
// Show confirmation dialog before exiting
|
159
|
+
// This is important as closing mid-flow can cause issues
|
160
|
+
// Implementation of confirmation dialog omitted for brevity
|
161
|
+
}
|
162
|
+
}
|
163
|
+
}
|
164
|
+
```
|
165
|
+
|
166
|
+
### Web Integration
|
167
|
+
|
168
|
+
#### React Application Integration
|
169
|
+
|
170
|
+
```tsx
|
171
|
+
import React, { useEffect, useRef } from 'react';
|
172
|
+
|
173
|
+
interface SAFERedirectionProps {
|
174
|
+
financialInstitutionId: string;
|
175
|
+
encryptedRequest: string;
|
176
|
+
requestDate: string;
|
177
|
+
onSuccess?: () => void;
|
178
|
+
onRejection?: () => void;
|
179
|
+
theme?: 'light' | 'dark' | 'system';
|
180
|
+
}
|
181
|
+
|
182
|
+
const SAFERedirection: React.FC<SAFERedirectionProps> = ({
|
183
|
+
financialInstitutionId,
|
184
|
+
encryptedRequest,
|
185
|
+
requestDate,
|
186
|
+
onSuccess,
|
187
|
+
onRejection,
|
188
|
+
theme = 'system'
|
189
|
+
}) => {
|
190
|
+
const iframeRef = useRef<HTMLIFrameElement>(null);
|
191
|
+
|
192
|
+
useEffect(() => {
|
193
|
+
const handleMessage = (event: MessageEvent) => {
|
194
|
+
// Verify origin for security
|
195
|
+
if (event.origin !== 'https://saafe-app.com') return;
|
196
|
+
|
197
|
+
// Process messages from the iframe
|
198
|
+
if (event.data.type === 'saafe:success') {
|
199
|
+
onSuccess?.();
|
200
|
+
} else if (event.data.type === 'saafe:rejection') {
|
201
|
+
onRejection?.();
|
202
|
+
}
|
203
|
+
};
|
204
|
+
|
205
|
+
window.addEventListener('message', handleMessage);
|
206
|
+
return () => window.removeEventListener('message', handleMessage);
|
207
|
+
}, [onSuccess, onRejection]);
|
208
|
+
|
209
|
+
const safeUrl = `https://saafe-app.com/login?fi=${encodeURIComponent(financialInstitutionId)}&ecreq=${encodeURIComponent(encryptedRequest)}&reqdate=${encodeURIComponent(requestDate)}&platform=web&theme=${theme}`;
|
210
|
+
|
211
|
+
return (
|
212
|
+
<iframe
|
213
|
+
ref={iframeRef}
|
214
|
+
src={safeUrl}
|
215
|
+
style={{ width: '100%', height: '600px', border: 'none' }}
|
216
|
+
title="SAAFE Account Linking"
|
217
|
+
allow="camera; microphone"
|
218
|
+
/>
|
219
|
+
);
|
220
|
+
};
|
221
|
+
|
222
|
+
export default SAFERedirection;
|
223
|
+
```
|
224
|
+
|
225
|
+
## URL Parameters Reference
|
226
|
+
|
227
|
+
| Parameter | Description | Valid Values | Required |
|
228
|
+
|-----------|-------------|-------------|----------|
|
229
|
+
| fi | Financial Institution ID | String | Yes |
|
230
|
+
| ecreq | Encrypted Request | String | Yes |
|
231
|
+
| reqdate | Request Date | String | Yes |
|
232
|
+
| profile | User Profile | String | No |
|
233
|
+
| platform | Client Platform | ios, android, react-native, flutter, web | No |
|
234
|
+
| theme | Application Theme | light, dark, system | No |
|
235
|
+
|
236
|
+
### Detailed Parameter Information
|
237
|
+
|
238
|
+
#### Financial Institution ID (fi)
|
239
|
+
|
240
|
+
Unique identifier for the financial institution being accessed. This is provided by the SAAFE platform.
|
241
|
+
|
242
|
+
#### Encrypted Request (ecreq)
|
243
|
+
|
244
|
+
A JWT-encoded request payload that contains:
|
245
|
+
- User identification information
|
246
|
+
- Request scope (what data is being requested)
|
247
|
+
- Expiration time
|
248
|
+
- Signature
|
249
|
+
|
250
|
+
The encryption ensures that request parameters cannot be tampered with.
|
251
|
+
|
252
|
+
#### Request Date (reqdate)
|
253
|
+
|
254
|
+
ISO8601 formatted date-time string that indicates when the request was initiated. Used for security validation.
|
255
|
+
|
256
|
+
#### Platform (platform)
|
257
|
+
|
258
|
+
Identifies the client platform for optimized display and behavior:
|
259
|
+
- **ios**: iOS-specific optimizations (status bar handling, iOS-style UI)
|
260
|
+
- **android**: Android optimizations
|
261
|
+
- **react-native**: React Native WebView optimizations
|
262
|
+
- **flutter**: Flutter WebView optimizations
|
263
|
+
- **web**: Standard web experience
|
264
|
+
|
265
|
+
#### Theme (theme)
|
266
|
+
|
267
|
+
Controls the visual theme:
|
268
|
+
- **light**: Forces light theme
|
269
|
+
- **dark**: Forces dark theme
|
270
|
+
- **system**: Uses device theme preference (default)
|
271
|
+
|
272
|
+
## Security Considerations
|
273
|
+
|
274
|
+
### Cross-Origin Restrictions
|
275
|
+
|
276
|
+
When embedding the SAAFE Redirection Flow in a web application via an iframe, be aware of potential cross-origin restrictions. The application handles document displays to avoid cross-origin issues.
|
277
|
+
|
278
|
+
### Navigation Flow Protection
|
279
|
+
|
280
|
+
The SAAFE Redirection Flow includes navigation protection to warn users before exiting a flow in progress. This helps prevent accidental cancellations.
|
281
|
+
|
282
|
+
### Secure Communication
|
283
|
+
|
284
|
+
For mobile WebViews, use the provided URL interception patterns to securely communicate the flow outcome back to your application.
|
285
|
+
|
286
|
+
## Callback Handling
|
287
|
+
|
288
|
+
### Success Callback
|
289
|
+
|
290
|
+
When an account linking flow completes successfully, the application navigates to the `/success` route. For iframe integrations, a message is posted to the parent window. For WebViews, you can intercept this URL to handle success in your native application.
|
291
|
+
|
292
|
+
### Rejection Callback
|
293
|
+
|
294
|
+
If the user rejects the consent, the application navigates to the `/rejected` route. Similar to the success case, messages are posted for iframes and the URL can be intercepted in WebViews.
|
295
|
+
|
296
|
+
## Styling and Customization
|
297
|
+
|
298
|
+
### Custom Styling
|
299
|
+
|
300
|
+
You can provide custom styling parameters via the URL:
|
301
|
+
- Primary button color
|
302
|
+
- Background colors
|
303
|
+
- Font styles
|
304
|
+
|
305
|
+
These are applied via CSS variables at runtime.
|
306
|
+
|
307
|
+
## Testing
|
308
|
+
|
309
|
+
To test your integration, you can use the following test credentials:
|
310
|
+
|
311
|
+
- Financial Institution ID: `test_fi`
|
312
|
+
- Encrypted Request: `test_encrypted_request`
|
313
|
+
- Request Date: Current timestamp
|
314
|
+
|
315
|
+
## Troubleshooting
|
316
|
+
|
317
|
+
### Common Issues
|
318
|
+
|
319
|
+
1. **Blank Screen**: Ensure all required URL parameters are provided and correctly encoded.
|
320
|
+
2. **Navigation Issues**: If the flow doesn't complete, check your URL interception logic in WebViews.
|
321
|
+
3. **Cross-Origin Errors**: For web iframe integration, ensure your domain is whitelisted.
|
322
|
+
|
323
|
+
### Support
|
324
|
+
|
325
|
+
For further assistance, contact the SAAFE support team at support@saafe-platform.com.
|