@wf-financing/ui 0.1.1 → 1.1.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/README.md +3 -0
- package/dist/index.es.js +72962 -68930
- package/global.d.ts +8 -0
- package/index.ts +5 -18
- package/package.json +24 -7
- package/sdk/index.ts +36 -0
- package/src/App.tsx +7 -6
- package/src/CtaWidget.tsx +13 -8
- package/src/api/ctaBanner.ts +5 -3
- package/src/api/fetchCtaBanner.test.ts +36 -0
- package/src/api/getHeadlessSdkInstance.test.ts +54 -0
- package/src/api/getHeadlessSdkInstance.ts +32 -7
- package/src/api/startHostedApplication.test.ts +53 -0
- package/src/api/startHostedApplication.ts +4 -4
- package/src/components/banner/BannerActionsDesktop.tsx +13 -0
- package/src/components/banner/BannerContent.stories.tsx +31 -0
- package/src/components/banner/BulletList.stories.tsx +15 -0
- package/src/components/banner/BulletList.tsx +1 -1
- package/src/components/banner/CloseButton.tsx +16 -0
- package/src/components/banner/CtaBanner.stories.tsx +51 -0
- package/src/components/banner/CtaBanner.tsx +24 -22
- package/src/components/banner/CtaBannerContent.tsx +14 -10
- package/src/components/banner/FooterActions.tsx +8 -0
- package/src/components/banner/HeaderActions.tsx +9 -0
- package/src/components/banner/ProceedFundingButton.tsx +17 -6
- package/src/components/modal/ConsentModal.stories.tsx +42 -0
- package/src/components/modal/ConsentModal.tsx +2 -2
- package/src/components/modal/FundingSteps.tsx +2 -4
- package/src/components/modal/Modal.tsx +4 -9
- package/src/components/modal/ModalFooter.tsx +21 -13
- package/src/components/modal/modalEnhancements.ts +3 -4
- package/src/config/index.ts +2 -0
- package/src/config/scriptId.ts +1 -0
- package/src/config/url.ts +1 -0
- package/src/hooks/index.ts +3 -0
- package/src/hooks/useCtaBanner.ts +5 -11
- package/src/hooks/usePartnerContext.ts +7 -0
- package/src/hooks/useStartHostedApplication.ts +4 -13
- package/src/locales/en.json +3 -1
- package/src/main.tsx +12 -14
- package/src/utils/index.ts +3 -0
- package/src/utils/initializeHeadlessSdk.ts +21 -0
- package/src/utils/loadScriptAndInitializeSdk.ts +19 -0
- package/src/utils/partnerContext.ts +10 -6
- package/tsconfig.json +2 -2
- package/vite.config.ts +2 -1
- package/vitest.shims.d.ts +1 -0
- package/src/components/banner/CtaBannerActions.tsx +0 -19
|
@@ -1,26 +1,30 @@
|
|
|
1
|
-
import { Flex,
|
|
1
|
+
import { Flex, Text } from '@wayflyer/flyui';
|
|
2
2
|
import type { CtaResponseType } from '@wf-financing/embedded-types';
|
|
3
3
|
|
|
4
4
|
import { useCtaBanner } from '../../hooks/useCtaBanner';
|
|
5
5
|
import { BulletList } from './BulletList';
|
|
6
6
|
|
|
7
|
-
type
|
|
7
|
+
type CtaBannerContentProps = {
|
|
8
8
|
isMobile: boolean;
|
|
9
9
|
isTablet: boolean;
|
|
10
10
|
};
|
|
11
11
|
|
|
12
|
-
export const CtaBannerContent = ({ isMobile, isTablet }:
|
|
12
|
+
export const CtaBannerContent = ({ isMobile, isTablet }: CtaBannerContentProps) => {
|
|
13
13
|
const sdk = useCtaBanner();
|
|
14
14
|
const ctaData = sdk.data as CtaResponseType;
|
|
15
15
|
|
|
16
16
|
return (
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
17
|
+
<>
|
|
18
|
+
{!sdk.isLoading && (
|
|
19
|
+
<Flex direction="column" gap="1">
|
|
20
|
+
<Text size={isMobile ? 'lg' : 'xl'} fontStyle="regular" fontWeight="medium" lineHeight="normal">
|
|
21
|
+
{ctaData?.data?.config?.text}
|
|
22
|
+
</Text>
|
|
23
|
+
{!(isTablet || isMobile) && ctaData?.data?.config?.bullet_points && (
|
|
24
|
+
<BulletList items={ctaData?.data?.config?.bullet_points} />
|
|
25
|
+
)}
|
|
26
|
+
</Flex>
|
|
23
27
|
)}
|
|
24
|
-
|
|
28
|
+
</>
|
|
25
29
|
);
|
|
26
30
|
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { useDetectDeviceSize } from '@wayflyer/flyui';
|
|
2
|
+
import { ProceedFundingButton } from './ProceedFundingButton';
|
|
3
|
+
|
|
4
|
+
export const FooterActions = () => {
|
|
5
|
+
const { isMobile } = useDetectDeviceSize();
|
|
6
|
+
|
|
7
|
+
return isMobile ? <ProceedFundingButton /> : null;
|
|
8
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { useDetectDeviceSize } from '@wayflyer/flyui';
|
|
2
|
+
import { BannerActionsDesktop } from './BannerActionsDesktop';
|
|
3
|
+
import { CloseButton } from './CloseButton';
|
|
4
|
+
|
|
5
|
+
export const HeaderActions = () => {
|
|
6
|
+
const { isMobile } = useDetectDeviceSize();
|
|
7
|
+
|
|
8
|
+
return isMobile ? <CloseButton /> : <BannerActionsDesktop />;
|
|
9
|
+
};
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { Button } from '@wayflyer/flyui';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
CtaContinueFundingType,
|
|
4
|
+
CtaGenericOfferType,
|
|
5
|
+
CtaIndicativeOfferType,
|
|
6
|
+
CtaStateType,
|
|
7
|
+
} from '@wf-financing/embedded-types';
|
|
3
8
|
import { useState } from 'react';
|
|
4
9
|
|
|
5
10
|
import { useCtaBanner } from '../../hooks/useCtaBanner';
|
|
@@ -10,8 +15,14 @@ type CtaResponseType = CtaGenericOfferType | CtaIndicativeOfferType | CtaContinu
|
|
|
10
15
|
export const ProceedFundingButton = () => {
|
|
11
16
|
const [isModalOpen, setIsModalOpen] = useState(false);
|
|
12
17
|
const sdkResponse = useCtaBanner();
|
|
13
|
-
const sdk = sdkResponse.data as CtaResponseType
|
|
14
|
-
|
|
18
|
+
const sdk = sdkResponse.data as CtaResponseType;
|
|
19
|
+
|
|
20
|
+
if (!sdk) return null;
|
|
21
|
+
|
|
22
|
+
const {
|
|
23
|
+
state,
|
|
24
|
+
data: { config },
|
|
25
|
+
} = sdk;
|
|
15
26
|
|
|
16
27
|
const handleButtonClick = () => {
|
|
17
28
|
switch (state) {
|
|
@@ -22,12 +33,12 @@ export const ProceedFundingButton = () => {
|
|
|
22
33
|
setIsModalOpen(true);
|
|
23
34
|
break;
|
|
24
35
|
}
|
|
25
|
-
|
|
36
|
+
};
|
|
26
37
|
|
|
27
38
|
return (
|
|
28
39
|
<>
|
|
29
|
-
<Button variant="Primary" onClick={handleButtonClick}>
|
|
30
|
-
{config
|
|
40
|
+
<Button variant="Primary" fullWidth onClick={handleButtonClick}>
|
|
41
|
+
{config?.button_label}
|
|
31
42
|
</Button>
|
|
32
43
|
<ConsentModal isModalOpen={isModalOpen} setIsModalOpen={setIsModalOpen} />
|
|
33
44
|
</>
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { ConsentModal } from './ConsentModal';
|
|
3
|
+
|
|
4
|
+
const fn = (): void => {};
|
|
5
|
+
|
|
6
|
+
const meta: Meta<typeof ConsentModal> = {
|
|
7
|
+
title: 'ConsentModal',
|
|
8
|
+
component: ConsentModal,
|
|
9
|
+
argTypes: {
|
|
10
|
+
isModalOpen: { control: 'boolean', defaultValue: true },
|
|
11
|
+
setIsModalOpen: { action: 'setIsModalOpen' },
|
|
12
|
+
},
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export default meta;
|
|
16
|
+
|
|
17
|
+
type Story = StoryObj<typeof ConsentModal>;
|
|
18
|
+
|
|
19
|
+
export const Default: Story = {
|
|
20
|
+
args: {
|
|
21
|
+
isModalOpen: true,
|
|
22
|
+
setIsModalOpen: fn,
|
|
23
|
+
},
|
|
24
|
+
render: (args) => <ConsentModal {...args} />,
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export const WithContent: Story = {
|
|
28
|
+
args: {
|
|
29
|
+
isModalOpen: true,
|
|
30
|
+
setIsModalOpen: fn,
|
|
31
|
+
},
|
|
32
|
+
render: (args) => (
|
|
33
|
+
<ConsentModal {...args}>
|
|
34
|
+
<div style={{ padding: '20px', background: 'white' }}>
|
|
35
|
+
<h2>Consent Agreement</h2>
|
|
36
|
+
<p>Please agree to the terms to proceed.</p>
|
|
37
|
+
<button>Continue with Wayflyer</button>
|
|
38
|
+
<button>Cancel</button>
|
|
39
|
+
</div>
|
|
40
|
+
</ConsentModal>
|
|
41
|
+
),
|
|
42
|
+
};
|
|
@@ -16,9 +16,9 @@ export const ConsentModal = ({ isModalOpen, setIsModalOpen }: ConsentModalProps)
|
|
|
16
16
|
return (
|
|
17
17
|
<Modal isModalOpen={isModalOpen} setIsModalOpen={setIsModalOpen}>
|
|
18
18
|
<Image src="https://static.wayflyer.com/flyui-assets/logos/wayflyer-ef.png" />
|
|
19
|
-
<Flex margin={['6'
|
|
19
|
+
<Flex margin={['6']} direction="column" gap="10">
|
|
20
20
|
<Flex direction="column" gap="6">
|
|
21
|
-
<Text fontWeight="
|
|
21
|
+
<Text fontStyle="regular" fontWeight="medium" lineHeight="tight" size="2xl">
|
|
22
22
|
{formatMessage({ id: 'ctaModal.title' })}
|
|
23
23
|
</Text>
|
|
24
24
|
<FundingSteps />
|
|
@@ -13,10 +13,8 @@ export const FundingSteps = () => {
|
|
|
13
13
|
<Flex key={id} direction="column" gap="1">
|
|
14
14
|
<Flex gap="2" direction="row" align="center">
|
|
15
15
|
<Icon />
|
|
16
|
-
<Text fontWeight="
|
|
17
|
-
|
|
18
|
-
</Text>
|
|
19
|
-
<Badge>{formatMessage(time)}</Badge>
|
|
16
|
+
<Text fontWeight="medium">{formatMessage(title)}</Text>
|
|
17
|
+
<Badge size="small">{formatMessage(time)}</Badge>
|
|
20
18
|
</Flex>
|
|
21
19
|
<div style={{ paddingLeft: theme.spacing('8') }}>
|
|
22
20
|
<Text color="placeholder">{formatMessage(subtitle)}</Text>
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Dialog
|
|
3
|
-
} from '@wayflyer/flyui';
|
|
1
|
+
import { Dialog } from '@wayflyer/flyui';
|
|
4
2
|
import { AnimatePresence, LazyMotion, domAnimation } from 'framer-motion';
|
|
5
3
|
import { ReactNode, useId, useRef } from 'react';
|
|
6
4
|
import { UNSAFE_PortalProvider as PortalProvider } from 'react-aria';
|
|
@@ -12,7 +10,7 @@ type ModalProps = {
|
|
|
12
10
|
isModalOpen: boolean;
|
|
13
11
|
setIsModalOpen: (isOpen: boolean) => void;
|
|
14
12
|
children: ReactNode;
|
|
15
|
-
}
|
|
13
|
+
};
|
|
16
14
|
|
|
17
15
|
export const Modal = ({ isModalOpen, setIsModalOpen, children }: ModalProps) => {
|
|
18
16
|
const modalId = useId();
|
|
@@ -33,7 +31,7 @@ export const Modal = ({ isModalOpen, setIsModalOpen, children }: ModalProps) =>
|
|
|
33
31
|
animate={fullSize}
|
|
34
32
|
exit={small}
|
|
35
33
|
transition={{ duration: 0.3 }}
|
|
36
|
-
style={{ width: '438px', border: 'none' }}
|
|
34
|
+
style={{ width: '438px', border: 'none', maxWidth: '100vw' }}
|
|
37
35
|
>
|
|
38
36
|
<MotionModalOverlay
|
|
39
37
|
data-id="modal-mask"
|
|
@@ -43,10 +41,7 @@ export const Modal = ({ isModalOpen, setIsModalOpen, children }: ModalProps) =>
|
|
|
43
41
|
exit={transparent}
|
|
44
42
|
transition={{ duration: 0.6 }}
|
|
45
43
|
/>
|
|
46
|
-
<Dialog
|
|
47
|
-
role="dialog"
|
|
48
|
-
aria-labelledby={modalId}
|
|
49
|
-
>
|
|
44
|
+
<Dialog role="dialog" aria-labelledby={modalId}>
|
|
50
45
|
<DialogBody ref={scrollableElRef} data-testid="modal-body">
|
|
51
46
|
{children}
|
|
52
47
|
</DialogBody>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { Button, Flex, Text } from '@wayflyer/flyui';
|
|
1
|
+
import { Button, Flex, Link, Text } from '@wayflyer/flyui';
|
|
2
|
+
import { IconArrowOnSquareUpRight16Line } from '@wayflyer/flyui-icons/16/line';
|
|
2
3
|
import { StartHostedApplicationResponseType } from '@wf-financing/embedded-types';
|
|
3
|
-
import {
|
|
4
|
+
import { FormattedMessage } from 'react-intl';
|
|
4
5
|
|
|
5
6
|
import { useStartHostedApplication } from '../../hooks/useStartHostedApplication';
|
|
6
7
|
|
|
@@ -9,33 +10,40 @@ type ModalFooterType = {
|
|
|
9
10
|
};
|
|
10
11
|
|
|
11
12
|
export const ModalFooter = ({ setOpen }: ModalFooterType) => {
|
|
12
|
-
const { formatMessage } = useIntl();
|
|
13
13
|
const startHostedAppMutation = useStartHostedApplication();
|
|
14
14
|
|
|
15
15
|
const handleStartApplication = () => {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
16
|
+
startHostedAppMutation.mutate(undefined, {
|
|
17
|
+
onSuccess: (nextUrl: StartHostedApplicationResponseType) => {
|
|
18
|
+
const { next } = nextUrl;
|
|
19
|
+
window.open(next);
|
|
20
|
+
},
|
|
21
21
|
onError: (error) => {
|
|
22
22
|
console.error('Failed to start application', error);
|
|
23
23
|
},
|
|
24
24
|
});
|
|
25
25
|
};
|
|
26
26
|
|
|
27
|
+
const handleOpenExternalLink = () => {
|
|
28
|
+
window.open('https://wayflyer.com/en/privacy-notice', '_blank', 'noopener,noreferrer');
|
|
29
|
+
};
|
|
30
|
+
|
|
27
31
|
return (
|
|
28
32
|
<Flex direction="column" gap="3">
|
|
29
33
|
<Flex gap="2">
|
|
30
|
-
<Button onClick={handleStartApplication} variant="Primary">
|
|
31
|
-
|
|
34
|
+
<Button fullWidth onClick={handleStartApplication} variant="Primary" external>
|
|
35
|
+
<FormattedMessage id="ctaModal.action" />
|
|
36
|
+
<IconArrowOnSquareUpRight16Line />
|
|
32
37
|
</Button>
|
|
33
|
-
<Button variant="
|
|
34
|
-
|
|
38
|
+
<Button fullWidth variant="Secondary" onClick={() => setOpen(false)}>
|
|
39
|
+
<FormattedMessage id="common.cancel" />
|
|
35
40
|
</Button>
|
|
36
41
|
</Flex>
|
|
37
42
|
<Text size="sm" lineHeight="normal">
|
|
38
|
-
|
|
43
|
+
<FormattedMessage id="ctaModal.consent" />
|
|
44
|
+
<Link onClick={handleOpenExternalLink}>
|
|
45
|
+
<FormattedMessage id="ctaModal.consent.privacy_policy" />
|
|
46
|
+
</Link>
|
|
39
47
|
</Text>
|
|
40
48
|
</Flex>
|
|
41
49
|
);
|
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ModalOverlay as OriginalModalOverlay,
|
|
3
|
-
ModalPrimitive as OriginalModalPrimitive
|
|
4
|
-
} from '@wayflyer/flyui';
|
|
1
|
+
import { ModalOverlay as OriginalModalOverlay, ModalPrimitive as OriginalModalPrimitive } from '@wayflyer/flyui';
|
|
5
2
|
import { m } from 'framer-motion';
|
|
6
3
|
import styled from 'styled-components';
|
|
7
4
|
|
|
@@ -24,6 +21,8 @@ export const DialogBody = styled.div`
|
|
|
24
21
|
overflow-y: auto;
|
|
25
22
|
background-color: var(--palette-modal-surface);
|
|
26
23
|
border-radius: var(--sizes-radius-md);
|
|
24
|
+
max-height: 80vh;
|
|
25
|
+
padding-bottom: 10px;
|
|
27
26
|
|
|
28
27
|
&::-webkit-scrollbar {
|
|
29
28
|
width: 12px;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const WAYFLYER_HEADLESS_SDK_ID = 'wayflyer-headless-sdk';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const HEADLESS_SDK_URL = 'https://unpkg.com/@wf-financing/headless@1/dist/index.es.js';
|
|
@@ -1,20 +1,14 @@
|
|
|
1
1
|
import { useQuery } from '@tanstack/react-query';
|
|
2
|
-
import { useContext } from 'react';
|
|
3
2
|
|
|
4
3
|
import { fetchCtaBanner } from '../api/ctaBanner';
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
type PartnerDataType = {
|
|
8
|
-
companyToken: string;
|
|
9
|
-
isMockedMode: boolean;
|
|
10
|
-
};
|
|
4
|
+
import { usePartnerContext } from './usePartnerContext';
|
|
11
5
|
|
|
12
6
|
export const useCtaBanner = () => {
|
|
13
|
-
const { companyToken,
|
|
7
|
+
const { companyToken, mockedMode } = usePartnerContext();
|
|
14
8
|
|
|
15
9
|
return useQuery({
|
|
16
|
-
queryKey: ['cta', companyToken,
|
|
17
|
-
queryFn: () => fetchCtaBanner(companyToken,
|
|
10
|
+
queryKey: ['cta', companyToken, mockedMode],
|
|
11
|
+
queryFn: () => fetchCtaBanner(companyToken, mockedMode),
|
|
18
12
|
staleTime: Infinity,
|
|
19
13
|
});
|
|
20
|
-
}
|
|
14
|
+
};
|
|
@@ -1,21 +1,12 @@
|
|
|
1
|
-
import { PartnerCallbackType } from '@wf-financing/embedded-types';
|
|
2
|
-
import { useContext } from "react";
|
|
3
|
-
|
|
4
|
-
import { PartnerContext } from "../utils/partnerContext";
|
|
5
|
-
|
|
6
|
-
type PartnerDataType = {
|
|
7
|
-
companyToken: string;
|
|
8
|
-
isMockedMode: boolean;
|
|
9
|
-
partnerCallback: PartnerCallbackType;
|
|
10
|
-
};
|
|
11
|
-
|
|
12
1
|
import { useMutation } from '@tanstack/react-query';
|
|
2
|
+
|
|
13
3
|
import { startHostedApplication } from '../api/startHostedApplication';
|
|
4
|
+
import { usePartnerContext } from './usePartnerContext';
|
|
14
5
|
|
|
15
6
|
export const useStartHostedApplication = () => {
|
|
16
|
-
const { companyToken,
|
|
7
|
+
const { companyToken, mockedMode, partnerCallback } = usePartnerContext();
|
|
17
8
|
|
|
18
9
|
return useMutation({
|
|
19
|
-
mutationFn: () => startHostedApplication(companyToken,
|
|
10
|
+
mutationFn: () => startHostedApplication(companyToken, partnerCallback, mockedMode),
|
|
20
11
|
});
|
|
21
12
|
};
|
package/src/locales/en.json
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"common.cancel": "Cancel",
|
|
3
|
+
"common.dismiss": "Dismiss",
|
|
3
4
|
"ctaModal.call": "Get funded",
|
|
4
5
|
"ctaModal.title": "We work with Wayflyer to provide you capital",
|
|
5
6
|
"ctaModal.action": "Continue with Wayflyer",
|
|
6
|
-
"ctaModal.consent": "By proceeding, you consent to sharing your
|
|
7
|
+
"ctaModal.consent": "By proceeding, you consent to us sharing your information with Wayflyer so they can assess your eligibility for financing, in accordance with the Wayflyer ",
|
|
8
|
+
"ctaModal.consent.privacy_policy": "Privacy Policy.",
|
|
7
9
|
"ctaModal.step1.title": "Create your account",
|
|
8
10
|
"ctaModal.step1.subtitle": "Tell us about your business and funding needs",
|
|
9
11
|
"ctaModal.step1.time": "2 mins",
|
package/src/main.tsx
CHANGED
|
@@ -1,38 +1,36 @@
|
|
|
1
1
|
import type { Themes } from '@wayflyer/flyui';
|
|
2
|
-
import { PartnerCallbackType } from '@wf-financing/embedded-types';
|
|
2
|
+
import { PartnerCallbackType, MockedModeType } from '@wf-financing/embedded-types';
|
|
3
3
|
import ReactDOM from 'react-dom/client';
|
|
4
4
|
|
|
5
5
|
import { App } from './App';
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
let root: ReactDOM.Root | undefined = undefined;
|
|
8
8
|
|
|
9
9
|
export const mountToTarget = (
|
|
10
10
|
targetId: string,
|
|
11
11
|
partnerDesignId: Themes,
|
|
12
12
|
partnerCallback: PartnerCallbackType,
|
|
13
13
|
companyToken: string,
|
|
14
|
-
|
|
14
|
+
mockedMode?: MockedModeType,
|
|
15
15
|
) => {
|
|
16
16
|
const targetElement = document.getElementById(targetId);
|
|
17
|
+
if (!targetElement) throw new Error(`Target element with id "${targetId}" not found.`);
|
|
17
18
|
|
|
18
|
-
if (!targetElement)
|
|
19
|
-
console.warn(`Target element with id "${targetId}" not found.`);
|
|
20
|
-
return;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
let root = roots.get(targetElement);
|
|
19
|
+
if (!root) root = ReactDOM.createRoot(targetElement);
|
|
24
20
|
|
|
25
|
-
|
|
26
|
-
root
|
|
27
|
-
|
|
21
|
+
function handleCloseWidget() {
|
|
22
|
+
if (!root) throw new Error('Root is not found');
|
|
23
|
+
root.unmount();
|
|
24
|
+
root = undefined;
|
|
28
25
|
}
|
|
29
26
|
|
|
30
27
|
root.render(
|
|
31
28
|
<App
|
|
32
29
|
partnerDesignId={partnerDesignId}
|
|
33
30
|
companyToken={companyToken}
|
|
34
|
-
|
|
31
|
+
mockedMode={mockedMode}
|
|
35
32
|
partnerCallback={partnerCallback}
|
|
36
|
-
|
|
33
|
+
onWidgetClose={handleCloseWidget}
|
|
34
|
+
/>,
|
|
37
35
|
);
|
|
38
36
|
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { IHeadlessWayflyerCtaSdk, MockedModeType } from '@wf-financing/embedded-types';
|
|
2
|
+
|
|
3
|
+
export const initializeHeadlessSdk = (companyToken: string, mockedMode?: MockedModeType): IHeadlessWayflyerCtaSdk => {
|
|
4
|
+
if (!window.WayflyerHeadlessSdk) {
|
|
5
|
+
throw new Error('Failed to load WayflyerHeadlessSdk from the script.');
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const WayflyerHeadlessSdk = window.WayflyerHeadlessSdk;
|
|
9
|
+
|
|
10
|
+
if (mockedMode) {
|
|
11
|
+
mockedMode.sdkScenario;
|
|
12
|
+
const { isMockedMode, sdkScenario } = mockedMode;
|
|
13
|
+
|
|
14
|
+
const wayflyerCtaSdk = new WayflyerHeadlessSdk(companyToken, isMockedMode);
|
|
15
|
+
wayflyerCtaSdk.setSdkScenario(sdkScenario);
|
|
16
|
+
|
|
17
|
+
return wayflyerCtaSdk;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return new WayflyerHeadlessSdk(companyToken);
|
|
21
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { IHeadlessWayflyerCtaSdk, MockedModeType } from '@wf-financing/embedded-types';
|
|
2
|
+
|
|
3
|
+
import { initializeHeadlessSdk } from './initializeHeadlessSdk';
|
|
4
|
+
|
|
5
|
+
export const loadScriptAndInitializeSdk = (
|
|
6
|
+
script: HTMLScriptElement,
|
|
7
|
+
companyToken: string,
|
|
8
|
+
mockedMode?: MockedModeType,
|
|
9
|
+
): Promise<IHeadlessWayflyerCtaSdk> => {
|
|
10
|
+
return new Promise<IHeadlessWayflyerCtaSdk>((resolve, reject) => {
|
|
11
|
+
script.onload = () => {
|
|
12
|
+
try {
|
|
13
|
+
resolve(initializeHeadlessSdk(companyToken, mockedMode));
|
|
14
|
+
} catch (error) {
|
|
15
|
+
reject(error);
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
});
|
|
19
|
+
};
|
|
@@ -1,10 +1,14 @@
|
|
|
1
|
-
import { PartnerCallbackType } from '@wf-financing/embedded-types';
|
|
2
|
-
import { createContext } from
|
|
1
|
+
import { PartnerCallbackType, MockedModeType } from '@wf-financing/embedded-types';
|
|
2
|
+
import { createContext } from 'react';
|
|
3
3
|
|
|
4
|
-
type PartnerContextType = {
|
|
4
|
+
export type PartnerContextType = {
|
|
5
5
|
companyToken: string;
|
|
6
6
|
isMockedMode?: boolean;
|
|
7
|
-
partnerCallback: PartnerCallbackType
|
|
8
|
-
|
|
7
|
+
partnerCallback: PartnerCallbackType;
|
|
8
|
+
mockedMode?: MockedModeType;
|
|
9
|
+
onWidgetClose: () => void;
|
|
10
|
+
};
|
|
9
11
|
|
|
10
|
-
|
|
12
|
+
type PartnerContextWithDefaultType = PartnerContextType | null;
|
|
13
|
+
|
|
14
|
+
export const PartnerContext = createContext<PartnerContextWithDefaultType>(null);
|
package/tsconfig.json
CHANGED
package/vite.config.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/// <reference types="vitest/config" />
|
|
1
2
|
import react from '@vitejs/plugin-react';
|
|
2
3
|
import path from 'path';
|
|
3
4
|
import { defineConfig } from 'vite';
|
|
@@ -22,5 +23,5 @@ export default defineConfig({
|
|
|
22
23
|
rollupOptions: {
|
|
23
24
|
external: [],
|
|
24
25
|
},
|
|
25
|
-
}
|
|
26
|
+
},
|
|
26
27
|
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/// <reference types="@vitest/browser/providers/playwright" />
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { Button, Flex } from '@wayflyer/flyui';
|
|
2
|
-
import { IconX16Line } from '@wayflyer/flyui-icons/16/line';
|
|
3
|
-
|
|
4
|
-
import { ProceedFundingButton } from './ProceedFundingButton';
|
|
5
|
-
|
|
6
|
-
type CtaBannerActionsType = {
|
|
7
|
-
isMobile: boolean;
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
export const CtaBannerActions = ({ isMobile }: CtaBannerActionsType) => (
|
|
11
|
-
<Flex gap="4">
|
|
12
|
-
{!isMobile && (
|
|
13
|
-
<ProceedFundingButton />
|
|
14
|
-
)}
|
|
15
|
-
<Button variant="Tertiary">
|
|
16
|
-
<IconX16Line />
|
|
17
|
-
</Button>
|
|
18
|
-
</Flex>
|
|
19
|
-
);
|