@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.
- package/CHANGELOG.md +24 -0
- package/dist/index.es.js +21897 -12225
- package/global.d.ts +1 -1
- package/index.ts +2 -2
- package/package.json +5 -2
- package/src/App.tsx +5 -2
- package/src/CtaWidget.tsx +31 -9
- package/src/api/ctaBanner.ts +1 -2
- package/src/api/getHeadlessSdkInstance.ts +4 -2
- package/src/components/banner/BannerActions.tsx +26 -0
- package/src/components/banner/BulletList.tsx +34 -21
- package/src/components/banner/CloseButton.tsx +22 -2
- package/src/components/banner/CtaBanner.snapshot.stories.tsx +11 -1
- package/src/components/banner/CtaBanner.tsx +23 -8
- package/src/components/banner/CtaMainText.tsx +23 -0
- package/src/components/modal/ConsentModal.snapshot.stories.tsx +28 -25
- package/src/components/modal/ConsentModal.tsx +18 -30
- package/src/components/modal/ConsentModalContent.tsx +63 -0
- package/src/components/modal/FundingSteps.tsx +16 -8
- package/src/components/modal/ModalFooter.tsx +15 -17
- package/src/components/modal/TemplateWithUrl.tsx +30 -0
- package/src/config/applicationVersion.ts +1 -0
- package/src/config/index.ts +1 -0
- package/src/hooks/index.ts +1 -0
- package/src/hooks/useCopy.ts +30 -0
- package/src/main.tsx +8 -1
- package/src/utils/buildBannerConfig.ts +26 -0
- package/src/utils/getBannerConfig.ts +44 -0
- package/src/utils/getModalItems.ts +19 -0
- package/src/utils/index.ts +5 -0
- package/src/utils/injectUrlInTemplate.ts +6 -0
- package/src/utils/parseJwt.ts +4 -2
- package/src/utils/replacePlaceholdersForMainText.ts +29 -0
- package/tsconfig.json +2 -1
- package/vite-env.d.ts +1 -0
- package/vite.config.mts +3 -0
- package/src/components/banner/BannerActionsDesktop.tsx +0 -13
- package/src/components/banner/CtaBannerContent.tsx +0 -37
- package/src/components/banner/FooterActions.tsx +0 -8
- package/src/components/banner/HeaderActions.tsx +0 -21
- package/src/components/banner/ProceedFundingButton.tsx +0 -61
- package/src/constants/index.ts +0 -1
- 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 {
|
|
4
|
+
import { getModalItems } from '../../utils';
|
|
6
5
|
|
|
7
|
-
|
|
8
|
-
|
|
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
|
-
{
|
|
14
|
-
<Flex key={
|
|
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
|
-
{
|
|
26
|
+
{title}
|
|
19
27
|
</Text>
|
|
20
|
-
<Text color="placeholder">{
|
|
28
|
+
<Text color="placeholder">{description}</Text>
|
|
21
29
|
</Flex>
|
|
22
30
|
</Flex>
|
|
23
31
|
))}
|
|
@@ -1,20 +1,27 @@
|
|
|
1
|
-
import { Button, Flex,
|
|
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 {
|
|
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
|
|
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 }:
|
|
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
|
-
|
|
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
|
-
|
|
41
|
+
{buttons.accept}
|
|
39
42
|
{!isLoading && <IconArrowOnSquareUpRight16Line />}
|
|
40
43
|
</Button>
|
|
41
44
|
<Button fullWidth variant="Secondary" onClick={() => setOpen(false)}>
|
|
42
|
-
|
|
45
|
+
{buttons.close}
|
|
43
46
|
</Button>
|
|
44
47
|
</Flex>
|
|
45
|
-
<
|
|
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;
|
package/src/config/index.ts
CHANGED
|
@@ -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';
|
package/src/hooks/index.ts
CHANGED
|
@@ -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)
|
|
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
|
+
};
|
package/src/utils/index.ts
CHANGED
|
@@ -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
|
+
};
|
package/src/utils/parseJwt.ts
CHANGED
|
@@ -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
|
|
9
|
-
|
|
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
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
|
-
};
|
package/src/constants/index.ts
DELETED
|
@@ -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
|
-
];
|