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,124 @@
1
+ # Semantic Release Setup
2
+
3
+ This project uses [semantic-release](https://github.com/semantic-release/semantic-release) for automated version management and package publishing.
4
+
5
+ ## Commit Message Format
6
+
7
+ We use the [Angular Commit Message Convention](https://github.com/angular/angular/blob/master/CONTRIBUTING.md#-commit-message-format). Each commit message consists of a **header**, a **body**, and a **footer**.
8
+
9
+ ### Header
10
+
11
+ The header has a special format that includes a **type**, a **scope**, and a **subject**:
12
+
13
+ ```
14
+ <type>(<scope>): <subject>
15
+ ```
16
+
17
+ #### Type
18
+
19
+ Must be one of the following:
20
+
21
+ - **feat**: A new feature (correlates with MINOR in semantic versioning)
22
+ - **fix**: A bug fix (correlates with PATCH in semantic versioning)
23
+ - **docs**: Documentation only changes
24
+ - **style**: Changes that do not affect the meaning of the code
25
+ - **refactor**: A code change that neither fixes a bug nor adds a feature
26
+ - **perf**: A code change that improves performance
27
+ - **test**: Adding missing tests or correcting existing tests
28
+ - **chore**: Changes to the build process or auxiliary tools
29
+
30
+ #### Scope
31
+
32
+ The scope should be the name of the npm package affected (as perceived by the person reading the changelog generated from commit messages).
33
+
34
+ Examples:
35
+ - `ui`
36
+ - `auth`
37
+ - `api`
38
+ - `components`
39
+
40
+ #### Subject
41
+
42
+ The subject contains a succinct description of the change:
43
+
44
+ - Use the imperative, present tense: "change" not "changed" nor "changes"
45
+ - Don't capitalize the first letter
46
+ - No dot (.) at the end
47
+
48
+ ### Breaking Changes
49
+
50
+ To indicate a breaking change, add `BREAKING CHANGE:` in the footer of the commit message, or append `!` after the type/scope:
51
+
52
+ ```
53
+ feat!: drop support for Node 12
54
+ ```
55
+
56
+ or
57
+
58
+ ```
59
+ feat(api): add new authentication method
60
+
61
+ BREAKING CHANGE: The old authentication method is no longer supported.
62
+ ```
63
+
64
+ ## Release Types
65
+
66
+ | Commit message | Release type |
67
+ |---|---|
68
+ | `fix(pencil): stop graphite breaking when too much pressure applied` | Patch Release |
69
+ | `feat(pencil): add 'graphiteWidth' option` | Feature Release |
70
+ | `perf(pencil): remove graphiteWidth option`<br><br>`BREAKING CHANGE: The graphiteWidth option has been removed.` | Breaking Release |
71
+
72
+ ## Examples
73
+
74
+ ### Feature
75
+ ```
76
+ feat(ui): add version display component
77
+
78
+ - Add responsive version display component
79
+ - Include build date information
80
+ - Support multiple display variants
81
+ ```
82
+
83
+ ### Bug Fix
84
+ ```
85
+ fix(auth): resolve login timeout issue
86
+
87
+ - Increase timeout duration for mobile networks
88
+ - Add better error handling for network failures
89
+ ```
90
+
91
+ ### Breaking Change
92
+ ```
93
+ feat(api)!: update authentication flow
94
+
95
+ BREAKING CHANGE: Authentication now requires OAuth 2.0 instead of API keys
96
+ ```
97
+
98
+ ## Running Semantic Release
99
+
100
+ ### Locally (Dry Run)
101
+ ```bash
102
+ npm run semantic-release:dry-run
103
+ ```
104
+
105
+ ### Production
106
+ Semantic release runs automatically on the CI/CD pipeline when code is pushed to the `main` branch.
107
+
108
+ ## Configuration
109
+
110
+ The semantic release configuration is defined in `.releaserc.json`:
111
+
112
+ - **Branches**: `main` for production releases, `develop` for beta releases
113
+ - **Plugins**: Commit analyzer, release notes generator, changelog, git, and GitHub releases
114
+ - **Assets**: Updates `package.json`, `package-lock.json`, and `CHANGELOG.md`
115
+
116
+ ## Version Display
117
+
118
+ The application automatically displays the current version in:
119
+
120
+ 1. **Mobile Footer**: Compact version display
121
+ 2. **Desktop Footer**: Version with build date
122
+ 3. **Desktop Sidebar**: Minimal version display
123
+
124
+ The version information is automatically injected during the build process using Vite environment variables.
@@ -0,0 +1,206 @@
1
+ # SAAFE Redirection Flow - User Journey
2
+
3
+ This document outlines the typical user journey through the SAAFE Redirection Flow application, from initial loading to successful account linking or rejection.
4
+
5
+ ## User Flow Overview
6
+
7
+ The SAAFE Redirection Flow guides users through a structured process to securely link their financial accounts. The typical flow consists of these key stages:
8
+
9
+ 1. **Application Loading**
10
+ 2. **Authentication**
11
+ 3. **Account Discovery**
12
+ 4. **Account Selection**
13
+ 5. **Consent Review**
14
+ 6. **Completion (Success or Rejection)**
15
+
16
+ Below is a detailed explanation of each stage, including screenshots, user interactions, and technical considerations.
17
+
18
+ ## 1. Application Loading
19
+
20
+ ### Initial Experience
21
+
22
+ When users first access the SAAFE Redirection Flow (typically through a partner app's WebView or iframe), they see:
23
+
24
+ - Loading indicator while URL parameters are decoded
25
+ - Branded experience with partner's logo and styling (if configured)
26
+ - Platform-specific UI optimizations based on the `platform` parameter
27
+
28
+ ### Technical Details
29
+
30
+ - URL parameters (`fi`, `ecreq`, `reqdate`) are validated and decoded
31
+ - Theme is initialized based on the `theme` parameter or system preference
32
+ - Custom styling is applied if provided
33
+ - Analytics event `APP_LOAD` is triggered
34
+
35
+ ## 2. Authentication
36
+
37
+ ### User Actions
38
+
39
+ Users authenticate themselves with their financial institution:
40
+
41
+ 1. Enter login credentials (username/password)
42
+ 2. Verify identity with One-Time Password (OTP) if required
43
+ 3. View and accept the financial institution's terms and conditions
44
+
45
+ ### UI Components
46
+
47
+ - Login form with validation
48
+ - OTP input with auto-focus and clipboard support
49
+ - Terms and conditions modal (platform-specific display)
50
+ - Error messages for invalid credentials
51
+
52
+ ### Technical Details
53
+
54
+ - Secure credential transmission
55
+ - Session token management
56
+ - Authentication state management in Zustand store
57
+ - Platform-specific document handling
58
+
59
+ ## 3. Account Discovery
60
+
61
+ ### User Actions
62
+
63
+ After successful authentication, users can:
64
+
65
+ 1. View financial institutions available for linking
66
+ 2. Browse by category (Banks, NBFCs, Insurance, etc.)
67
+ 3. Search for specific institutions
68
+ 4. Select their institution
69
+
70
+ ### UI Components
71
+
72
+ - Category tabs or filters
73
+ - Search bar with autocomplete
74
+ - Institution cards with logos
75
+ - Skeleton loaders during data fetching
76
+
77
+ ### Technical Details
78
+
79
+ - Data fetching with React Query
80
+ - Caching of institution list
81
+ - Search functionality with debounce
82
+ - Analytics events for tracking selections
83
+
84
+ ## 4. Account Selection
85
+
86
+ ### User Actions
87
+
88
+ After selecting an institution, users can:
89
+
90
+ 1. View their accounts at the selected institution
91
+ 2. Select which accounts to link
92
+ 3. View account details (type, balance, etc.)
93
+ 4. Proceed to consent review
94
+
95
+ ### UI Components
96
+
97
+ - Account cards with details
98
+ - Checkbox selection for multiple accounts
99
+ - Continue button with disabled state when no accounts selected
100
+ - Information tooltips for account types
101
+
102
+ ### Technical Details
103
+
104
+ - Account data fetching and state management
105
+ - Selection tracking in local state
106
+ - Validation before proceeding to next step
107
+ - Progressive disclosure of information
108
+
109
+ ## 5. Consent Review
110
+
111
+ ### User Actions
112
+
113
+ Before finalizing the account linking, users:
114
+
115
+ 1. Review what data will be shared
116
+ 2. See who will receive the data (third-party application)
117
+ 3. Understand how the data will be used
118
+ 4. Choose to approve or reject the consent request
119
+
120
+ ### UI Components
121
+
122
+ - Detailed consent information
123
+ - Data sharing scope visualization
124
+ - Clear accept and reject buttons
125
+ - Terms and policies links
126
+
127
+ ### Technical Details
128
+
129
+ - Consent data preparation
130
+ - Tracking consent review time
131
+ - Preparing for submission
132
+ - Navigation protection to prevent accidental exits
133
+
134
+ ## 6. Completion
135
+
136
+ ### Success Path
137
+
138
+ If the user approves the consent:
139
+
140
+ 1. Success screen confirms account linking
141
+ 2. Confirmation of which accounts were linked
142
+ 3. Next steps or return to partner application
143
+ 4. Optional promotional content
144
+
145
+ ### Rejection Path
146
+
147
+ If the user rejects the consent:
148
+
149
+ 1. Rejection confirmation screen
150
+ 2. Explanation of implications
151
+ 3. Option to try again or return to partner application
152
+
153
+ ### Technical Details
154
+
155
+ - Final API submission of user selections
156
+ - Success/failure handling
157
+ - Communication back to parent application
158
+ - Session cleanup
159
+ - Final analytics events
160
+
161
+ ## Special Flows
162
+
163
+ ### Returning Users
164
+
165
+ For users who have previously linked accounts:
166
+
167
+ 1. View currently linked accounts
168
+ 2. Option to link additional accounts
169
+ 3. Option to unlink existing accounts
170
+
171
+ ### Error Handling
172
+
173
+ When errors occur during the flow:
174
+
175
+ 1. User-friendly error messages
176
+ 2. Retry options where appropriate
177
+ 3. Fallback paths for recoverable errors
178
+ 4. Contact support options for unrecoverable errors
179
+
180
+ ## Platform-Specific Differences
181
+
182
+ ### Mobile vs Web
183
+
184
+ The user experience adjusts based on platform:
185
+
186
+ - **Mobile**: Full-screen optimized UI, bottom sheet dialogs, mobile-specific gestures
187
+ - **Web**: More spacious layout, hover states, keyboard shortcuts
188
+
189
+ ### iOS vs Android
190
+
191
+ Platform-specific optimizations:
192
+
193
+ - **iOS**: iOS-style UI components, respects safe areas, iOS-specific gestures
194
+ - **Android**: Material Design influenced components, Android back button handling
195
+
196
+ ## Analytics Touchpoints
197
+
198
+ The application tracks user progress through the journey:
199
+
200
+ - Page views for each step
201
+ - Time spent on each step
202
+ - Drop-off points
203
+ - Success/failure rates
204
+ - Error encounters
205
+
206
+ This data helps improve the flow and identify potential issues.
@@ -0,0 +1,28 @@
1
+ import js from '@eslint/js'
2
+ import globals from 'globals'
3
+ import reactHooks from 'eslint-plugin-react-hooks'
4
+ import reactRefresh from 'eslint-plugin-react-refresh'
5
+ import tseslint from 'typescript-eslint'
6
+
7
+ export default tseslint.config(
8
+ { ignores: ['dist'] },
9
+ {
10
+ extends: [js.configs.recommended, ...tseslint.configs.recommended],
11
+ files: ['**/*.{ts,tsx}'],
12
+ languageOptions: {
13
+ ecmaVersion: 2020,
14
+ globals: globals.browser,
15
+ },
16
+ plugins: {
17
+ 'react-hooks': reactHooks,
18
+ 'react-refresh': reactRefresh,
19
+ },
20
+ rules: {
21
+ ...reactHooks.configs.recommended.rules,
22
+ 'react-refresh/only-export-components': [
23
+ 'warn',
24
+ { allowConstantExport: true },
25
+ ],
26
+ },
27
+ },
28
+ )
package/index.html ADDED
@@ -0,0 +1,19 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <link rel="icon" type="image/svg+xml" href="/saafe-icon.svg" />
6
+ <link rel="preconnect" href="https://fonts.googleapis.com">
7
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
8
+ <link
9
+ href="https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap"
10
+ rel="stylesheet"
11
+ />
12
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
13
+ <title>Saafe</title>
14
+ </head>
15
+ <body>
16
+ <div id="root"></div>
17
+ <script type="module" src="/src/main.tsx"></script>
18
+ </body>
19
+ </html>
package/install.sh ADDED
@@ -0,0 +1,198 @@
1
+ #!/bin/bash
2
+
3
+ # Color definitions
4
+ RED='\033[0;31m'
5
+ GREEN='\033[0;32m'
6
+ YELLOW='\033[1;33m'
7
+ BLUE='\033[0;34m'
8
+ CYAN='\033[0;36m'
9
+ NC='\033[0m' # No Color
10
+
11
+ # Logo
12
+ print_logo() {
13
+ echo -e "${CYAN}"
14
+ cat << "EOF"
15
+ ██████╗██╗ ██╗██████╗ ███████╗ ██████╗ ██████╗ ██████╗ ██████╗ ██████╗
16
+ ██╔════╝██║ ██║██╔══██╗██╔════╝██╔═══██╗██╔══██╗ ██╔══██╗██╔══██╗██╔═══██╗
17
+ ██║ ██║ ██║██████╔╝███████╗██║ ██║██████╔╝ ██████╔╝██████╔╝██║ ██║
18
+ ██║ ██║ ██║██╔══██╗╚════██║██║ ██║██╔══██╗ ██╔═══╝ ██╔══██╗██║ ██║
19
+ ╚██████╗╚██████╔╝██║ ██║███████║╚██████╔╝██║ ██║ ██║ ██║ ██║╚██████╔╝
20
+ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝
21
+ EOF
22
+ echo -e "${NC}"
23
+ }
24
+
25
+ # Get download folder path
26
+ get_downloads_dir() {
27
+ if [[ "$(uname)" == "Darwin" ]]; then
28
+ echo "$HOME/Downloads"
29
+ else
30
+ if [ -f "$HOME/.config/user-dirs.dirs" ]; then
31
+ . "$HOME/.config/user-dirs.dirs"
32
+ echo "${XDG_DOWNLOAD_DIR:-$HOME/Downloads}"
33
+ else
34
+ echo "$HOME/Downloads"
35
+ fi
36
+ fi
37
+ }
38
+
39
+ # Get latest version
40
+ get_latest_version() {
41
+ echo -e "${CYAN}ℹ️ Checking latest version...${NC}"
42
+ latest_release=$(curl -s https://api.github.com/repos/yeongpin/cursor-free-vip/releases/latest) || {
43
+ echo -e "${RED}❌ Cannot get latest version information${NC}"
44
+ exit 1
45
+ }
46
+
47
+ VERSION=$(echo "$latest_release" | grep -o '"tag_name": ".*"' | cut -d'"' -f4 | tr -d 'v')
48
+ if [ -z "$VERSION" ]; then
49
+ echo -e "${RED}❌ Failed to parse version from GitHub API response:\n${latest_release}"
50
+ exit 1
51
+ fi
52
+
53
+ echo -e "${GREEN}✅ Found latest version: ${VERSION}${NC}"
54
+ }
55
+
56
+ # Detect system type and architecture
57
+ detect_os() {
58
+ if [[ "$(uname)" == "Darwin" ]]; then
59
+ # Detect macOS architecture
60
+ ARCH=$(uname -m)
61
+ if [[ "$ARCH" == "arm64" ]]; then
62
+ OS="mac_arm64"
63
+ echo -e "${CYAN}ℹ️ Detected macOS ARM64 architecture${NC}"
64
+ else
65
+ OS="mac_intel"
66
+ echo -e "${CYAN}ℹ️ Detected macOS Intel architecture${NC}"
67
+ fi
68
+ elif [[ "$(uname)" == "Linux" ]]; then
69
+ # Detect Linux architecture
70
+ ARCH=$(uname -m)
71
+ if [[ "$ARCH" == "aarch64" || "$ARCH" == "arm64" ]]; then
72
+ OS="linux_arm64"
73
+ echo -e "${CYAN}ℹ️ Detected Linux ARM64 architecture${NC}"
74
+ else
75
+ OS="linux_x64"
76
+ echo -e "${CYAN}ℹ️ Detected Linux x64 architecture${NC}"
77
+ fi
78
+ else
79
+ # Assume Windows
80
+ OS="windows"
81
+ echo -e "${CYAN}ℹ️ Detected Windows system${NC}"
82
+ fi
83
+ }
84
+
85
+ # Install and download
86
+ install_cursor_free_vip() {
87
+ local downloads_dir=$(get_downloads_dir)
88
+ local binary_name="CursorFreeVIP_${VERSION}_${OS}"
89
+ local binary_path="${downloads_dir}/${binary_name}"
90
+ local download_url="https://github.com/yeongpin/cursor-free-vip/releases/download/v${VERSION}/${binary_name}"
91
+
92
+ # Check if file already exists
93
+ if [ -f "${binary_path}" ]; then
94
+ echo -e "${GREEN}✅ Found existing installation file${NC}"
95
+ echo -e "${CYAN}ℹ️ Location: ${binary_path}${NC}"
96
+
97
+ # Check if running as root
98
+ if [ "$EUID" -ne 0 ]; then
99
+ echo -e "${YELLOW}⚠️ Requesting administrator privileges...${NC}"
100
+ if command -v sudo >/dev/null 2>&1; then
101
+ echo -e "${CYAN}ℹ️ Starting program with sudo...${NC}"
102
+ sudo chmod +x "${binary_path}"
103
+ sudo "${binary_path}"
104
+ else
105
+ echo -e "${YELLOW}⚠️ sudo not found, trying to run normally...${NC}"
106
+ chmod +x "${binary_path}"
107
+ "${binary_path}"
108
+ fi
109
+ else
110
+ # Already running as root
111
+ echo -e "${CYAN}ℹ️ Already running as root, starting program...${NC}"
112
+ chmod +x "${binary_path}"
113
+ "${binary_path}"
114
+ fi
115
+ return
116
+ fi
117
+
118
+ echo -e "${CYAN}ℹ️ No existing installation file found, starting download...${NC}"
119
+ echo -e "${CYAN}ℹ️ Downloading to ${downloads_dir}...${NC}"
120
+ echo -e "${CYAN}ℹ️ Download link: ${download_url}${NC}"
121
+
122
+ # Check if file exists
123
+ if curl --output /dev/null --silent --head --fail "$download_url"; then
124
+ echo -e "${GREEN}✅ File exists, starting download...${NC}"
125
+ else
126
+ echo -e "${RED}❌ Download link does not exist: ${download_url}${NC}"
127
+ echo -e "${YELLOW}⚠️ Trying without architecture...${NC}"
128
+
129
+ # Try without architecture
130
+ if [[ "$OS" == "mac_arm64" || "$OS" == "mac_intel" ]]; then
131
+ OS="mac"
132
+ binary_name="CursorFreeVIP_${VERSION}_${OS}"
133
+ download_url="https://github.com/yeongpin/cursor-free-vip/releases/download/v${VERSION}/${binary_name}"
134
+ echo -e "${CYAN}ℹ️ New download link: ${download_url}${NC}"
135
+
136
+ if ! curl --output /dev/null --silent --head --fail "$download_url"; then
137
+ echo -e "${RED}❌ New download link does not exist${NC}"
138
+ exit 1
139
+ fi
140
+ elif [[ "$OS" == "linux_x64" || "$OS" == "linux_arm64" ]]; then
141
+ OS="linux"
142
+ binary_name="CursorFreeVIP_${VERSION}_${OS}"
143
+ download_url="https://github.com/yeongpin/cursor-free-vip/releases/download/v${VERSION}/${binary_name}"
144
+ echo -e "${CYAN}ℹ️ New download link: ${download_url}${NC}"
145
+
146
+ if ! curl --output /dev/null --silent --head --fail "$download_url"; then
147
+ echo -e "${RED}❌ New download link does not exist${NC}"
148
+ exit 1
149
+ fi
150
+ else
151
+ exit 1
152
+ fi
153
+ fi
154
+
155
+ # Download file
156
+ if ! curl -L -o "${binary_path}" "$download_url"; then
157
+ echo -e "${RED}❌ Download failed${NC}"
158
+ exit 1
159
+ fi
160
+
161
+ # Check downloaded file size
162
+ local file_size=$(stat -f%z "${binary_path}" 2>/dev/null || stat -c%s "${binary_path}" 2>/dev/null)
163
+ echo -e "${CYAN}ℹ️ Downloaded file size: ${file_size} bytes${NC}"
164
+
165
+ # If file is too small, it might be an error message
166
+ if [ "$file_size" -lt 1000 ]; then
167
+ echo -e "${YELLOW}⚠️ Warning: Downloaded file is too small, possibly not a valid executable file${NC}"
168
+ echo -e "${YELLOW}⚠️ File content:${NC}"
169
+ cat "${binary_path}"
170
+ echo ""
171
+ echo -e "${RED}❌ Download failed, please check version and operating system${NC}"
172
+ exit 1
173
+ fi
174
+
175
+ echo -e "${CYAN}ℹ️ Setting executable permissions...${NC}"
176
+ if chmod +x "${binary_path}"; then
177
+ echo -e "${GREEN}✅ Installation completed!${NC}"
178
+ echo -e "${CYAN}ℹ️ Program downloaded to: ${binary_path}${NC}"
179
+ echo -e "${CYAN}ℹ️ Starting program...${NC}"
180
+
181
+ # Run program directly
182
+ "${binary_path}"
183
+ else
184
+ echo -e "${RED}❌ Installation failed${NC}"
185
+ exit 1
186
+ fi
187
+ }
188
+
189
+ # Main program
190
+ main() {
191
+ print_logo
192
+ get_latest_version
193
+ detect_os
194
+ install_cursor_free_vip
195
+ }
196
+
197
+ # Run main program
198
+ main
package/package.json ADDED
@@ -0,0 +1,115 @@
1
+ {
2
+ "name": "saafe-redirection-flow",
3
+ "version": "2.0.0",
4
+ "type": "module",
5
+ "scripts": {
6
+ "dev": "vite",
7
+ "build": "tsc -b && vite build",
8
+ "build:production": "vite build --mode production",
9
+ "build:stage": "vite build --mode stage",
10
+ "build:sandbox": "vite build --mode sandbox",
11
+ "build:gh": "vite build --base=/saafe-redirection-flow/",
12
+ "lint": "eslint .",
13
+ "preview": "vite preview",
14
+ "preview:production": "vite preview --mode production",
15
+ "preview:stage": "vite preview --mode stage",
16
+ "preview:sandbox": "vite preview --mode sandbox",
17
+ "storybook": "storybook dev -p 6006",
18
+ "build-storybook": "storybook build",
19
+ "semantic-release": "semantic-release",
20
+ "semantic-release:dry-run": "semantic-release --dry-run",
21
+ "release": "npm run semantic-release",
22
+ "release:dry": "npm run semantic-release:dry-run",
23
+ "version:check": "echo \"Current version: $(node -p 'require(\"./package.json\").version')\"",
24
+ "env:check": "node -e \"console.log('Environment:', process.env.NODE_ENV || 'development'); console.log('Available env vars:', Object.keys(process.env).filter(k => k.startsWith('VITE_')).join(', '))\"",
25
+ "env:list": "ls -la .env*",
26
+ "build:all": "npm run build:production && npm run build:stage && npm run build:sandbox",
27
+ "release:real": "semantic-release --no-ci",
28
+ "release:prod": "git checkout prod && npm run release:real"
29
+ },
30
+ "dependencies": {
31
+ "@hookform/resolvers": "^4.1.3",
32
+ "@radix-ui/react-avatar": "^1.1.3",
33
+ "@radix-ui/react-checkbox": "^1.1.4",
34
+ "@radix-ui/react-collapsible": "^1.1.3",
35
+ "@radix-ui/react-dialog": "^1.1.6",
36
+ "@radix-ui/react-dropdown-menu": "^2.1.6",
37
+ "@radix-ui/react-icons": "^1.3.2",
38
+ "@radix-ui/react-label": "^2.1.2",
39
+ "@radix-ui/react-popover": "^1.1.6",
40
+ "@radix-ui/react-radio-group": "^1.2.3",
41
+ "@radix-ui/react-scroll-area": "^1.2.3",
42
+ "@radix-ui/react-select": "^2.1.7",
43
+ "@radix-ui/react-separator": "^1.1.2",
44
+ "@radix-ui/react-slot": "^1.2.0",
45
+ "@radix-ui/react-tabs": "^1.1.3",
46
+ "@radix-ui/react-tooltip": "^1.1.8",
47
+ "@tailwindcss/vite": "^4.0.14",
48
+ "@tanstack/react-query": "^5.71.5",
49
+ "@tanstack/react-query-devtools": "^5.71.5",
50
+ "axios": "^1.8.4",
51
+ "class-variance-authority": "^0.7.1",
52
+ "clsx": "^2.1.1",
53
+ "framer-motion": "^12.6.0",
54
+ "i18next": "^24.2.3",
55
+ "i18next-browser-languagedetector": "^8.0.4",
56
+ "input-otp": "^1.4.2",
57
+ "lucide-react": "^0.482.0",
58
+ "next-themes": "^0.4.6",
59
+ "posthog-js": "^1.234.10",
60
+ "react": "^19.0.0",
61
+ "react-day-picker": "^9.6.7",
62
+ "react-dom": "^19.0.0",
63
+ "react-hook-form": "^7.54.2",
64
+ "react-i18next": "^15.4.1",
65
+ "react-router-dom": "^7.4.0",
66
+ "sonner": "^2.0.3",
67
+ "tailwind-merge": "^3.0.2",
68
+ "tailwindcss": "^4.0.14",
69
+ "tailwindcss-animate": "^1.0.7",
70
+ "zod": "^3.24.2",
71
+ "zustand": "^5.0.3"
72
+ },
73
+ "devDependencies": {
74
+ "@chromatic-com/storybook": "^3.2.6",
75
+ "@eslint/js": "^9.21.0",
76
+ "@semantic-release/changelog": "^6.0.3",
77
+ "@semantic-release/git": "^10.0.1",
78
+ "@semantic-release/npm": "^12.0.1",
79
+ "@storybook/addon-essentials": "^8.6.10",
80
+ "@storybook/addon-interactions": "^8.6.10",
81
+ "@storybook/addon-links": "^8.6.10",
82
+ "@storybook/addon-onboarding": "^8.6.10",
83
+ "@storybook/blocks": "^8.6.10",
84
+ "@storybook/experimental-addon-test": "^8.6.10",
85
+ "@storybook/react": "^8.6.10",
86
+ "@storybook/react-vite": "^8.6.10",
87
+ "@storybook/test": "^8.6.10",
88
+ "@storybook/testing-library": "^0.2.2",
89
+ "@types/node": "^22.13.10",
90
+ "@types/react": "^19.0.10",
91
+ "@types/react-dom": "^19.0.4",
92
+ "@vitejs/plugin-react": "^4.3.4",
93
+ "@vitest/browser": "^3.0.9",
94
+ "@vitest/coverage-v8": "^3.0.9",
95
+ "cross-env": "^7.0.3",
96
+ "eslint": "^9.21.0",
97
+ "eslint-plugin-react-hooks": "^5.1.0",
98
+ "eslint-plugin-react-refresh": "^0.4.19",
99
+ "eslint-plugin-storybook": "^0.12.0",
100
+ "globals": "^15.15.0",
101
+ "playwright": "^1.51.1",
102
+ "react-docgen-typescript": "^2.2.2",
103
+ "semantic-release": "^24.2.5",
104
+ "storybook": "^8.6.10",
105
+ "typescript": "~5.7.2",
106
+ "typescript-eslint": "^8.24.1",
107
+ "vite": "^6.2.0",
108
+ "vitest": "^3.0.9"
109
+ },
110
+ "eslintConfig": {
111
+ "extends": [
112
+ "plugin:storybook/recommended"
113
+ ]
114
+ }
115
+ }
Binary file