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,333 @@
1
+ "use client";
2
+
3
+ import React, { useEffect, useState } from "react";
4
+ import { FrostedPanel } from "@/components/ui/frosted-panel";
5
+ import { Step, StepGroup, StepConnector } from "@/components/ui/step";
6
+ import { Link, FileText, Shield, Building2, Receipt, ShieldCheck, Info } from "lucide-react";
7
+ import { useLocation } from "react-router-dom";
8
+ import { motion, AnimatePresence } from "framer-motion";
9
+ import AppBar from "../title/AppBar";
10
+ import { useIsMobile } from "@/hooks/use-mobile";
11
+ import { MobileLayout } from "./MobileLayout";
12
+ import { useFipStore } from "@/store/fip.store";
13
+ import { useTranslation } from "react-i18next";
14
+ import { useStepStore } from "@/store/step.store";
15
+ import { useRTL } from "@/contexts/RTLContext";
16
+ import { useRedirectStore } from "@/store/redirect.store";
17
+ import { Tooltip, TooltipContent, TooltipTrigger } from "../ui/tooltip";
18
+ import { VersionDisplay } from "../ui/version-display";
19
+ // Define step interfaces
20
+ interface BaseStep {
21
+ step: number;
22
+ title: string;
23
+ description: string;
24
+ icon: React.ReactNode;
25
+ path: string;
26
+ parentStep?: number;
27
+ }
28
+
29
+ // Base steps without dynamic child steps
30
+ const baseSteps: BaseStep[] = [
31
+ {
32
+ step: 1,
33
+ title: "Login/Signup",
34
+ description: "Enter the OTP sent to your mobile",
35
+ icon: <Shield className="w-4 h-4" />,
36
+ path: "/login",
37
+ },
38
+ {
39
+ step: 2,
40
+ title: "Link Accounts",
41
+ description: "Select & Link the accounts you'd like to share",
42
+ icon: <Link className="w-4 h-4" />,
43
+ path: "/link-accounts/discover",
44
+ },
45
+ {
46
+ step: 3,
47
+ title: "Review Consent",
48
+ description: "Approve/Reject the consent after reviewing the details",
49
+ icon: <FileText className="w-4 h-4" />,
50
+ path: "/review",
51
+ },
52
+ ];
53
+
54
+ // Map of category icons
55
+ const categoryIcons = {
56
+ "BANK": <Building2 className="w-4 h-4" />,
57
+ "GST": <Receipt className="w-4 h-4" />,
58
+ "INSURANCE": <ShieldCheck className="w-4 h-4" />,
59
+ "INVESTMENTS": <ShieldCheck className="w-4 h-4" />
60
+ };
61
+
62
+ interface FrostedLayoutProps {
63
+ children: React.ReactNode;
64
+ footer?: React.ReactNode;
65
+ title?: string;
66
+ notAuthenticated?: boolean;
67
+ }
68
+
69
+ export function FrostedLayout({ footer, children, title, notAuthenticated }: FrostedLayoutProps) {
70
+ const location = useLocation();
71
+ const isMobile = useIsMobile();
72
+ const currentPath = location.pathname;
73
+ const [steps, setSteps] = useState(baseSteps);
74
+ const { t } = useTranslation();
75
+ const { decodedInfo } = useRedirectStore()
76
+ const { categories, activeCategory, currentChildStep } = useFipStore();
77
+ const { activeStep, completedSteps, setActiveStep, setCompletedSteps, determineActiveStep } = useStepStore();
78
+ const [expandedParents, setExpandedParents] = useState<number[]>([]);
79
+ const { isRTL } = useRTL();
80
+
81
+ // Dynamically create steps whenever categories change
82
+ useEffect(() => {
83
+ if (categories && categories.length > 0) {
84
+ // Create child steps for Link Accounts
85
+ const childSteps = categories.map((category, index) => ({
86
+ step: 3 + index, // Start numbering after Link Accounts
87
+ title: t(`categories.${category.toLowerCase()}`),
88
+ description: t(`categories.${category.toLowerCase()}Description`),
89
+ icon: categoryIcons[category as keyof typeof categoryIcons] || <Link className="w-4 h-4" />,
90
+ path: `/link-accounts/${category.toLowerCase()}`,
91
+ parentStep: 2, // Link Accounts is step 2,
92
+ isActive: category === activeCategory
93
+ }));
94
+
95
+ // Combine base steps with child steps
96
+ const newSteps = [
97
+ ...baseSteps.slice(0, 2), // Login and Link Accounts
98
+ ...childSteps,
99
+ baseSteps[2], // Review Consent, update the step number
100
+ ];
101
+
102
+ // Update Review Consent step number
103
+ newSteps[newSteps.length - 1] = {
104
+ ...newSteps[newSteps.length - 1],
105
+ step: 3 + childSteps.length
106
+ };
107
+
108
+ setSteps(newSteps);
109
+
110
+ // Update totalSteps in the store
111
+ useStepStore.setState({ totalSteps: newSteps.length });
112
+ } else {
113
+ setSteps(baseSteps);
114
+
115
+ // Reset to base steps count
116
+ useStepStore.setState({ totalSteps: baseSteps.length });
117
+ }
118
+ }, [categories, activeCategory]);
119
+
120
+ // Find the app title from the current step
121
+ const currentStepData = steps.find(step => step.path === currentPath);
122
+ const appTitle = title || t("keywords.select") + " " + `${currentStepData?.title || t("categories.bank")}` + " & " + t("keywords.discover") + " " + t("keywords.your") + " " + t("keywords.accounts");
123
+
124
+
125
+ // Determine the current active step using the store's determineActiveStep function
126
+ const currentStep = determineActiveStep(currentPath, steps);
127
+ const [hoverIButton, setHoverIButton] = useState()
128
+ // Update the store's active step whenever it changes
129
+ useEffect(() => {
130
+ setActiveStep(currentStep);
131
+
132
+ // Mark previous steps as completed
133
+ if (currentStep > 1) {
134
+ const newCompletedSteps = new Set(completedSteps);
135
+
136
+ // Add all steps from 1 to current-1 as completed
137
+ for (let i = 1; i < currentStep; i++) {
138
+ newCompletedSteps.add(i);
139
+ }
140
+
141
+ // For parent steps, check if all their children are completed
142
+ steps.forEach(step => {
143
+ if (step.parentStep) {
144
+ const childSteps = steps.filter(s => s.parentStep === step.parentStep);
145
+ const allChildrenCompleted = childSteps.every(s => newCompletedSteps.has(s.step));
146
+ if (allChildrenCompleted) {
147
+ newCompletedSteps.add(step.parentStep);
148
+ }
149
+ }
150
+ });
151
+
152
+ setCompletedSteps(Array.from(newCompletedSteps));
153
+ }
154
+ }, [currentStep, setActiveStep, setCompletedSteps, steps]);
155
+
156
+ // Check if all child steps of a parent are completed
157
+ const areAllChildStepsCompleted = (parentStep: number) => {
158
+ const childSteps = steps.filter(step => step.parentStep === parentStep);
159
+ return childSteps.length > 0 && childSteps.every(step => completedSteps.includes(step.step));
160
+ };
161
+
162
+ // Toggle expansion of a parent step
163
+ const toggleParentExpansion = (parentStep: number) => {
164
+ setExpandedParents(prev =>
165
+ prev.includes(parentStep)
166
+ ? prev.filter(p => p !== parentStep)
167
+ : [...prev, parentStep]
168
+ );
169
+ };
170
+
171
+ // On completion of all child steps, automatically fold them
172
+ useEffect(() => {
173
+ // Get all parent steps that have children
174
+ const parentSteps = [...new Set(steps.filter(step => step.parentStep).map(step => step.parentStep))];
175
+
176
+ // Initial setup - expand the parent of the active step if it exists
177
+ const activeStepParent = steps.find(s => s.step === activeStep)?.parentStep;
178
+
179
+ // Check each parent step
180
+ parentSteps.forEach(parentStep => {
181
+ if (parentStep) {
182
+ if (areAllChildStepsCompleted(parentStep)) {
183
+ // If all children completed and parent is expanded and not the active parent, collapse it
184
+ if (expandedParents.includes(parentStep) && parentStep !== activeStepParent) {
185
+ setExpandedParents(prev => prev.filter(p => p !== parentStep));
186
+ }
187
+ } else {
188
+ // If not all completed, ensure it's expanded
189
+ if (!expandedParents.includes(parentStep)) {
190
+ setExpandedParents(prev => [...prev, parentStep]);
191
+ }
192
+ }
193
+
194
+ // Always expand the active step's parent
195
+ if (activeStepParent && !expandedParents.includes(activeStepParent)) {
196
+ setExpandedParents(prev => [...prev, activeStepParent]);
197
+ }
198
+ }
199
+ });
200
+ }, [completedSteps, steps, activeStep]);
201
+
202
+ // Use mobile layout for mobile devices
203
+ if (isMobile) {
204
+ return <MobileLayout title={appTitle}>{children}</MobileLayout>;
205
+ }
206
+
207
+ // Tablet and desktop layout
208
+ return (
209
+ <FrostedPanel
210
+ blobConfig={{
211
+ speed: 0.9,
212
+ count: 4,
213
+ color: "rgba(255, 255, 255, 0.4)",
214
+ minSize: 100,
215
+ maxSize: 250,
216
+ }}
217
+ gradientColors={{
218
+ top: "#004d4d",
219
+ bottom: "#00b2c1",
220
+ }}
221
+ >
222
+ <FrostedPanel.Aside className="px-4 py-6">
223
+ <div className="flex justify-between items-center cursor-default">
224
+ <h1 className="text-2xl font-semibold text-white">
225
+ {t('layout.title')}
226
+ </h1>
227
+ </div>
228
+
229
+ <StepGroup
230
+ activeStep={activeStep}
231
+ completedSteps={completedSteps}
232
+ baseColor="#FFF"
233
+ className="mt-20"
234
+ spacing={32}
235
+ >
236
+ <AnimatePresence mode="wait">
237
+ {steps.map(({ step, title, icon, description, parentStep }, index) => {
238
+
239
+ // Skip child steps of completed parents that aren't expanded
240
+
241
+ if (parentStep &&
242
+ areAllChildStepsCompleted(parentStep) &&
243
+ !expandedParents.includes(parentStep) &&
244
+ activeStep !== step) {
245
+
246
+ return null;
247
+ }
248
+
249
+ // For parent steps that have children
250
+ const hasChildren = steps.some(s => s.parentStep === step);
251
+
252
+ return (
253
+ <motion.div
254
+ key={`step-${step}-${title}`}
255
+ className="relative group" // group for hover
256
+ initial={{ opacity: 0, x: -10 }}
257
+ animate={{ opacity: 1, x: 0 }}
258
+ exit={{ opacity: 0, x: 10 }}
259
+ transition={{
260
+ duration: 0.3,
261
+ delay: parentStep ? 0.1 * (index % categories.length) : 0
262
+ }}
263
+ >
264
+ <div className="relative flex items-center">
265
+ <Step
266
+ step={step}
267
+ title={parentStep ? title : t(`stepper.${title.toLowerCase().replace('/', '')}`)}
268
+ icon={icon}
269
+ isActive={parentStep ? activeCategory == title?.toUpperCase() : activeStep == step}
270
+ isCompleted={!parentStep && steps[step]?.parentStep ?
271
+ steps.filter(s => s.parentStep === step).every(s => completedSteps.includes(s.step)) :
272
+ completedSteps.includes(step)
273
+ }
274
+ isParentPending={Boolean(!parentStep && steps[step]?.parentStep &&
275
+ !steps.filter(s => s.parentStep === step).every(s => completedSteps.includes(s.step)))
276
+ }
277
+ isLast={index === steps.length - 1}
278
+ height={parentStep ? 90 : 80}
279
+ isChildStep={Boolean(parentStep)}
280
+ onStepClick={hasChildren ? () => toggleParentExpansion(step) : undefined}
281
+ notAuthenticated={notAuthenticated}
282
+ isRTL={isRTL}
283
+ />
284
+
285
+ {index < steps.length - 1 && (
286
+ <StepConnector
287
+ isActive={true}
288
+ isCompleted={completedSteps.includes(step)}
289
+ />
290
+ )}
291
+
292
+ {index == 1 && (
293
+ <Tooltip>
294
+ <TooltipTrigger asChild>
295
+ <Info className={`${'w-3 h-3 mb-13 ml-2'} text-muted cursor-pointer ml-1`} />
296
+ </TooltipTrigger>
297
+ <TooltipContent side="right" align="center" className="max-w-[280px] whitespace-normal text-sm bg-gray-700" >
298
+ {t("stepper.linkAccountsDescription")}
299
+ </TooltipContent>
300
+ </Tooltip>
301
+ )}
302
+ </div>
303
+ </motion.div>
304
+ )
305
+ })}
306
+ </AnimatePresence>
307
+ </StepGroup>
308
+ </FrostedPanel.Aside>
309
+
310
+ <FrostedPanel.Main className="flex flex-col justify-between">
311
+ <div className="px-14 sticky top-0 z-10">
312
+
313
+ <AppBar title={appTitle} className="mt-6" />
314
+ </div>
315
+ <div className="overflow-y-auto h-full my-1">
316
+ <AnimatePresence mode="wait">
317
+ <motion.div
318
+ key={location.pathname}
319
+ initial={{ opacity: 0, y: 20 }}
320
+ animate={{ opacity: 1, y: 0 }}
321
+ exit={{ opacity: 0, y: -20 }}
322
+ transition={{ duration: 0.3 }}
323
+ className="flex h-full w-full flex-col"
324
+ >
325
+ {children}
326
+ </motion.div>
327
+ </AnimatePresence>
328
+ </div>
329
+ {footer && <div className="w-full px-14 py-4">{footer}</div>}
330
+ </FrostedPanel.Main>
331
+ </FrostedPanel>
332
+ );
333
+ }