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,32 @@
|
|
1
|
+
.storybook-header {
|
2
|
+
display: flex;
|
3
|
+
justify-content: space-between;
|
4
|
+
align-items: center;
|
5
|
+
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
|
6
|
+
padding: 15px 20px;
|
7
|
+
font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
8
|
+
}
|
9
|
+
|
10
|
+
.storybook-header svg {
|
11
|
+
display: inline-block;
|
12
|
+
vertical-align: top;
|
13
|
+
}
|
14
|
+
|
15
|
+
.storybook-header h1 {
|
16
|
+
display: inline-block;
|
17
|
+
vertical-align: top;
|
18
|
+
margin: 6px 0 6px 10px;
|
19
|
+
font-weight: 700;
|
20
|
+
font-size: 20px;
|
21
|
+
line-height: 1;
|
22
|
+
}
|
23
|
+
|
24
|
+
.storybook-header button + button {
|
25
|
+
margin-left: 10px;
|
26
|
+
}
|
27
|
+
|
28
|
+
.storybook-header .welcome {
|
29
|
+
margin-right: 10px;
|
30
|
+
color: #333;
|
31
|
+
font-size: 14px;
|
32
|
+
}
|
@@ -0,0 +1,68 @@
|
|
1
|
+
.storybook-page {
|
2
|
+
margin: 0 auto;
|
3
|
+
padding: 48px 20px;
|
4
|
+
max-width: 600px;
|
5
|
+
color: #333;
|
6
|
+
font-size: 14px;
|
7
|
+
line-height: 24px;
|
8
|
+
font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
9
|
+
}
|
10
|
+
|
11
|
+
.storybook-page h2 {
|
12
|
+
display: inline-block;
|
13
|
+
vertical-align: top;
|
14
|
+
margin: 0 0 4px;
|
15
|
+
font-weight: 700;
|
16
|
+
font-size: 32px;
|
17
|
+
line-height: 1;
|
18
|
+
}
|
19
|
+
|
20
|
+
.storybook-page p {
|
21
|
+
margin: 1em 0;
|
22
|
+
}
|
23
|
+
|
24
|
+
.storybook-page a {
|
25
|
+
color: inherit;
|
26
|
+
}
|
27
|
+
|
28
|
+
.storybook-page ul {
|
29
|
+
margin: 1em 0;
|
30
|
+
padding-left: 30px;
|
31
|
+
}
|
32
|
+
|
33
|
+
.storybook-page li {
|
34
|
+
margin-bottom: 8px;
|
35
|
+
}
|
36
|
+
|
37
|
+
.storybook-page .tip {
|
38
|
+
display: inline-block;
|
39
|
+
vertical-align: top;
|
40
|
+
margin-right: 10px;
|
41
|
+
border-radius: 1em;
|
42
|
+
background: #e7fdd8;
|
43
|
+
padding: 4px 12px;
|
44
|
+
color: #357a14;
|
45
|
+
font-weight: 700;
|
46
|
+
font-size: 11px;
|
47
|
+
line-height: 12px;
|
48
|
+
}
|
49
|
+
|
50
|
+
.storybook-page .tip-wrapper {
|
51
|
+
margin-top: 40px;
|
52
|
+
margin-bottom: 40px;
|
53
|
+
font-size: 13px;
|
54
|
+
line-height: 20px;
|
55
|
+
}
|
56
|
+
|
57
|
+
.storybook-page .tip-wrapper svg {
|
58
|
+
display: inline-block;
|
59
|
+
vertical-align: top;
|
60
|
+
margin-top: 3px;
|
61
|
+
margin-right: 4px;
|
62
|
+
width: 12px;
|
63
|
+
height: 12px;
|
64
|
+
}
|
65
|
+
|
66
|
+
.storybook-page .tip-wrapper svg path {
|
67
|
+
fill: #1ea7fd;
|
68
|
+
}
|
@@ -0,0 +1,90 @@
|
|
1
|
+
/* RTL utilities for Tailwind CSS */
|
2
|
+
|
3
|
+
/* These custom utilities will complement Tailwind classes */
|
4
|
+
.rtl\:flex-row-reverse {
|
5
|
+
flex-direction: row-reverse;
|
6
|
+
}
|
7
|
+
|
8
|
+
.rtl\:text-right {
|
9
|
+
text-align: right;
|
10
|
+
}
|
11
|
+
|
12
|
+
.rtl\:mr-auto {
|
13
|
+
margin-right: auto;
|
14
|
+
}
|
15
|
+
|
16
|
+
.rtl\:ml-auto {
|
17
|
+
margin-left: auto;
|
18
|
+
}
|
19
|
+
|
20
|
+
/* RTL specific padding and margin classes */
|
21
|
+
.rtl\:pl-0 {
|
22
|
+
padding-left: 0;
|
23
|
+
}
|
24
|
+
|
25
|
+
.rtl\:pr-0 {
|
26
|
+
padding-right: 0;
|
27
|
+
}
|
28
|
+
|
29
|
+
/* RTL transforms for icons */
|
30
|
+
.rtl\:rotate-180 {
|
31
|
+
transform: rotate(180deg);
|
32
|
+
}
|
33
|
+
|
34
|
+
.rtl\:scale-x-n1 {
|
35
|
+
transform: scaleX(-1);
|
36
|
+
}
|
37
|
+
|
38
|
+
/* RTL borders */
|
39
|
+
.rtl\:border-r {
|
40
|
+
border-right-width: 1px;
|
41
|
+
border-right-style: solid;
|
42
|
+
}
|
43
|
+
|
44
|
+
.rtl\:border-l {
|
45
|
+
border-left-width: 1px;
|
46
|
+
border-left-style: solid;
|
47
|
+
}
|
48
|
+
|
49
|
+
.rtl\:border-r-0 {
|
50
|
+
border-right-width: 0;
|
51
|
+
}
|
52
|
+
|
53
|
+
.rtl\:border-l-0 {
|
54
|
+
border-left-width: 0;
|
55
|
+
}
|
56
|
+
|
57
|
+
/* Typography direction */
|
58
|
+
.rtl\:direction-rtl {
|
59
|
+
direction: rtl;
|
60
|
+
}
|
61
|
+
|
62
|
+
.rtl\:direction-ltr {
|
63
|
+
direction: ltr;
|
64
|
+
}
|
65
|
+
|
66
|
+
/* RTL float classes */
|
67
|
+
.rtl\:float-right {
|
68
|
+
float: right;
|
69
|
+
}
|
70
|
+
|
71
|
+
.rtl\:float-left {
|
72
|
+
float: left;
|
73
|
+
}
|
74
|
+
|
75
|
+
/* Variable to manage padding and margin amounts based on size */
|
76
|
+
:root {
|
77
|
+
--padding-amount-1: 0.25rem;
|
78
|
+
--padding-amount-2: 0.5rem;
|
79
|
+
--padding-amount-3: 0.75rem;
|
80
|
+
--padding-amount-4: 1rem;
|
81
|
+
--padding-amount-5: 1.25rem;
|
82
|
+
--padding-amount-6: 1.5rem;
|
83
|
+
|
84
|
+
--margin-amount-1: 0.25rem;
|
85
|
+
--margin-amount-2: 0.5rem;
|
86
|
+
--margin-amount-3: 0.75rem;
|
87
|
+
--margin-amount-4: 1rem;
|
88
|
+
--margin-amount-5: 1.25rem;
|
89
|
+
--margin-amount-6: 1.5rem;
|
90
|
+
}
|
@@ -0,0 +1,105 @@
|
|
1
|
+
/* RTL Specific Styles */
|
2
|
+
|
3
|
+
/* Global RTL adjustments */
|
4
|
+
.rtl {
|
5
|
+
direction: rtl;
|
6
|
+
text-align: right;
|
7
|
+
}
|
8
|
+
|
9
|
+
/* Flip padding and margins for RTL */
|
10
|
+
.rtl .language-switcher {
|
11
|
+
margin-left: 0;
|
12
|
+
margin-right: auto;
|
13
|
+
}
|
14
|
+
|
15
|
+
/* Flip button icons */
|
16
|
+
.rtl button svg:not(.no-flip) {
|
17
|
+
transform: scaleX(-1);
|
18
|
+
}
|
19
|
+
|
20
|
+
/* Adjust flexbox direction */
|
21
|
+
.rtl .flex-row {
|
22
|
+
flex-direction: row-reverse;
|
23
|
+
}
|
24
|
+
|
25
|
+
/* Adjust text alignment in inputs and forms */
|
26
|
+
.rtl input,
|
27
|
+
.rtl textarea {
|
28
|
+
text-align: right;
|
29
|
+
}
|
30
|
+
|
31
|
+
/* Adjust dropdown menus */
|
32
|
+
.rtl .dropdown-menu-content {
|
33
|
+
transform-origin: top right;
|
34
|
+
}
|
35
|
+
|
36
|
+
/* Adjust borders */
|
37
|
+
.rtl .border-l {
|
38
|
+
border-left: none;
|
39
|
+
border-right: 1px solid;
|
40
|
+
}
|
41
|
+
|
42
|
+
.rtl .border-r {
|
43
|
+
border-right: none;
|
44
|
+
border-left: 1px solid;
|
45
|
+
}
|
46
|
+
|
47
|
+
/* Adjust any left/right padding or margins in common components */
|
48
|
+
.rtl .pl-1, .rtl .pl-2, .rtl .pl-3, .rtl .pl-4, .rtl .pl-5, .rtl .pl-6 {
|
49
|
+
padding-left: 0;
|
50
|
+
padding-right: var(--padding-amount);
|
51
|
+
}
|
52
|
+
|
53
|
+
.rtl .pr-1, .rtl .pr-2, .rtl .pr-3, .rtl .pr-4, .rtl .pr-5, .rtl .pr-6 {
|
54
|
+
padding-right: 0;
|
55
|
+
padding-left: var(--padding-amount);
|
56
|
+
}
|
57
|
+
|
58
|
+
.rtl .ml-1, .rtl .ml-2, .rtl .ml-3, .rtl .ml-4, .rtl .ml-5, .rtl .ml-6 {
|
59
|
+
margin-left: 0;
|
60
|
+
margin-right: var(--margin-amount);
|
61
|
+
}
|
62
|
+
|
63
|
+
.rtl .mr-1, .rtl .mr-2, .rtl .mr-3, .rtl .mr-4, .rtl .mr-5, .rtl .mr-6 {
|
64
|
+
margin-right: 0;
|
65
|
+
margin-left: var(--margin-amount);
|
66
|
+
}
|
67
|
+
|
68
|
+
/* Adjust input groups */
|
69
|
+
.rtl .input-group-prepend {
|
70
|
+
border-radius: 0 0.25rem 0.25rem 0;
|
71
|
+
}
|
72
|
+
|
73
|
+
.rtl .input-group-append {
|
74
|
+
border-radius: 0.25rem 0 0 0.25rem;
|
75
|
+
}
|
76
|
+
|
77
|
+
/* If using tailwind, we need to adjust text alignment for RTL */
|
78
|
+
.rtl .text-left {
|
79
|
+
text-align: right;
|
80
|
+
}
|
81
|
+
|
82
|
+
.rtl .text-right {
|
83
|
+
text-align: left;
|
84
|
+
}
|
85
|
+
|
86
|
+
/* Reset direction for elements that should not be flipped */
|
87
|
+
.rtl .no-rtl {
|
88
|
+
direction: ltr;
|
89
|
+
text-align: left;
|
90
|
+
}
|
91
|
+
|
92
|
+
/* Stepper specific RTL adjustments */
|
93
|
+
.rtl .rtl-stepper {
|
94
|
+
/* Ensure connectors align correctly in RTL */
|
95
|
+
direction: rtl;
|
96
|
+
}
|
97
|
+
|
98
|
+
.rtl .rtl-stepper .step-content {
|
99
|
+
text-align: right;
|
100
|
+
}
|
101
|
+
|
102
|
+
/* Fix for step icons in RTL mode */
|
103
|
+
.rtl .rtl-stepper svg:not(.no-flip) {
|
104
|
+
transform: scaleX(-1);
|
105
|
+
}
|
@@ -0,0 +1,26 @@
|
|
1
|
+
import { ErrorResponse } from '@/services/api/auth.service';
|
2
|
+
|
3
|
+
export class ApiError extends Error {
|
4
|
+
code: string;
|
5
|
+
txnid: string;
|
6
|
+
timestamp: string;
|
7
|
+
|
8
|
+
constructor(error: ErrorResponse) {
|
9
|
+
super(error.errorMsg || error.errorCode);
|
10
|
+
this.name = 'ApiError';
|
11
|
+
this.code = error.errorCode;
|
12
|
+
this.txnid = error.txnid;
|
13
|
+
this.timestamp = error.timestamp;
|
14
|
+
}
|
15
|
+
}
|
16
|
+
|
17
|
+
export const getErrorMessage = (errorCode: string): string => {
|
18
|
+
const errorMessages: Record<string, string> = {
|
19
|
+
'Invalid Otp': 'The OTP you entered is invalid. Please try again.',
|
20
|
+
'Token Expired': 'Your session has expired. Please log in again.',
|
21
|
+
'Invalid Token': 'Authentication failed. Please log in again.',
|
22
|
+
'User Not Found': 'User not found. Please check your credentials.'
|
23
|
+
};
|
24
|
+
|
25
|
+
return errorMessages[errorCode] || 'An unexpected error occurred. Please try again.';
|
26
|
+
};
|
package/src/utils/cn.ts
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
import { clsx, type ClassValue } from 'clsx';
|
2
|
+
import { twMerge } from 'tailwind-merge';
|
3
|
+
|
4
|
+
/**
|
5
|
+
* A utility function that merges multiple class names together
|
6
|
+
* It combines clsx for conditional classes with tailwind-merge to handle Tailwind CSS class conflicts
|
7
|
+
*/
|
8
|
+
export function cn(...inputs: ClassValue[]) {
|
9
|
+
return twMerge(clsx(inputs));
|
10
|
+
}
|
@@ -0,0 +1,116 @@
|
|
1
|
+
interface ErrorCallbackData {
|
2
|
+
type: 'error';
|
3
|
+
status: 'error';
|
4
|
+
flowCompleted: boolean;
|
5
|
+
errorCode?: string;
|
6
|
+
errorMessage: string;
|
7
|
+
errorType?: 'api' | 'auth' | 'network' | 'validation' | 'unknown';
|
8
|
+
statusCode?: number;
|
9
|
+
timestamp: string;
|
10
|
+
userAgent?: string;
|
11
|
+
url?: string;
|
12
|
+
stack?: string;
|
13
|
+
consentHandle?: string;
|
14
|
+
redirectUrl?: string;
|
15
|
+
}
|
16
|
+
|
17
|
+
/**
|
18
|
+
* Send error callback to parent window
|
19
|
+
*/
|
20
|
+
export const sendErrorCallback = (
|
21
|
+
errorMessage: string,
|
22
|
+
options: {
|
23
|
+
errorCode?: string;
|
24
|
+
errorType?: 'api' | 'auth' | 'network' | 'validation' | 'unknown';
|
25
|
+
statusCode?: number;
|
26
|
+
stack?: string;
|
27
|
+
consentHandle?: string;
|
28
|
+
redirectUrl?: string;
|
29
|
+
flowCompleted?: boolean;
|
30
|
+
} = {}
|
31
|
+
) => {
|
32
|
+
const errorData: ErrorCallbackData = {
|
33
|
+
type: 'error',
|
34
|
+
status: 'error',
|
35
|
+
flowCompleted: options.flowCompleted ?? false,
|
36
|
+
errorCode: options.errorCode,
|
37
|
+
errorMessage,
|
38
|
+
errorType: options.errorType || 'unknown',
|
39
|
+
statusCode: options.statusCode,
|
40
|
+
timestamp: new Date().toISOString(),
|
41
|
+
userAgent: navigator.userAgent,
|
42
|
+
url: window.location.href,
|
43
|
+
stack: options.stack,
|
44
|
+
consentHandle: options.consentHandle,
|
45
|
+
redirectUrl: options.redirectUrl
|
46
|
+
};
|
47
|
+
|
48
|
+
console.log('Sending error message to parent:', errorData);
|
49
|
+
|
50
|
+
try {
|
51
|
+
window.parent.postMessage(errorData, '*');
|
52
|
+
} catch (err) {
|
53
|
+
console.error('Failed to send error callback to parent:', err);
|
54
|
+
}
|
55
|
+
};
|
56
|
+
|
57
|
+
/**
|
58
|
+
* Handle API errors and send callback
|
59
|
+
*/
|
60
|
+
export const handleApiErrorWithCallback = (
|
61
|
+
error: unknown,
|
62
|
+
customMessage?: string,
|
63
|
+
consentHandle?: string,
|
64
|
+
redirectUrl?: string
|
65
|
+
) => {
|
66
|
+
let errorMessage = customMessage || 'An unexpected error occurred';
|
67
|
+
let errorCode: string | undefined;
|
68
|
+
let statusCode: number | undefined;
|
69
|
+
let errorType: 'api' | 'auth' | 'network' | 'validation' | 'unknown' = 'unknown';
|
70
|
+
|
71
|
+
// Handle Axios errors
|
72
|
+
if (error && typeof error === 'object' && 'response' in error) {
|
73
|
+
const errorResponse = error?.response as any;
|
74
|
+
statusCode = errorResponse?.status;
|
75
|
+
errorCode = errorResponse?.data?.errorCode;
|
76
|
+
errorType = 'api';
|
77
|
+
|
78
|
+
// Get specific error message from response
|
79
|
+
if (errorResponse?.data?.errorCode) {
|
80
|
+
errorMessage = errorResponse.data.errorCode;
|
81
|
+
} else if (errorResponse?.data?.errorMsg) {
|
82
|
+
errorMessage = errorResponse.data.errorMsg;
|
83
|
+
} else if (statusCode === 401) {
|
84
|
+
errorMessage = 'Authentication failed. Please log in again.';
|
85
|
+
errorType = 'auth';
|
86
|
+
} else if (statusCode === 403) {
|
87
|
+
errorMessage = "You don't have permission to perform this action.";
|
88
|
+
errorType = 'auth';
|
89
|
+
} else if (statusCode === 404) {
|
90
|
+
errorMessage = 'Resource not found.';
|
91
|
+
} else if (statusCode && statusCode >= 500) {
|
92
|
+
errorMessage = 'Server error. Please try again later.';
|
93
|
+
}
|
94
|
+
}
|
95
|
+
// Handle network errors
|
96
|
+
else if (error && typeof error === 'object' && 'code' in error && (error as any).code === 'NETWORK_ERROR') {
|
97
|
+
errorMessage = 'Network error. Please check your connection.';
|
98
|
+
errorType = 'network';
|
99
|
+
}
|
100
|
+
// Handle standard errors
|
101
|
+
else if (error && typeof error === 'object' && 'message' in error) {
|
102
|
+
errorMessage = (error as Error).message;
|
103
|
+
errorType = error.name === 'ValidationError' ? 'validation' : 'unknown';
|
104
|
+
}
|
105
|
+
|
106
|
+
// Send error callback
|
107
|
+
sendErrorCallback(errorMessage, {
|
108
|
+
errorCode,
|
109
|
+
errorType,
|
110
|
+
statusCode,
|
111
|
+
stack: error instanceof Error ? error.stack : undefined,
|
112
|
+
consentHandle,
|
113
|
+
redirectUrl,
|
114
|
+
flowCompleted: false
|
115
|
+
});
|
116
|
+
};
|
@@ -0,0 +1,90 @@
|
|
1
|
+
interface Identifier {
|
2
|
+
type: 'PAN' | 'AADHAAR' | 'MOBILE';
|
3
|
+
value?: string;
|
4
|
+
}
|
5
|
+
|
6
|
+
interface Fip {
|
7
|
+
id: string;
|
8
|
+
Identifiers?: Identifier[];
|
9
|
+
}
|
10
|
+
|
11
|
+
interface DecodedInfo {
|
12
|
+
pan?: string;
|
13
|
+
aadhaar?: string;
|
14
|
+
}
|
15
|
+
|
16
|
+
interface SelectedFips {
|
17
|
+
[key: string]: string[];
|
18
|
+
}
|
19
|
+
|
20
|
+
interface NavigateState {
|
21
|
+
category: string;
|
22
|
+
selectedFips: string[];
|
23
|
+
}
|
24
|
+
|
25
|
+
interface NavigateOptions {
|
26
|
+
state?: NavigateState;
|
27
|
+
}
|
28
|
+
|
29
|
+
const handleIdentifiers = ({
|
30
|
+
selectedFips,
|
31
|
+
activeCategory,
|
32
|
+
decodedInfo,
|
33
|
+
selectedMobileNumber,
|
34
|
+
setIdentifiers,
|
35
|
+
fips,
|
36
|
+
navigate
|
37
|
+
}: {
|
38
|
+
selectedFips: SelectedFips;
|
39
|
+
activeCategory: string;
|
40
|
+
decodedInfo: DecodedInfo;
|
41
|
+
selectedMobileNumber: string;
|
42
|
+
setIdentifiers: (identifiers: Identifier[]) => void;
|
43
|
+
fips: Fip[];
|
44
|
+
navigate: (path: string, options?: NavigateOptions) => void;
|
45
|
+
}) => {
|
46
|
+
let redirect = false;
|
47
|
+
const identifiersList: Identifier[] = [];
|
48
|
+
|
49
|
+
fips
|
50
|
+
.filter(fip =>
|
51
|
+
selectedFips[activeCategory]?.includes(fip.id)
|
52
|
+
)
|
53
|
+
.forEach(fip => {
|
54
|
+
fip.Identifiers?.forEach(identifier => {
|
55
|
+
if (!identifiersList.find(i => i.type === identifier.type)) {
|
56
|
+
const value =
|
57
|
+
identifier.type === 'PAN'
|
58
|
+
? decodedInfo?.pan
|
59
|
+
: identifier.type === 'AADHAAR'
|
60
|
+
? decodedInfo?.aadhaar
|
61
|
+
: identifier.type === 'MOBILE'
|
62
|
+
? selectedMobileNumber
|
63
|
+
: undefined;
|
64
|
+
identifiersList.push({ ...identifier, value });
|
65
|
+
}
|
66
|
+
});
|
67
|
+
});
|
68
|
+
|
69
|
+
setIdentifiers(identifiersList);
|
70
|
+
if (identifiersList?.length > 0 && Boolean(identifiersList.find(val => !val.value)?.type)) {
|
71
|
+
if (identifiersList.find(i => i.type === 'PAN')) {
|
72
|
+
redirect = true;
|
73
|
+
}
|
74
|
+
if (identifiersList.find(i => i.type === 'AADHAAR')) {
|
75
|
+
redirect = true;
|
76
|
+
}
|
77
|
+
}
|
78
|
+
|
79
|
+
if (redirect) {
|
80
|
+
navigate(`/link-accounts/discover-account`, {
|
81
|
+
state: {
|
82
|
+
category: activeCategory,
|
83
|
+
selectedFips: selectedFips[activeCategory]
|
84
|
+
}
|
85
|
+
});
|
86
|
+
return null;
|
87
|
+
}
|
88
|
+
};
|
89
|
+
|
90
|
+
export default handleIdentifiers;
|
@@ -0,0 +1,67 @@
|
|
1
|
+
import posthog from 'posthog-js';
|
2
|
+
import { EXTERNAL_URLS } from '@/config/urls';
|
3
|
+
import { useRedirectStore } from '@/store/redirect.store';
|
4
|
+
|
5
|
+
export const trackEvent = (eventName: string, properties?: Record<string, unknown>) => {
|
6
|
+
if (import.meta.env.VITE_MODE.toLowerCase() !== 'production') {
|
7
|
+
return;
|
8
|
+
}
|
9
|
+
|
10
|
+
// Get decoded info from the redirect store
|
11
|
+
const { decodedInfo } = useRedirectStore.getState();
|
12
|
+
|
13
|
+
// Prepare default properties from redirect store
|
14
|
+
const defaultProperties: Record<string, unknown> = {};
|
15
|
+
|
16
|
+
if (decodedInfo) {
|
17
|
+
defaultProperties.fiuId = decodedInfo.fiuId;
|
18
|
+
defaultProperties.fiuName = decodedInfo.fiuName;
|
19
|
+
defaultProperties.fipId = decodedInfo.fipId;
|
20
|
+
defaultProperties.platform = decodedInfo.platform;
|
21
|
+
defaultProperties.isNewUser = !decodedInfo.isUserPresent;
|
22
|
+
}
|
23
|
+
|
24
|
+
// Merge default properties with provided properties
|
25
|
+
const combinedProperties = { ...defaultProperties, ...properties };
|
26
|
+
|
27
|
+
const prefixedEventName = `AA_${eventName}`;
|
28
|
+
posthog.capture(prefixedEventName, combinedProperties);
|
29
|
+
};
|
30
|
+
|
31
|
+
// Event names as constants for type safety and reusability
|
32
|
+
export const EVENTS = {
|
33
|
+
INIT_OTP: 'INIT_OTP',
|
34
|
+
RESEND_OTP: 'RESEND_OTP',
|
35
|
+
SUBMIT_OTP: 'SUBMIT_OTP',
|
36
|
+
ADD_NEW_MOBILE: 'ADD_NEW_MOBILE',
|
37
|
+
VERIFY_NEW_MOBILE: 'VERIFY_NEW_MOBILE',
|
38
|
+
DISCOVER_ACCOUNT: 'DISCOVER_ACCOUNT',
|
39
|
+
DISCOVER_MORE: 'DISCOVER_MORE',
|
40
|
+
CHANGE_LANGUAGE: 'CHANGE_LANGUAGE',
|
41
|
+
USER_EXIT: 'USER_EXIT',
|
42
|
+
VIEW_TERMS: 'VIEW_TERMS',
|
43
|
+
SELECT_ALL_ACCOUNTS: 'SELECT_ALL_ACCOUNTS',
|
44
|
+
SKIP_LINKING: 'SKIP_LINKING',
|
45
|
+
LINK_ACCOUNT: 'LINK_ACCOUNT',
|
46
|
+
RETRY_FAILED_ACCOUNTS: 'RETRY_FAILED_ACCOUNTS',
|
47
|
+
EDIT_ACCOUNT: 'EDIT_ACCOUNT',
|
48
|
+
ADD_ACCOUNT: 'ADD_ACCOUNT',
|
49
|
+
APPROVE_CONSENT: 'APPROVE_CONSENT',
|
50
|
+
REJECT_CONSENT: 'REJECT_CONSENT',
|
51
|
+
VIEW_MORE_CONSENT: 'VIEW_MORE_CONSENT',
|
52
|
+
SUBMIT_RATING: 'SUBMIT_RATING',
|
53
|
+
SUBMIT_FEEDBACK: 'SUBMIT_FEEDBACK',
|
54
|
+
NOTIFY_UPDATES: 'NOTIFY_UPDATES',
|
55
|
+
SEARCH_BANKS: 'SEARCH_BANKS',
|
56
|
+
} as const;
|
57
|
+
|
58
|
+
// Initialize PostHog with configuration from environment
|
59
|
+
export const initPostHog = () => {
|
60
|
+
if (EXTERNAL_URLS.POSTHOG_KEY) {
|
61
|
+
posthog.init(EXTERNAL_URLS.POSTHOG_KEY, {
|
62
|
+
api_host: EXTERNAL_URLS.POSTHOG_HOST || 'https://app.posthog.com',
|
63
|
+
disable_session_recording: true,
|
64
|
+
capture_pageview: true,
|
65
|
+
});
|
66
|
+
}
|
67
|
+
};
|
@@ -0,0 +1,61 @@
|
|
1
|
+
import { toast } from 'sonner'
|
2
|
+
|
3
|
+
export const handleApiError = (
|
4
|
+
error: unknown,
|
5
|
+
customMessage: string = 'An error occurred'
|
6
|
+
) => {
|
7
|
+
// Handle Axios errors
|
8
|
+
if (error && typeof error === 'object' && 'response' in error) {
|
9
|
+
const errorResponse = error?.response as any
|
10
|
+
|
11
|
+
// Display server error message if available
|
12
|
+
if (errorResponse?.data?.errorCode) {
|
13
|
+
toast.error('Error', {
|
14
|
+
description: errorResponse.data.errorCode
|
15
|
+
})
|
16
|
+
return
|
17
|
+
}
|
18
|
+
|
19
|
+
// Handle different status codes
|
20
|
+
if (errorResponse?.status === 401) {
|
21
|
+
toast.error('Unauthorized. Please log in again.')
|
22
|
+
return
|
23
|
+
}
|
24
|
+
|
25
|
+
if (errorResponse?.status === 403) {
|
26
|
+
toast.error("You don't have permission to perform this action.")
|
27
|
+
return
|
28
|
+
}
|
29
|
+
|
30
|
+
if (errorResponse?.status === 404) {
|
31
|
+
toast.error('Resource not found.')
|
32
|
+
return
|
33
|
+
}
|
34
|
+
|
35
|
+
if (errorResponse?.status >= 500) {
|
36
|
+
toast.error('Server error. Please try again later.!!!')
|
37
|
+
return
|
38
|
+
}
|
39
|
+
}
|
40
|
+
|
41
|
+
// For standard errors with message property
|
42
|
+
if (error && typeof error === 'object' && 'message' in error) {
|
43
|
+
toast.error(error.message as string)
|
44
|
+
return
|
45
|
+
}
|
46
|
+
|
47
|
+
// Default fallback
|
48
|
+
toast.error(customMessage)
|
49
|
+
}
|
50
|
+
|
51
|
+
export const showSuccessToast = (message: string) => {
|
52
|
+
toast.success(message)
|
53
|
+
}
|
54
|
+
|
55
|
+
export const showInfoToast = (message: string) => {
|
56
|
+
toast.info(message)
|
57
|
+
}
|
58
|
+
|
59
|
+
export const showWarningToast = (message: string) => {
|
60
|
+
toast.warning(message)
|
61
|
+
}
|
@@ -0,0 +1 @@
|
|
1
|
+
/// <reference types="vite/client" />
|
Binary file
|