@wf-financing/ui 4.0.0 → 4.2.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 +19 -0
- package/dist/index.es.js +5786 -5749
- package/package.json +4 -4
- package/sdk/index.ts +2 -1
- package/src/App.tsx +3 -0
- package/src/CtaWidget.tsx +11 -2
- package/src/EventProvider.tsx +22 -0
- package/src/components/banner/BulletList.tsx +1 -1
- package/src/components/banner/CtaBanner.snapshot.stories.tsx +3 -0
- package/src/components/modal/ConsentModal.snapshot.stories.tsx +1 -0
- package/src/config/whitelistedPartnerIds.ts +3 -0
- package/src/hooks/index.ts +2 -1
- package/src/hooks/useEventContext.ts +13 -0
- package/src/hooks/useNotificationOnRender.ts +30 -0
- package/src/main.tsx +13 -11
- package/src/utils/buildBannerConfig.ts +4 -0
- package/src/utils/eventContext.ts +8 -0
- package/src/utils/index.ts +1 -0
- package/src/utils/partnerContext.ts +1 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wf-financing/ui",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.2.0",
|
|
4
4
|
"exports": {
|
|
5
5
|
".": {
|
|
6
6
|
"import": "./dist/index.es.js",
|
|
@@ -37,9 +37,9 @@
|
|
|
37
37
|
"react-intl": "^6.2.5",
|
|
38
38
|
"react-markdown": "^10.1.0",
|
|
39
39
|
"styled-components": "^6.1.19",
|
|
40
|
-
"@wf-financing/embedded-types": "1.
|
|
41
|
-
"@wf-financing/ui-assets": "1.0.
|
|
42
|
-
"@wf-financing/logger": "2.
|
|
40
|
+
"@wf-financing/embedded-types": "1.1.0",
|
|
41
|
+
"@wf-financing/ui-assets": "1.0.1",
|
|
42
|
+
"@wf-financing/logger": "2.1.0"
|
|
43
43
|
},
|
|
44
44
|
"publishConfig": {
|
|
45
45
|
"access": "public"
|
package/sdk/index.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { PartnerCallbackType, UiSdkOptions } from '@wf-financing/embedded-types';
|
|
2
2
|
|
|
3
|
-
import { PartnerTheme } from '../src/config';
|
|
3
|
+
import { PartnerTheme, APPLICATION_VERSION } from '../src/config';
|
|
4
4
|
import { mountToTarget } from '../src/main';
|
|
5
5
|
import { getPartnerIdFromToken, getPartnerThemeById } from '../src/utils';
|
|
6
6
|
|
|
7
7
|
export class WayflyerUiSdk {
|
|
8
|
+
readonly sdkVersion = APPLICATION_VERSION;
|
|
8
9
|
private readonly partnerTheme: PartnerTheme;
|
|
9
10
|
|
|
10
11
|
constructor(
|
package/src/App.tsx
CHANGED
|
@@ -17,6 +17,7 @@ type AppPropsType = {
|
|
|
17
17
|
partnerCallback: PartnerCallbackType;
|
|
18
18
|
onWidgetClose: () => void;
|
|
19
19
|
portalContainer: HTMLElement;
|
|
20
|
+
mountToTargetTimestamp: number;
|
|
20
21
|
};
|
|
21
22
|
|
|
22
23
|
const queryClient = new QueryClient();
|
|
@@ -31,6 +32,7 @@ export const App = ({
|
|
|
31
32
|
partnerCallback,
|
|
32
33
|
onWidgetClose,
|
|
33
34
|
portalContainer,
|
|
35
|
+
mountToTargetTimestamp,
|
|
34
36
|
}: AppPropsType) => {
|
|
35
37
|
const [isThemeLoaded, setIsThemeLoaded] = useState(false);
|
|
36
38
|
const [isWidgetDismissed, setIsWidgetDismissed] = useState(false);
|
|
@@ -61,6 +63,7 @@ export const App = ({
|
|
|
61
63
|
portalContainer,
|
|
62
64
|
isWidgetDismissed,
|
|
63
65
|
onWidgetDismiss,
|
|
66
|
+
mountToTargetTimestamp,
|
|
64
67
|
}}
|
|
65
68
|
>
|
|
66
69
|
<FlyUIProvider
|
package/src/CtaWidget.tsx
CHANGED
|
@@ -5,7 +5,14 @@ import { ContinueHostedApplicationResponseType } from '@wf-financing/embedded-ty
|
|
|
5
5
|
import { AnimationWrapper } from './components/banner/AnimationWrapper';
|
|
6
6
|
import { CtaBanner } from './components/banner/CtaBanner';
|
|
7
7
|
import { ConsentModal } from './components/modal/ConsentModal.tsx';
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
useCopy,
|
|
10
|
+
useCtaBanner,
|
|
11
|
+
usePartnerContext,
|
|
12
|
+
useContinueHostedApplication,
|
|
13
|
+
usePreloadImage,
|
|
14
|
+
useNotificationOnRender,
|
|
15
|
+
} from './hooks';
|
|
9
16
|
import { getBannerConfig } from './utils';
|
|
10
17
|
|
|
11
18
|
export const CtaWidget = () => {
|
|
@@ -16,8 +23,9 @@ export const CtaWidget = () => {
|
|
|
16
23
|
const { mutate: continueHostedApplicationMutaion } = useContinueHostedApplication();
|
|
17
24
|
const [isModalOpen, setIsModalOpen] = useState(false);
|
|
18
25
|
usePreloadImage(copy);
|
|
26
|
+
const sendNotification = useNotificationOnRender();
|
|
19
27
|
|
|
20
|
-
const showBanner = cta && copy && !isWidgetDismissed;
|
|
28
|
+
const showBanner = !!cta && !!copy && !isWidgetDismissed;
|
|
21
29
|
|
|
22
30
|
if (!showBanner) return null;
|
|
23
31
|
|
|
@@ -41,6 +49,7 @@ export const CtaWidget = () => {
|
|
|
41
49
|
};
|
|
42
50
|
|
|
43
51
|
const bannerConfig = getBannerConfig(cta, copy, handleIsModalOpen, handleContinueHostedApplication);
|
|
52
|
+
sendNotification(cta, bannerConfig);
|
|
44
53
|
|
|
45
54
|
return (
|
|
46
55
|
<AnimatePresence mode="wait" onExitComplete={handleExitComplete}>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import { Logger } from '@wf-financing/logger';
|
|
3
|
+
|
|
4
|
+
import { APPLICATION_VERSION } from './config';
|
|
5
|
+
import { EventContext, type EventAttributes } from './utils';
|
|
6
|
+
|
|
7
|
+
type EventProviderProps = {
|
|
8
|
+
children: ReactNode;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export const EventProvider = ({ children }: EventProviderProps) => {
|
|
12
|
+
const logEvent = (name: string, attributes: Partial<EventAttributes> = {}) => {
|
|
13
|
+
const payload = {
|
|
14
|
+
...attributes,
|
|
15
|
+
sdk_version: APPLICATION_VERSION,
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
Logger.logEvent(name, payload);
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
return <EventContext.Provider value={{ logEvent }}>{children}</EventContext.Provider>;
|
|
22
|
+
};
|
|
@@ -15,7 +15,7 @@ export const BulletList = ({ isOnDarkTheme, bulletPoints }: BulletListProps) =>
|
|
|
15
15
|
<Flex gap="4">
|
|
16
16
|
{bulletPoints.map((bulletPoint: string) => (
|
|
17
17
|
<Flex key={bulletPoint} gap="1" align="center">
|
|
18
|
-
<Icon color={isOnDarkTheme ? '
|
|
18
|
+
<Icon color={isOnDarkTheme ? 'onDark' : 'default'}>
|
|
19
19
|
<IconCheck12Line />
|
|
20
20
|
</Icon>
|
|
21
21
|
<Text
|
|
@@ -11,6 +11,8 @@ const bannerConfig = {
|
|
|
11
11
|
bulletPoints: ['Funds in 24 hours', 'No personal guarantees', '$5B+ in funding delivered'],
|
|
12
12
|
buttonText: 'Get funding',
|
|
13
13
|
buttonAction: () => {},
|
|
14
|
+
version: '1.0.0',
|
|
15
|
+
type: 'genericOffer',
|
|
14
16
|
};
|
|
15
17
|
|
|
16
18
|
const defaultArgs = {
|
|
@@ -21,6 +23,7 @@ const defaultArgs = {
|
|
|
21
23
|
isWidgetDismissed: false,
|
|
22
24
|
skipAnimation: false,
|
|
23
25
|
bannerState: 'test',
|
|
26
|
+
mountToTargetTimestamp: 10,
|
|
24
27
|
bannerConfig,
|
|
25
28
|
portalContainer,
|
|
26
29
|
};
|
|
@@ -22,4 +22,7 @@ export const WHITELISTED_PARTNER_IDS = {
|
|
|
22
22
|
|
|
23
23
|
'0e553c21-13a7-461f-bf4d-5a92fad4a403': 'reveni',
|
|
24
24
|
'bb9f8122-66ff-41bd-a8c0-52a9af0b3b4f': 'reveni',
|
|
25
|
+
|
|
26
|
+
'9f21c2f7-fd67-4557-82df-8e2f4783c66a': 'linkMyBooks',
|
|
27
|
+
'01aba3d9-21d6-4a40-b6d2-a9f0c8628b0f': 'linkMyBooks',
|
|
25
28
|
} as const satisfies Record<string, PartnerTheme>;
|
package/src/hooks/index.ts
CHANGED
|
@@ -6,4 +6,5 @@ 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
|
|
9
|
+
export { useCopy } from './useCopy';
|
|
10
|
+
export { useNotificationOnRender } from './useNotificationOnRender';
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { useContext } from 'react';
|
|
2
|
+
|
|
3
|
+
import { EventContext } from '../utils';
|
|
4
|
+
|
|
5
|
+
export const useEventContext = () => {
|
|
6
|
+
const eventContext = useContext(EventContext);
|
|
7
|
+
|
|
8
|
+
if (!eventContext) {
|
|
9
|
+
throw new Error('useEventContext must be used within an EventProvider');
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
return eventContext;
|
|
13
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { CtaResponseType, CtaStateType } from '@wf-financing/embedded-types';
|
|
2
|
+
|
|
3
|
+
import { useEventContext } from './useEventContext';
|
|
4
|
+
import { usePartnerContext } from './usePartnerContext';
|
|
5
|
+
import { type BannerConfig } from '../utils';
|
|
6
|
+
|
|
7
|
+
export const useNotificationOnRender = () => {
|
|
8
|
+
const { logEvent } = useEventContext();
|
|
9
|
+
const { mountToTargetTimestamp } = usePartnerContext();
|
|
10
|
+
|
|
11
|
+
return (cta: CtaResponseType, bannerConfig: BannerConfig) => {
|
|
12
|
+
if (!cta || !bannerConfig) return;
|
|
13
|
+
|
|
14
|
+
const bannerRenderingLatency = Date.now() - mountToTargetTimestamp;
|
|
15
|
+
|
|
16
|
+
const { state, data } = cta;
|
|
17
|
+
const attrs: Record<string, string | number> = {
|
|
18
|
+
cta_state: state,
|
|
19
|
+
banner_copy_version: bannerConfig.version,
|
|
20
|
+
banner_rendering_latency: bannerRenderingLatency,
|
|
21
|
+
copy_type: bannerConfig.type,
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
if (state === CtaStateType.CONTINUE_APPLICATION) {
|
|
25
|
+
attrs.required_action = data.config.required_action;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
logEvent('cta_mounted_to_target', attrs);
|
|
29
|
+
};
|
|
30
|
+
};
|
package/src/main.tsx
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { PartnerCallbackType, UiSdkOptions } from '@wf-financing/embedded-types';
|
|
2
|
-
import { Logger } from '@wf-financing/logger';
|
|
3
2
|
import ReactDOM from 'react-dom/client';
|
|
4
3
|
import { StyleSheetManager } from 'styled-components';
|
|
5
4
|
|
|
6
5
|
import { MotionGlobalConfig } from 'framer-motion';
|
|
7
6
|
import { App } from './App';
|
|
7
|
+
import { EventProvider } from './EventProvider';
|
|
8
8
|
import { PartnerTheme } from './config';
|
|
9
9
|
import { applyStyles, createRoots } from './utils';
|
|
10
10
|
|
|
@@ -18,6 +18,7 @@ export const mountToTarget = async (
|
|
|
18
18
|
companyToken: string,
|
|
19
19
|
options?: UiSdkOptions,
|
|
20
20
|
): Promise<void> => {
|
|
21
|
+
const mountToTargetTimestamp = Date.now();
|
|
21
22
|
const isNewTargetId = targetId !== savedTargetId;
|
|
22
23
|
|
|
23
24
|
if (isNewTargetId) {
|
|
@@ -53,16 +54,17 @@ export const mountToTarget = async (
|
|
|
53
54
|
|
|
54
55
|
root.render(
|
|
55
56
|
<StyleSheetManager target={styledComponentsStyleRoot}>
|
|
56
|
-
<
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
57
|
+
<EventProvider>
|
|
58
|
+
<App
|
|
59
|
+
theme={partnerTheme}
|
|
60
|
+
companyToken={companyToken}
|
|
61
|
+
options={options}
|
|
62
|
+
partnerCallback={partnerCallback}
|
|
63
|
+
onWidgetClose={handleCloseWidget}
|
|
64
|
+
portalContainer={portalRoot}
|
|
65
|
+
mountToTargetTimestamp={mountToTargetTimestamp}
|
|
66
|
+
/>
|
|
67
|
+
</EventProvider>
|
|
64
68
|
</StyleSheetManager>,
|
|
65
69
|
);
|
|
66
|
-
|
|
67
|
-
Logger.logEvent('cta_mounted_to_target');
|
|
68
70
|
};
|
|
@@ -4,6 +4,8 @@ type CopySection = {
|
|
|
4
4
|
mainText: string;
|
|
5
5
|
buttonText: string;
|
|
6
6
|
bulletPoints?: string[];
|
|
7
|
+
version: string;
|
|
8
|
+
type: string;
|
|
7
9
|
};
|
|
8
10
|
|
|
9
11
|
export type BannerConfig = CopySection & {
|
|
@@ -23,4 +25,6 @@ export const buildBannerConfig: BuildBannerConfig = (copySection, buttonAction,
|
|
|
23
25
|
bulletPoints: copySection.bulletPoints,
|
|
24
26
|
buttonText: copySection.buttonText,
|
|
25
27
|
buttonAction: buttonAction,
|
|
28
|
+
version: copySection.version,
|
|
29
|
+
type: copySection.type,
|
|
26
30
|
});
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { createContext } from 'react';
|
|
2
|
+
|
|
3
|
+
export type EventAttributes = Record<string, string | number | boolean | null | undefined>;
|
|
4
|
+
export type EventContextValue = {
|
|
5
|
+
logEvent: (name: string, extraAttributes?: Partial<EventAttributes>) => void;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export const EventContext = createContext<EventContextValue | null>(null);
|
package/src/utils/index.ts
CHANGED
|
@@ -10,3 +10,4 @@ export { getModalItems } from './getModalItems';
|
|
|
10
10
|
export { injectUrlInTemplate } from './injectUrlInTemplate';
|
|
11
11
|
export { buildBannerConfig, type BannerConfig } from './buildBannerConfig';
|
|
12
12
|
export { getBannerConfig } from './getBannerConfig';
|
|
13
|
+
export { EventContext, type EventContextValue, type EventAttributes } from './eventContext';
|