@wf-financing/ui 3.10.0 → 3.12.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 (43) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/dist/index.es.js +21897 -12225
  3. package/global.d.ts +1 -1
  4. package/index.ts +2 -2
  5. package/package.json +5 -2
  6. package/src/App.tsx +5 -2
  7. package/src/CtaWidget.tsx +31 -9
  8. package/src/api/ctaBanner.ts +1 -2
  9. package/src/api/getHeadlessSdkInstance.ts +4 -2
  10. package/src/components/banner/BannerActions.tsx +26 -0
  11. package/src/components/banner/BulletList.tsx +34 -21
  12. package/src/components/banner/CloseButton.tsx +22 -2
  13. package/src/components/banner/CtaBanner.snapshot.stories.tsx +11 -1
  14. package/src/components/banner/CtaBanner.tsx +23 -8
  15. package/src/components/banner/CtaMainText.tsx +23 -0
  16. package/src/components/modal/ConsentModal.snapshot.stories.tsx +28 -25
  17. package/src/components/modal/ConsentModal.tsx +18 -30
  18. package/src/components/modal/ConsentModalContent.tsx +63 -0
  19. package/src/components/modal/FundingSteps.tsx +16 -8
  20. package/src/components/modal/ModalFooter.tsx +15 -17
  21. package/src/components/modal/TemplateWithUrl.tsx +30 -0
  22. package/src/config/applicationVersion.ts +1 -0
  23. package/src/config/index.ts +1 -0
  24. package/src/hooks/index.ts +1 -0
  25. package/src/hooks/useCopy.ts +30 -0
  26. package/src/main.tsx +8 -1
  27. package/src/utils/buildBannerConfig.ts +26 -0
  28. package/src/utils/getBannerConfig.ts +44 -0
  29. package/src/utils/getModalItems.ts +19 -0
  30. package/src/utils/index.ts +5 -0
  31. package/src/utils/injectUrlInTemplate.ts +6 -0
  32. package/src/utils/parseJwt.ts +4 -2
  33. package/src/utils/replacePlaceholdersForMainText.ts +29 -0
  34. package/tsconfig.json +2 -1
  35. package/vite-env.d.ts +1 -0
  36. package/vite.config.mts +3 -0
  37. package/src/components/banner/BannerActionsDesktop.tsx +0 -13
  38. package/src/components/banner/CtaBannerContent.tsx +0 -37
  39. package/src/components/banner/FooterActions.tsx +0 -8
  40. package/src/components/banner/HeaderActions.tsx +0 -21
  41. package/src/components/banner/ProceedFundingButton.tsx +0 -61
  42. package/src/constants/index.ts +0 -1
  43. package/src/constants/modalItems.ts +0 -26
@@ -1,23 +1,31 @@
1
1
  import { Flex, Text } from '@wayflyer/flyui';
2
- import { useIntl } from 'react-intl';
3
2
 
4
3
  import { useDetectSmallScreen } from '../../hooks';
5
- import { MODAL_ITEMS } from '../../constants';
4
+ import { getModalItems } from '../../utils';
6
5
 
7
- export const FundingSteps = () => {
8
- const { formatMessage } = useIntl();
6
+ type ModalDescriptions = {
7
+ title: string;
8
+ description: string;
9
+ };
10
+
11
+ type FundingStepsProps = {
12
+ descriptions: ModalDescriptions[];
13
+ };
14
+
15
+ export const FundingSteps = ({ descriptions }: FundingStepsProps) => {
9
16
  const isSmallScreen = useDetectSmallScreen();
17
+ const modalDescriptions = getModalItems(descriptions);
10
18
 
11
19
  return (
12
20
  <Flex direction="column" gap="2">
13
- {MODAL_ITEMS.map(({ id, title, subtitle, Icon }) => (
14
- <Flex key={id} direction="row" align="center" gap="2">
21
+ {modalDescriptions.map(({ title, description, Icon }) => (
22
+ <Flex key={title} direction="row" align="center" gap="2">
15
23
  {!isSmallScreen && <Icon />}
16
24
  <Flex direction="column">
17
25
  <Text color="default" fontWeight="medium">
18
- {formatMessage(title)}
26
+ {title}
19
27
  </Text>
20
- <Text color="placeholder">{formatMessage(subtitle)}</Text>
28
+ <Text color="placeholder">{description}</Text>
21
29
  </Flex>
22
30
  </Flex>
23
31
  ))}
@@ -1,20 +1,27 @@
1
- import { Button, Flex, Link, Text, useDetectDeviceSize } from '@wayflyer/flyui';
1
+ import { Button, Flex, useDetectDeviceSize } from '@wayflyer/flyui';
2
2
  import { IconArrowOnSquareUpRight16Line } from '@wayflyer/flyui-icons/16/line';
3
3
  import { StartHostedApplicationResponseType } from '@wf-financing/embedded-types';
4
- import { FormattedMessage } from 'react-intl';
4
+ import { Logger } from '@wf-financing/logger';
5
5
 
6
+ import { TemplateWithUrl } from './TemplateWithUrl';
6
7
  import { useDetectSmallScreen, useStartHostedApplication } from '../../hooks';
7
8
 
8
- type ModalFooterType = {
9
+ type ModalFooterProps = {
10
+ buttons: {
11
+ accept: string;
12
+ close: string;
13
+ };
14
+ termsAndConditions: string;
9
15
  setOpen: (isOpen: boolean) => void;
10
16
  };
11
17
 
12
- export const ModalFooter = ({ setOpen }: ModalFooterType) => {
18
+ export const ModalFooter = ({ setOpen, buttons, termsAndConditions }: ModalFooterProps) => {
13
19
  const { isMobile } = useDetectDeviceSize();
14
20
  const { mutate, isPending: isLoading } = useStartHostedApplication();
15
21
  const isSmallScreen = useDetectSmallScreen();
16
22
 
17
23
  const handleStartApplication = () => {
24
+ Logger.logEvent('cta_start_hosted_application');
18
25
  mutate(undefined, {
19
26
  onSuccess: (nextUrl: StartHostedApplicationResponseType) => {
20
27
  const { next } = nextUrl;
@@ -22,32 +29,23 @@ export const ModalFooter = ({ setOpen }: ModalFooterType) => {
22
29
  window.open(next);
23
30
  },
24
31
  onError: (error) => {
25
- console.error('Failed to start application', error);
32
+ Logger.logError(`Failed to start application ${error.message}`);
26
33
  },
27
34
  });
28
35
  };
29
36
 
30
- const handleOpenExternalLink = () => {
31
- window.open('https://wayflyer.com/en/privacy-notice', '_blank', 'noopener,noreferrer');
32
- };
33
-
34
37
  return (
35
38
  <Flex direction="column" gap="3">
36
39
  <Flex gap="2" direction={isSmallScreen || isMobile ? 'column' : 'row'}>
37
40
  <Button fullWidth onClick={handleStartApplication} loading={isLoading} variant="Primary" external>
38
- <FormattedMessage id="ctaModal.action" />
41
+ {buttons.accept}
39
42
  {!isLoading && <IconArrowOnSquareUpRight16Line />}
40
43
  </Button>
41
44
  <Button fullWidth variant="Secondary" onClick={() => setOpen(false)}>
42
- <FormattedMessage id="common.cancel" />
45
+ {buttons.close}
43
46
  </Button>
44
47
  </Flex>
45
- <Text size="sm" lineHeight="normal">
46
- <FormattedMessage id="ctaModal.consent" />
47
- <Link onClick={handleOpenExternalLink}>
48
- <FormattedMessage id="ctaModal.consent.privacy_policy" />
49
- </Link>
50
- </Text>
48
+ <TemplateWithUrl templateString={termsAndConditions} />
51
49
  </Flex>
52
50
  );
53
51
  };
@@ -0,0 +1,30 @@
1
+ import ReactMarkdown from 'react-markdown';
2
+ import { Link, Text } from '@wayflyer/flyui';
3
+ import { Logger } from '@wf-financing/logger';
4
+
5
+ import { injectUrlInTemplate } from '../../utils';
6
+
7
+ type TemplateWithUrlProps = {
8
+ templateString: string;
9
+ };
10
+
11
+ export const TemplateWithUrl = ({ templateString }: TemplateWithUrlProps) => {
12
+ const termsUrl = 'https://wayflyer.com/en/privacy-notice';
13
+ const text = injectUrlInTemplate(templateString, termsUrl, 'termsUrl');
14
+
15
+ const handleOpenExternalLink = () => {
16
+ Logger.logEvent('cta_open_privacy_note');
17
+ window.open('https://wayflyer.com/en/privacy-notice', '_blank', 'noopener,noreferrer');
18
+ };
19
+
20
+ return (
21
+ <ReactMarkdown
22
+ components={{
23
+ a: ({ children }) => <Link onClick={handleOpenExternalLink} children={children} />,
24
+ p: ({ children }) => <Text size="sm" lineHeight="normal" children={children} />,
25
+ }}
26
+ >
27
+ {text}
28
+ </ReactMarkdown>
29
+ );
30
+ };
@@ -0,0 +1 @@
1
+ export const APPLICATION_VERSION: string = import.meta.env.VITE_APP_VERSION;
@@ -6,3 +6,4 @@ export { HEADLESS_SDK_URL } from './url';
6
6
  export { WHITELISTED_PARTNER_IDS } from './whitelistedPartnerIds';
7
7
  export type { PartnerId, PartnerTheme } from './whitelistedPartnerIds';
8
8
  export { STATIC_BASE_URL, DM_SANS_URL, MERRION_SANS_URL, MODAL_LOGO_IMAGE_URL } from './staticUrls';
9
+ export { APPLICATION_VERSION } from './applicationVersion';
@@ -6,3 +6,4 @@ export { useContinueHostedApplication } from './useContinueHostedApplication';
6
6
  export { useDismissCta } from './useDismissCta';
7
7
  export { useRemoveInerted } from './useRemoveInerted';
8
8
  export { usePreloadImage } from './usePreloadImage';
9
+ export { useCopy } from './useCopy.ts';
@@ -0,0 +1,30 @@
1
+ import { SdkOptionsType } from '@wf-financing/embedded-types';
2
+ import { useQuery, keepPreviousData } from '@tanstack/react-query';
3
+ import { loadAndConfigureCopy } from '@wf-financing/ui-assets';
4
+
5
+ import { usePartnerContext } from './usePartnerContext.ts';
6
+ import { APPLICATION_VERSION } from '../config';
7
+ import { getPartnerIdFromToken } from '../utils';
8
+
9
+ type Options = SdkOptionsType & {
10
+ language?: string;
11
+ cohort?: string;
12
+ };
13
+
14
+ export const useCopy = () => {
15
+ const { options, companyToken } = usePartnerContext();
16
+
17
+ const partnerId = getPartnerIdFromToken(companyToken);
18
+ // TODO: remove after extension of SdkOptionType
19
+ const copyOptions = options as Options;
20
+
21
+ return useQuery({
22
+ queryKey: ['partnerCopy'],
23
+ queryFn: () => loadAndConfigureCopy({ version: APPLICATION_VERSION, partnerId, options: copyOptions }),
24
+ placeholderData: keepPreviousData,
25
+ refetchOnWindowFocus: false,
26
+ refetchOnMount: false,
27
+ staleTime: 10 * 60 * 1000,
28
+ gcTime: 10 * 60 * 1000,
29
+ });
30
+ };
package/src/main.tsx CHANGED
@@ -1,4 +1,5 @@
1
1
  import { PartnerCallbackType, SdkOptionsType } from '@wf-financing/embedded-types';
2
+ import { Logger } from '@wf-financing/logger';
2
3
  import ReactDOM from 'react-dom/client';
3
4
  import { StyleSheetManager } from 'styled-components';
4
5
 
@@ -24,10 +25,14 @@ export const mountToTarget = async (
24
25
  }
25
26
 
26
27
  const hostEl = document.getElementById(savedTargetId as string);
27
- if (!hostEl) throw new Error(`Target element with id "${savedTargetId}" not found.`);
28
+ if (!hostEl) {
29
+ Logger.logError(`Target element with id "${savedTargetId}" not found.`);
30
+ throw new Error(`Target element with id "${savedTargetId}" not found.`);
31
+ }
28
32
 
29
33
  const shadow = hostEl.shadowRoot ?? (hostEl.attachShadow({ mode: 'open' }) as ShadowRoot);
30
34
 
35
+ // TODO: remove font loading from SDK
31
36
  try {
32
37
  applyStyles({ shadow });
33
38
  await applyFont(shadow, partnerTheme);
@@ -61,4 +66,6 @@ export const mountToTarget = async (
61
66
  />
62
67
  </StyleSheetManager>,
63
68
  );
69
+
70
+ Logger.logEvent('cta_mounted_to_target');
64
71
  };
@@ -0,0 +1,26 @@
1
+ import { replacePlaceholdersForMainText } from './replacePlaceholdersForMainText.ts';
2
+
3
+ type CopySection = {
4
+ mainText: string;
5
+ buttonText: string;
6
+ bulletPoints?: string[];
7
+ };
8
+
9
+ export type BannerConfig = CopySection & {
10
+ buttonAction: () => void;
11
+ };
12
+
13
+ type BuildBannerConfig = (
14
+ copySection: CopySection,
15
+ buttonAction: () => void,
16
+ offer?: { currency: string; amount: number },
17
+ ) => BannerConfig;
18
+
19
+ export const buildBannerConfig: BuildBannerConfig = (copySection, buttonAction, offer) => ({
20
+ mainText: offer
21
+ ? replacePlaceholdersForMainText(offer.currency, offer.amount, copySection.mainText)
22
+ : copySection.mainText,
23
+ bulletPoints: copySection.bulletPoints,
24
+ buttonText: copySection.buttonText,
25
+ buttonAction: buttonAction,
26
+ });
@@ -0,0 +1,44 @@
1
+ import type { Copy } from '@wf-financing/ui-assets';
2
+ import { CtaStateType, ApplicationRequiredActions, CtaResponseType } from '@wf-financing/embedded-types';
3
+
4
+ import { buildBannerConfig, type BannerConfig } from './buildBannerConfig.ts';
5
+
6
+ type GetBannerConfig = (
7
+ cta: Exclude<CtaResponseType, null>,
8
+ copy: Copy,
9
+ handleIsModalOpen: () => void,
10
+ handleContinueHostedApplication: () => void,
11
+ ) => BannerConfig;
12
+
13
+ export const getBannerConfig: GetBannerConfig = (cta, copy, handleIsModalOpen, handleContinueHostedApplication) => {
14
+ const { state, data } = cta;
15
+ const {
16
+ genericOffer,
17
+ indicativeOffer,
18
+ completeApplication,
19
+ selectOffer,
20
+ completeKyc,
21
+ signContract,
22
+ provideAdditionalInfo,
23
+ } = copy;
24
+
25
+ switch (state) {
26
+ case CtaStateType.GENERIC_OFFER:
27
+ return buildBannerConfig(genericOffer, handleIsModalOpen);
28
+ case CtaStateType.INDICATIVE_OFFER:
29
+ return buildBannerConfig(indicativeOffer, handleIsModalOpen, data.offer);
30
+ case CtaStateType.CONTINUE_APPLICATION:
31
+ switch (cta.data.config.required_action) {
32
+ case ApplicationRequiredActions.COMPLETE_APPLICATION:
33
+ return buildBannerConfig(completeApplication, handleContinueHostedApplication);
34
+ case ApplicationRequiredActions.SELECT_OFFER:
35
+ return buildBannerConfig(selectOffer, handleContinueHostedApplication, data.offer);
36
+ case ApplicationRequiredActions.COMPLETE_KYC:
37
+ return buildBannerConfig(completeKyc, handleContinueHostedApplication);
38
+ case ApplicationRequiredActions.SIGN_CONTRACT:
39
+ return buildBannerConfig(signContract, handleContinueHostedApplication);
40
+ case ApplicationRequiredActions.PROVIDE_ADDITIONAL_INFO:
41
+ return buildBannerConfig(provideAdditionalInfo, handleContinueHostedApplication);
42
+ }
43
+ }
44
+ };
@@ -0,0 +1,19 @@
1
+ import {
2
+ IconArrowsCwHorizontal24Line,
3
+ IconCheckCircle24Line,
4
+ IconPersonCircle24Line,
5
+ } from '@wayflyer/flyui-icons/24/line';
6
+
7
+ type ModalDescriptions = {
8
+ title: string;
9
+ description: string;
10
+ };
11
+
12
+ export const getModalItems = (consentModalDescription: ModalDescriptions[]) => {
13
+ const modalIcons = [IconPersonCircle24Line, IconArrowsCwHorizontal24Line, IconCheckCircle24Line];
14
+
15
+ return consentModalDescription.map((description, id) => ({
16
+ ...description,
17
+ Icon: modalIcons[id],
18
+ }));
19
+ };
@@ -6,3 +6,8 @@ export { getPartnerThemeById } from './getPartnerThemeById';
6
6
  export { initializeHeadlessSdk } from './initializeHeadlessSdk';
7
7
  export { loadScriptAndInitializeSdk } from './loadScriptAndInitializeSdk';
8
8
  export { PartnerContext, type PartnerContextType } from './partnerContext';
9
+ export { replacePlaceholdersForMainText } from './replacePlaceholdersForMainText.ts';
10
+ export { getModalItems } from './getModalItems';
11
+ export { injectUrlInTemplate } from './injectUrlInTemplate';
12
+ export { buildBannerConfig, type BannerConfig } from './buildBannerConfig';
13
+ export { getBannerConfig } from './getBannerConfig';
@@ -0,0 +1,6 @@
1
+ export const injectUrlInTemplate = (template: string, url: string, placeholder: string) => {
2
+ const escaped = placeholder.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
3
+ const regex = new RegExp(`\\(\\{${escaped}\\}\\)`, 'g');
4
+
5
+ return template.replace(regex, `(${url})`);
6
+ };
@@ -1,3 +1,5 @@
1
+ import { Logger } from '@wf-financing/logger';
2
+
1
3
  type CompanyToken = {
2
4
  sub: string;
3
5
  };
@@ -5,8 +7,8 @@ type CompanyToken = {
5
7
  export const parseJwt = (token: string): CompanyToken | null => {
6
8
  try {
7
9
  return JSON.parse(atob(token.split('.')[1]));
8
- } catch (error) {
9
- console.error('Error parsing a company token:', error);
10
+ } catch {
11
+ Logger.logError('Error parsing a company token');
10
12
  return null;
11
13
  }
12
14
  };
@@ -0,0 +1,29 @@
1
+ export const replacePlaceholdersForMainText = (currency: string, amount: number, templateString: string): string => {
2
+ const currencies = [
3
+ { code: 'USD', icon: '$', position: 'before' },
4
+ { code: 'GBP', icon: '£', position: 'before' },
5
+ { code: 'EUR', icon: '€', position: 'after' },
6
+ { code: 'SEK', icon: 'kr', position: 'after' },
7
+ { code: 'DKK', icon: 'kr', position: 'after' },
8
+ { code: 'AUD', icon: 'A$', position: 'before' },
9
+ { code: 'CAD', icon: 'C$', position: 'before' },
10
+ ];
11
+ const currencyWithIcon = currencies.find(({ code }) => currency === code);
12
+
13
+ const getConvertedAmount = () => {
14
+ if (!currencyWithIcon) return `${amount}${currency}`;
15
+
16
+ const { position, icon } = currencyWithIcon;
17
+
18
+ switch (position) {
19
+ case 'before':
20
+ return `${icon}${amount}`;
21
+ case 'after':
22
+ return `${amount}${icon}`;
23
+ default:
24
+ return `${icon}${amount}`;
25
+ }
26
+ };
27
+
28
+ return templateString.replace('{amount}', getConvertedAmount());
29
+ };
package/tsconfig.json CHANGED
@@ -2,7 +2,8 @@
2
2
  "extends": "../../tsconfig.base.json",
3
3
  "compilerOptions": {
4
4
  "rootDir": ".",
5
- "baseUrl": "."
5
+ "baseUrl": ".",
6
+ "resolveJsonModule": true
6
7
  },
7
8
  "include": ["**/*.ts", "**/*.tsx"],
8
9
  "exclude": ["dist", "tests", "playground", "node_modules"]
package/vite-env.d.ts ADDED
@@ -0,0 +1 @@
1
+ /// <reference types="vite/client" />
package/vite.config.mts CHANGED
@@ -4,6 +4,8 @@ import { defineConfig, type ConfigEnv, type UserConfig, type PluginOption } from
4
4
  import { visualizer } from 'rollup-plugin-visualizer';
5
5
  import inject from '@rollup/plugin-inject';
6
6
 
7
+ import pkg from './package.json';
8
+
7
9
  const visualizerOptions = {
8
10
  'analyze-html': { emitFile: true, filename: `bundle-stats/index.html`, gzipSize: true },
9
11
  'analyze-json': { emitFile: true, filename: `bundle-stats/stats.json`, template: 'raw-data', gzipSize: true },
@@ -18,6 +20,7 @@ export default defineConfig(({ mode }: ConfigEnv): UserConfig => {
18
20
  define: {
19
21
  'process.env': {},
20
22
  'process.env.NODE_ENV': JSON.stringify(mode),
23
+ 'import.meta.env.VITE_APP_VERSION': JSON.stringify(pkg.version),
21
24
  },
22
25
  server: {
23
26
  host: true,
@@ -1,13 +0,0 @@
1
- import { Flex } from '@wayflyer/flyui';
2
-
3
- import { CloseButton } from './CloseButton';
4
- import { ProceedFundingButton } from './ProceedFundingButton';
5
-
6
- export const BannerActionsDesktop = ({ isOnDarkTheme }: { isOnDarkTheme: boolean }) => {
7
- return (
8
- <Flex gap="4">
9
- <ProceedFundingButton isOnDarkTheme={isOnDarkTheme} />
10
- <CloseButton isOnDarkTheme={isOnDarkTheme} />
11
- </Flex>
12
- );
13
- };
@@ -1,37 +0,0 @@
1
- import { Flex, Text, Heading } from '@wayflyer/flyui';
2
- import type { CtaResponseType } from '@wf-financing/embedded-types';
3
-
4
- import { useCtaBanner } from '../../hooks';
5
- import { BulletList } from './BulletList';
6
-
7
- type CtaBannerContentProps = {
8
- isMobile: boolean;
9
- isTablet: boolean;
10
- isOnDarkTheme: boolean;
11
- };
12
-
13
- export const CtaBannerContent = ({ isMobile, isTablet, isOnDarkTheme }: CtaBannerContentProps) => {
14
- const sdk = useCtaBanner();
15
- const ctaData = sdk.data as CtaResponseType;
16
- const TextComponent = isMobile ? Text : Heading;
17
-
18
- return (
19
- <>
20
- {!sdk.isLoading && (
21
- <Flex direction="column" gap="1">
22
- <TextComponent
23
- size={isMobile ? 'base' : 'lg'}
24
- fontWeight="medium"
25
- lineHeight="normal"
26
- color={isOnDarkTheme ? 'onDark' : 'default'}
27
- >
28
- {ctaData?.data?.config?.text}
29
- </TextComponent>
30
- {!(isTablet || isMobile) && ctaData?.data?.config?.bullet_points && (
31
- <BulletList items={ctaData?.data?.config?.bullet_points} isOnDarkTheme={isOnDarkTheme} />
32
- )}
33
- </Flex>
34
- )}
35
- </>
36
- );
37
- };
@@ -1,8 +0,0 @@
1
- import { useDetectDeviceSize } from '@wayflyer/flyui';
2
- import { ProceedFundingButton } from './ProceedFundingButton';
3
-
4
- export const FooterActions = ({ isOnDarkTheme }: { isOnDarkTheme: boolean }) => {
5
- const { isMobile } = useDetectDeviceSize();
6
-
7
- return isMobile ? <ProceedFundingButton isOnDarkTheme={isOnDarkTheme} /> : null;
8
- };
@@ -1,21 +0,0 @@
1
- import { useDetectDeviceSize } from '@wayflyer/flyui';
2
- import styled from 'styled-components';
3
- import { BannerActionsDesktop } from './BannerActionsDesktop';
4
- import { CloseButton } from './CloseButton';
5
-
6
- const MobileButtonContainer = styled.div`
7
- margin-top: calc(0px - var(--sizes-spacing-3));
8
- margin-right: calc(0px - var(--sizes-spacing-2));
9
- `;
10
-
11
- export const HeaderActions = ({ isOnDarkTheme }: { isOnDarkTheme: boolean }) => {
12
- const { isMobile } = useDetectDeviceSize();
13
-
14
- return isMobile ? (
15
- <MobileButtonContainer>
16
- <CloseButton isOnDarkTheme={isOnDarkTheme} />
17
- </MobileButtonContainer>
18
- ) : (
19
- <BannerActionsDesktop isOnDarkTheme={isOnDarkTheme} />
20
- );
21
- };
@@ -1,61 +0,0 @@
1
- import { Button } from '@wayflyer/flyui';
2
- import {
3
- CtaContinueFundingType,
4
- CtaGenericOfferType,
5
- CtaIndicativeOfferType,
6
- CtaStateType,
7
- ContinueHostedApplicationResponseType,
8
- } from '@wf-financing/embedded-types';
9
- import { useState } from 'react';
10
-
11
- import { useCtaBanner, useContinueHostedApplication } from '../../hooks';
12
- import { ConsentModal } from '../modal/ConsentModal';
13
-
14
- type CtaResponseType = CtaGenericOfferType | CtaIndicativeOfferType | CtaContinueFundingType;
15
-
16
- export const ProceedFundingButton = ({ isOnDarkTheme }: { isOnDarkTheme: boolean }) => {
17
- const [isModalOpen, setIsModalOpen] = useState(false);
18
- const sdkResponse = useCtaBanner();
19
- const sdk = sdkResponse.data as CtaResponseType;
20
- const { mutate, isPending: isLoading } = useContinueHostedApplication();
21
-
22
- if (!sdk) return null;
23
-
24
- const {
25
- state,
26
- data: { config },
27
- } = sdk;
28
-
29
- const handleContinueHostedApplication = () => {
30
- switch (state) {
31
- case CtaStateType.CONTINUE_APPLICATION:
32
- mutate(undefined, {
33
- onSuccess: (nextUrl: ContinueHostedApplicationResponseType) => {
34
- const { next } = nextUrl;
35
- window.open(next);
36
- },
37
- onError: (error) => {
38
- console.error('Failed to continue application', error);
39
- },
40
- });
41
- break;
42
- default:
43
- setIsModalOpen(true);
44
- break;
45
- }
46
- };
47
-
48
- return (
49
- <>
50
- <Button
51
- variant={isOnDarkTheme ? 'PrimaryOnDark' : 'Primary'}
52
- fullWidth
53
- onClick={handleContinueHostedApplication}
54
- loading={isLoading}
55
- >
56
- {config?.button_label}
57
- </Button>
58
- <ConsentModal isModalOpen={isModalOpen} setIsModalOpen={setIsModalOpen} />
59
- </>
60
- );
61
- };
@@ -1 +0,0 @@
1
- export { MODAL_ITEMS } from './modalItems';
@@ -1,26 +0,0 @@
1
- import {
2
- IconArrowsCwHorizontal24Line,
3
- IconCheckCircle24Line,
4
- IconPersonCircle24Line,
5
- } from '@wayflyer/flyui-icons/24/line';
6
-
7
- export const MODAL_ITEMS = [
8
- {
9
- id: 'step1',
10
- title: { id: 'ctaModal.step1.title' },
11
- subtitle: { id: 'ctaModal.step1.subtitle' },
12
- Icon: IconPersonCircle24Line,
13
- },
14
- {
15
- id: 'step2',
16
- title: { id: 'ctaModal.step2.title' },
17
- subtitle: { id: 'ctaModal.step2.subtitle' },
18
- Icon: IconArrowsCwHorizontal24Line,
19
- },
20
- {
21
- id: 'step3',
22
- title: { id: 'ctaModal.step3.title' },
23
- subtitle: { id: 'ctaModal.step3.subtitle' },
24
- Icon: IconCheckCircle24Line,
25
- },
26
- ];