@moneylion/react-native-offer-carousel 1.3.1 → 1.4.1

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 (79) hide show
  1. package/lib/commonjs/capabilities/core/src/system/cnfContext/schemas/Brand.js +44 -45
  2. package/lib/commonjs/capabilities/core/src/system/cnfContext/schemas/Brand.js.map +1 -1
  3. package/lib/commonjs/components/Common/BaseOfferCard/index.js +17 -6
  4. package/lib/commonjs/components/Common/BaseOfferCard/index.js.map +1 -1
  5. package/lib/commonjs/components/Divider/index.js +0 -2
  6. package/lib/commonjs/components/Divider/index.js.map +1 -1
  7. package/lib/commonjs/components/DynamicOffers/Render/DynamicOffersRender.js +3 -2
  8. package/lib/commonjs/components/DynamicOffers/Render/DynamicOffersRender.js.map +1 -1
  9. package/lib/commonjs/components/ErrorBoundary/index.js +34 -0
  10. package/lib/commonjs/components/ErrorBoundary/index.js.map +1 -0
  11. package/lib/commonjs/components/Layouts/HeadlineWithDescriptionCard/index.js.map +1 -1
  12. package/lib/commonjs/components/Modal/AllOffersModal.js +14 -7
  13. package/lib/commonjs/components/Modal/AllOffersModal.js.map +1 -1
  14. package/lib/commonjs/components/Modal/OfferDetailsModal.js +19 -10
  15. package/lib/commonjs/components/Modal/OfferDetailsModal.js.map +1 -1
  16. package/lib/commonjs/components/MoneyLionOfferCarousel.js +23 -7
  17. package/lib/commonjs/components/MoneyLionOfferCarousel.js.map +1 -1
  18. package/lib/commonjs/config/mocks/cnfContext.js +151 -44
  19. package/lib/commonjs/config/mocks/cnfContext.js.map +1 -1
  20. package/lib/commonjs/context/ThemeProvider.js +8 -2
  21. package/lib/commonjs/context/ThemeProvider.js.map +1 -1
  22. package/lib/commonjs/utils/getThemeColors.js +24 -0
  23. package/lib/commonjs/utils/getThemeColors.js.map +1 -0
  24. package/lib/module/capabilities/core/src/system/cnfContext/schemas/Brand.js +44 -45
  25. package/lib/module/capabilities/core/src/system/cnfContext/schemas/Brand.js.map +1 -1
  26. package/lib/module/components/Common/BaseOfferCard/index.js +17 -6
  27. package/lib/module/components/Common/BaseOfferCard/index.js.map +1 -1
  28. package/lib/module/components/Divider/index.js +0 -2
  29. package/lib/module/components/Divider/index.js.map +1 -1
  30. package/lib/module/components/DynamicOffers/Render/DynamicOffersRender.js +3 -2
  31. package/lib/module/components/DynamicOffers/Render/DynamicOffersRender.js.map +1 -1
  32. package/lib/module/components/ErrorBoundary/index.js +28 -0
  33. package/lib/module/components/ErrorBoundary/index.js.map +1 -0
  34. package/lib/module/components/Layouts/HeadlineWithDescriptionCard/index.js.map +1 -1
  35. package/lib/module/components/Modal/AllOffersModal.js +14 -7
  36. package/lib/module/components/Modal/AllOffersModal.js.map +1 -1
  37. package/lib/module/components/Modal/OfferDetailsModal.js +19 -10
  38. package/lib/module/components/Modal/OfferDetailsModal.js.map +1 -1
  39. package/lib/module/components/MoneyLionOfferCarousel.js +23 -8
  40. package/lib/module/components/MoneyLionOfferCarousel.js.map +1 -1
  41. package/lib/module/config/mocks/cnfContext.js +151 -44
  42. package/lib/module/config/mocks/cnfContext.js.map +1 -1
  43. package/lib/module/context/ThemeProvider.js +8 -2
  44. package/lib/module/context/ThemeProvider.js.map +1 -1
  45. package/lib/module/utils/getThemeColors.js +17 -0
  46. package/lib/module/utils/getThemeColors.js.map +1 -0
  47. package/lib/typescript/src/capabilities/core/src/system/cnfContext/schemas/Brand.d.ts +312 -89
  48. package/lib/typescript/src/capabilities/core/src/system/cnfContext/schemas/Brand.d.ts.map +1 -1
  49. package/lib/typescript/src/capabilities/ui/elements/src/components/MarkdownText/components.d.ts +2 -2
  50. package/lib/typescript/src/capabilities/ui/elements/src/components/MarkdownText/components.d.ts.map +1 -1
  51. package/lib/typescript/src/components/Common/BaseOfferCard/index.d.ts.map +1 -1
  52. package/lib/typescript/src/components/Divider/index.d.ts.map +1 -1
  53. package/lib/typescript/src/components/DynamicOffers/Render/DynamicOffersRender.d.ts.map +1 -1
  54. package/lib/typescript/src/components/ErrorBoundary/index.d.ts +20 -0
  55. package/lib/typescript/src/components/ErrorBoundary/index.d.ts.map +1 -0
  56. package/lib/typescript/src/components/Layouts/HeadlineWithDescriptionCard/index.d.ts.map +1 -1
  57. package/lib/typescript/src/components/Modal/AllOffersModal.d.ts.map +1 -1
  58. package/lib/typescript/src/components/Modal/OfferDetailsModal.d.ts.map +1 -1
  59. package/lib/typescript/src/components/MoneyLionOfferCarousel.d.ts +8 -5
  60. package/lib/typescript/src/components/MoneyLionOfferCarousel.d.ts.map +1 -1
  61. package/lib/typescript/src/config/mocks/cnfContext.d.ts.map +1 -1
  62. package/lib/typescript/src/context/ThemeProvider.d.ts +3 -0
  63. package/lib/typescript/src/context/ThemeProvider.d.ts.map +1 -1
  64. package/lib/typescript/src/utils/getThemeColors.d.ts +8 -0
  65. package/lib/typescript/src/utils/getThemeColors.d.ts.map +1 -0
  66. package/package.json +1 -1
  67. package/src/capabilities/core/src/system/cnfContext/schemas/Brand.ts +51 -46
  68. package/src/capabilities/ui/elements/src/components/MarkdownText/components.tsx +1 -1
  69. package/src/components/Common/BaseOfferCard/index.tsx +17 -8
  70. package/src/components/Divider/index.tsx +0 -1
  71. package/src/components/DynamicOffers/Render/DynamicOffersRender.tsx +7 -3
  72. package/src/components/ErrorBoundary/index.tsx +40 -0
  73. package/src/components/Layouts/HeadlineWithDescriptionCard/index.tsx +1 -0
  74. package/src/components/Modal/AllOffersModal.tsx +19 -5
  75. package/src/components/Modal/OfferDetailsModal.tsx +20 -9
  76. package/src/components/MoneyLionOfferCarousel.tsx +49 -13
  77. package/src/config/mocks/cnfContext.ts +40 -44
  78. package/src/context/ThemeProvider.tsx +12 -1
  79. package/src/utils/getThemeColors.ts +29 -0
@@ -1,50 +1,55 @@
1
1
  import { Schema } from "effect";
2
2
 
3
- export type ThemeColors = Schema.Schema.Type<typeof ThemeColors>;
4
- const ThemeColors = Schema.Struct({
5
- backgroundPrimary: Schema.String,
6
- backgroundPrimaryFaded: Schema.String,
7
- backgroundPrimaryHighlighted: Schema.String,
8
- backgroundCritical: Schema.String,
9
- backgroundCriticalFaded: Schema.String,
10
- backgroundCriticalHighlighted: Schema.String,
11
- backgroundWarning: Schema.String,
12
- backgroundWarningFaded: Schema.String,
13
- backgroundWarningHighlighted: Schema.String,
14
- backgroundPositive: Schema.String,
15
- backgroundPositiveFaded: Schema.String,
16
- backgroundPositiveHighlighted: Schema.String,
17
- backgroundNeutral: Schema.String,
18
- backgroundNeutralFaded: Schema.String,
19
- backgroundNeutralHighlighted: Schema.String,
20
- backgroundDisabled: Schema.String,
21
- backgroundDisabledFaded: Schema.String,
22
- backgroundElevationBase: Schema.String,
23
- backgroundElevationRaised: Schema.String,
24
- backgroundElevationOverlay: Schema.String,
25
- backgroundPage: Schema.String,
26
- backgroundPageFaded: Schema.String,
27
- borderPrimary: Schema.String,
28
- borderPrimaryFaded: Schema.String,
29
- borderCritical: Schema.String,
30
- borderCriticalFaded: Schema.String,
31
- borderWarning: Schema.String,
32
- borderWarningFaded: Schema.String,
33
- borderPositive: Schema.String,
34
- borderPositiveFaded: Schema.String,
35
- borderNeutral: Schema.String,
36
- borderNeutralFaded: Schema.String,
37
- borderDisabled: Schema.String,
38
- foregroundPrimary: Schema.String,
39
- foregroundCritical: Schema.String,
40
- foregroundWarning: Schema.String,
41
- foregroundPositive: Schema.String,
42
- foregroundNeutral: Schema.String,
43
- foregroundNeutralFaded: Schema.String,
44
- foregroundDisabled: Schema.String,
45
- brand: Schema.String,
46
- white: Schema.String,
47
- black: Schema.String,
3
+ export type ReshapedThemeColorObject = Schema.Schema.Type<
4
+ typeof ReshapedThemeColorObject
5
+ >;
6
+ const ReshapedThemeColorObject = Schema.Struct({
7
+ hex: Schema.String,
8
+ hexDark: Schema.optional(Schema.String),
9
+ });
10
+
11
+ export type ReshapedThemeColors = Schema.Schema.Type<
12
+ typeof ReshapedThemeColors
13
+ >;
14
+ const ReshapedThemeColors = Schema.Struct({
15
+ backgroundCritical: ReshapedThemeColorObject,
16
+ backgroundCriticalFaded: ReshapedThemeColorObject,
17
+ backgroundDisabled: ReshapedThemeColorObject,
18
+ backgroundDisabledFaded: ReshapedThemeColorObject,
19
+ backgroundElevationBase: ReshapedThemeColorObject,
20
+ backgroundElevationOverlay: ReshapedThemeColorObject,
21
+ backgroundElevationRaised: ReshapedThemeColorObject,
22
+ backgroundNeutral: ReshapedThemeColorObject,
23
+ backgroundNeutralFaded: ReshapedThemeColorObject,
24
+ backgroundPage: ReshapedThemeColorObject,
25
+ backgroundPageFaded: ReshapedThemeColorObject,
26
+ backgroundPositive: ReshapedThemeColorObject,
27
+ backgroundPositiveFaded: ReshapedThemeColorObject,
28
+ backgroundPrimary: ReshapedThemeColorObject,
29
+ backgroundPrimaryFaded: ReshapedThemeColorObject,
30
+ backgroundWarning: ReshapedThemeColorObject,
31
+ backgroundWarningFaded: ReshapedThemeColorObject,
32
+ black: ReshapedThemeColorObject,
33
+ borderCritical: ReshapedThemeColorObject,
34
+ borderCriticalFaded: ReshapedThemeColorObject,
35
+ borderDisabled: ReshapedThemeColorObject,
36
+ borderNeutral: ReshapedThemeColorObject,
37
+ borderNeutralFaded: ReshapedThemeColorObject,
38
+ borderPositive: ReshapedThemeColorObject,
39
+ borderPositiveFaded: ReshapedThemeColorObject,
40
+ borderPrimary: ReshapedThemeColorObject,
41
+ borderPrimaryFaded: ReshapedThemeColorObject,
42
+ borderWarning: ReshapedThemeColorObject,
43
+ borderWarningFaded: ReshapedThemeColorObject,
44
+ brand: ReshapedThemeColorObject,
45
+ foregroundCritical: ReshapedThemeColorObject,
46
+ foregroundDisabled: ReshapedThemeColorObject,
47
+ foregroundNeutral: ReshapedThemeColorObject,
48
+ foregroundNeutralFaded: ReshapedThemeColorObject,
49
+ foregroundPositive: ReshapedThemeColorObject,
50
+ foregroundPrimary: ReshapedThemeColorObject,
51
+ foregroundWarning: ReshapedThemeColorObject,
52
+ white: ReshapedThemeColorObject,
48
53
  });
49
54
 
50
55
  export type Links = Schema.Schema.Type<typeof Links>;
@@ -120,7 +125,7 @@ const BrandFields = Schema.Struct({
120
125
  displayName: Schema.String,
121
126
  isLicensed: Schema.optional(Schema.Boolean),
122
127
  hideLicensedLogo: Schema.optional(Schema.Boolean),
123
- themeColors: ThemeColors,
128
+ reshapedThemeColors: ReshapedThemeColors,
124
129
  links: Schema.optional(Links),
125
130
  logos: Schema.optional(Logos),
126
131
  font: Schema.optional(Font),
@@ -10,7 +10,7 @@ import Text, {
10
10
  type TextWeight,
11
11
  type Variant,
12
12
  } from "../../../../../../components/Text";
13
- import type { ThemeColors } from "../../../../../core/src";
13
+ import type { ThemeColors } from "../../../../../../context/ThemeProvider";
14
14
 
15
15
  const BoldText = ({ children }: { children: React.ReactNode }) => {
16
16
  const processChildren = (_children: React.ReactNode) => {
@@ -11,6 +11,7 @@ import { Dimensions, StyleSheet } from "react-native";
11
11
  import { ThumborImage } from "../../../capabilities/ui/elements/src";
12
12
  import { arrayToMarkdownList } from "../../../capabilities/offer-catalog/src";
13
13
  import { MarkdownText } from "../../../capabilities/ui/elements/src/components/MarkdownText";
14
+ import { useTheme } from "../../../context/ThemeProvider";
14
15
 
15
16
  const CardWidth = 282;
16
17
 
@@ -24,7 +25,7 @@ const BaseOfferCard = ({
24
25
 
25
26
  return (
26
27
  <View
27
- borderColor={showCardBorder ? "borderNeutralFaded" : undefined}
28
+ borderColor={showCardBorder ? "borderNeutral" : undefined}
28
29
  direction={"column"}
29
30
  backgroundColor={"backgroundElevationBase"}
30
31
  width={fullCardWidth ? screenWidth - 32 : CardWidth} // 32 = left(16) + right(16) margin of the card
@@ -118,13 +119,18 @@ const PartnerImage = (
118
119
  );
119
120
  };
120
121
 
121
- const TopContainer = ({ children, ...viewProps }: ViewProps) => (
122
- <View {...viewProps} gap={3} direction={"column"}>
123
- {children}
122
+ const TopContainer = ({ children, ...viewProps }: ViewProps) => {
123
+ const themeContext = useTheme();
124
+ const theme = themeContext?.theme || {};
124
125
 
125
- <Divider />
126
- </View>
127
- );
126
+ return (
127
+ <View {...viewProps} gap={3} direction={"column"}>
128
+ {children}
129
+
130
+ <Divider color={theme.borderNeutral} />
131
+ </View>
132
+ );
133
+ };
128
134
 
129
135
  const TopBar = ({ children, ...viewProps }: ViewProps) => (
130
136
  <View
@@ -211,6 +217,9 @@ const DescriptionHandler = ({
211
217
  contentDescription?: string;
212
218
  hasDivider?: boolean;
213
219
  }) => {
220
+ const themeContext = useTheme();
221
+ const theme = themeContext?.theme || {};
222
+
214
223
  const renderContentDescription = () => {
215
224
  if (descriptionPoints.length > 0) {
216
225
  return (
@@ -236,7 +245,7 @@ const DescriptionHandler = ({
236
245
 
237
246
  return (
238
247
  <View gap={3} direction={"column"}>
239
- {hasDivider && <Divider />}
248
+ {hasDivider && <Divider color={theme.borderNeutral} />}
240
249
  {renderContentDescription()}
241
250
  </View>
242
251
  );
@@ -27,7 +27,6 @@ const styles = StyleSheet.create({
27
27
  divider: {
28
28
  height: 1,
29
29
  width: "100%",
30
- backgroundColor: "#E0E0E0", // Default neutral border color
31
30
  marginVertical: 12,
32
31
  },
33
32
  });
@@ -291,13 +291,13 @@ export const DynamicOffersRender = ({
291
291
  isHorizontalScroll,
292
292
  });
293
293
  }, [
294
+ offers,
295
+ isHorizontalScroll,
294
296
  displayLayout,
295
297
  productTypeBuilder,
296
- offers,
297
298
  showProductTypeLabel,
298
299
  fallbackTemplate,
299
300
  showCardBorder,
300
- isHorizontalScroll,
301
301
  ]);
302
302
 
303
303
  // Wrapped offer components with layout measurement
@@ -369,7 +369,11 @@ export const DynamicOffersRender = ({
369
369
  {showHeaderText && (
370
370
  <View style={styles.headerTextContainer}>
371
371
  {showTitle && (
372
- <Text variant="featured-3" weight="bold">
372
+ <Text
373
+ variant="featured-3"
374
+ weight="bold"
375
+ color="foregroundNeutral"
376
+ >
373
377
  {title}
374
378
  </Text>
375
379
  )}
@@ -0,0 +1,40 @@
1
+ import React, { Component } from "react";
2
+ import type { CustomError } from "../MoneyLionOfferCarousel";
3
+
4
+ interface Props {
5
+ children: React.ReactNode;
6
+ fallbackUI?: React.ReactNode;
7
+ onError: (error: CustomError) => void;
8
+ }
9
+
10
+ interface State {
11
+ hasError: boolean;
12
+ }
13
+
14
+ class ErrorBoundary extends Component<Props, State> {
15
+ constructor(props: Props) {
16
+ super(props);
17
+ this.state = { hasError: false };
18
+ }
19
+
20
+ static getDerivedStateFromError(_error: Error) {
21
+ return { hasError: true };
22
+ }
23
+
24
+ componentDidCatch(error: Error) {
25
+ this.props.onError({
26
+ message: error.message,
27
+ timestamp: new Date().toISOString(),
28
+ });
29
+ }
30
+
31
+ render() {
32
+ if (this.state.hasError) {
33
+ return this.props.fallbackUI ?? null;
34
+ }
35
+
36
+ return this.props.children;
37
+ }
38
+ }
39
+
40
+ export default ErrorBoundary;
@@ -16,6 +16,7 @@ type HeadlineWithDescriptionCardProps = {
16
16
  fullCardWidth?: boolean;
17
17
  isHorizontalScroll?: boolean;
18
18
  };
19
+
19
20
  export const HeadlineWithDescriptionCard = ({
20
21
  offer,
21
22
  productTypeBuilder,
@@ -14,6 +14,7 @@ import {
14
14
  import Text from "../Text";
15
15
  import { DynamicOffersContainer } from "../DynamicOffers/DynamicOffersContainer";
16
16
  import type { DynamicOfferProps } from "../DynamicOffers/DynamicOffers";
17
+ import { useTheme } from "../../context/ThemeProvider";
17
18
 
18
19
  type AllOffersModalProps = {
19
20
  visible: boolean;
@@ -50,6 +51,8 @@ export const AllOffersModal = ({
50
51
  onClose,
51
52
  config,
52
53
  }: AllOffersModalProps) => {
54
+ const { theme } = useTheme();
55
+
53
56
  const { brand, title } = config;
54
57
  const footerLinks = brand.links;
55
58
 
@@ -100,16 +103,28 @@ export const AllOffersModal = ({
100
103
  visible={visible}
101
104
  onRequestClose={onClose}
102
105
  >
103
- <SafeAreaView style={styles.modalContainer}>
106
+ <SafeAreaView
107
+ style={[
108
+ styles.modalContainer,
109
+ { backgroundColor: theme.backgroundPageFaded },
110
+ ]}
111
+ >
104
112
  <View style={styles.modalHeader}>
105
113
  <TouchableOpacity
106
114
  onPress={onClose}
107
115
  style={styles.closeXButton}
108
116
  hitSlop={{ top: 15, right: 15, bottom: 15, left: 15 }}
109
117
  >
110
- <Text style={styles.closeXText}>✕</Text>
118
+ <Text style={styles.closeXText} color={"foregroundNeutral"}>
119
+
120
+ </Text>
111
121
  </TouchableOpacity>
112
- <Text variant="title-3" weight="bold" style={styles.headerTitle}>
122
+ <Text
123
+ variant="title-3"
124
+ weight="bold"
125
+ color={"foregroundNeutral"}
126
+ style={styles.headerTitle}
127
+ >
113
128
  {title}
114
129
  </Text>
115
130
  </View>
@@ -157,7 +172,6 @@ export const AllOffersModal = ({
157
172
  const styles = StyleSheet.create({
158
173
  modalContainer: {
159
174
  flex: 1,
160
- backgroundColor: "#EEEEEE",
161
175
  },
162
176
  modalHeader: {
163
177
  flexDirection: "row",
@@ -173,11 +187,11 @@ const styles = StyleSheet.create({
173
187
  },
174
188
  closeXText: {
175
189
  fontSize: 20,
176
- color: "#000000",
177
190
  },
178
191
  headerTitle: {
179
192
  textAlign: "center",
180
193
  alignSelf: "center",
194
+ paddingHorizontal: 36, // To ensure title doesn't overlap with close button
181
195
  },
182
196
  contentWrapper: {
183
197
  flex: 1,
@@ -15,6 +15,7 @@ import { Disclaimer } from "./Disclaimer";
15
15
  import { CallToAction } from "../Common/DynamicOfferCard/CallToAction";
16
16
  import Divider from "../Divider";
17
17
  import type { BaseOffer } from "../../capabilities/offer-catalog/src";
18
+ import { useTheme } from "../../context/ThemeProvider";
18
19
 
19
20
  type OfferDetailsModalProps = {
20
21
  visible: boolean;
@@ -31,35 +32,48 @@ export const OfferDetailsModal = ({
31
32
  onClose,
32
33
  offerIndex,
33
34
  }: OfferDetailsModalProps) => {
35
+ const { theme, isDarkTheme } = useTheme();
36
+
34
37
  const showDescriptionPoints = Boolean(offer?.descriptionPoints?.length);
35
38
 
36
39
  const showDisclaimer = Boolean(offer?.legalLanguage);
37
40
 
38
41
  const showDivider = showDescriptionPoints && showDisclaimer;
39
42
 
43
+ const backgroundColor = theme.backgroundElevationOverlay;
44
+
40
45
  return (
41
46
  <Modal
42
47
  animationType="slide"
43
- transparent={false}
48
+ transparent={true}
44
49
  visible={visible}
45
50
  onRequestClose={onClose}
46
51
  statusBarTranslucent={true}
47
52
  >
48
- <SafeAreaView style={styles.modalContainer}>
53
+ <SafeAreaView style={[styles.modalContainer, { backgroundColor }]}>
49
54
  {visible && (
50
55
  <StatusBar
51
- backgroundColor={"#ffffff"}
52
- barStyle={"dark-content"}
56
+ backgroundColor={backgroundColor}
57
+ barStyle={isDarkTheme ? "light-content" : "dark-content"}
53
58
  translucent={false}
54
59
  />
55
60
  )}
56
- <View style={styles.modalHeader}>
61
+ <View
62
+ style={[
63
+ styles.modalHeader,
64
+ { borderBottomColor: theme.borderNeutral },
65
+ ]}
66
+ >
57
67
  <TouchableOpacity
58
68
  onPress={onClose}
59
69
  style={styles.closeXButton}
60
70
  hitSlop={{ top: 15, right: 15, bottom: 15, left: 15 }}
61
71
  >
62
- <Text style={styles.closeXText}>✕</Text>
72
+ <Text
73
+ style={[styles.closeXText, { color: theme.foregroundNeutral }]}
74
+ >
75
+
76
+ </Text>
63
77
  </TouchableOpacity>
64
78
  </View>
65
79
 
@@ -91,7 +105,6 @@ export const OfferDetailsModal = ({
91
105
  const styles = StyleSheet.create({
92
106
  modalContainer: {
93
107
  flex: 1,
94
- backgroundColor: "#ffffff",
95
108
  marginTop: Platform.OS === "android" ? StatusBar.currentHeight : 0,
96
109
  },
97
110
  modalHeader: {
@@ -100,7 +113,6 @@ const styles = StyleSheet.create({
100
113
  paddingHorizontal: 16,
101
114
  paddingBottom: 32,
102
115
  borderBottomWidth: 1,
103
- borderBottomColor: "#e0e0e0",
104
116
  position: "relative",
105
117
  },
106
118
  closeXButton: {
@@ -111,7 +123,6 @@ const styles = StyleSheet.create({
111
123
  },
112
124
  closeXText: {
113
125
  fontSize: 20,
114
- color: "#000000",
115
126
  },
116
127
  modalContent: {
117
128
  flex: 1,
@@ -1,4 +1,4 @@
1
- import React, { useEffect, useState } from "react";
1
+ import React, { useEffect, useMemo, useState } from "react";
2
2
  import { localCnfContext } from "../config/mocks/cnfContext";
3
3
  import { Text } from "react-native";
4
4
  import { getPageData } from "../pageData";
@@ -16,6 +16,15 @@ import {
16
16
  import { getConfigApiBaseUrl } from "../apiEnvironment";
17
17
  import { ConfigurationProvider } from "../context/ConfigurationProvider";
18
18
  import type { CnfContext } from "../capabilities/core/src/system/cnfContext/CnfContext";
19
+ import { getThemeColors } from "../utils/getThemeColors";
20
+ import type { ReshapedThemeColors } from "../capabilities/core/src";
21
+ import ErrorBoundary from "./ErrorBoundary";
22
+
23
+ export type CustomError = {
24
+ code?: number;
25
+ message: string;
26
+ timestamp: string;
27
+ };
19
28
 
20
29
  export type MoneyLionOfferCarouselProps = {
21
30
  channel: string;
@@ -34,11 +43,9 @@ export type MoneyLionOfferCarouselProps = {
34
43
  showDescriptionPoints?: boolean;
35
44
  title?: string;
36
45
  subtitle?: string;
37
- onError?: (error: {
38
- code?: number;
39
- message: string;
40
- timestamp: string;
41
- }) => void;
46
+ isDarkTheme?: boolean;
47
+ fallbackUI?: React.ReactNode;
48
+ onError?: (error: CustomError) => void;
42
49
  onLoad?: (numOffers: number) => void;
43
50
  };
44
51
 
@@ -91,8 +98,8 @@ const getConfiguration = async ({
91
98
  }
92
99
  };
93
100
 
94
- export const MoneyLionOfferCarousel = (
95
- props: MoneyLionOfferCarouselProps &
101
+ const InternalMoneyLionOfferCarousel = (
102
+ props: Omit<MoneyLionOfferCarouselProps, "fallbackUI"> &
96
103
  Omit<EventHandlerContextType, "rateTableUuid" | "leadUuid">
97
104
  ) => {
98
105
  const {
@@ -106,6 +113,7 @@ export const MoneyLionOfferCarousel = (
106
113
  onLoad,
107
114
  title,
108
115
  subtitle,
116
+ isDarkTheme = false,
109
117
  } = props;
110
118
 
111
119
  const {
@@ -227,6 +235,17 @@ export const MoneyLionOfferCarousel = (
227
235
  onLoad,
228
236
  ]);
229
237
 
238
+ const themeColors = useMemo(
239
+ () =>
240
+ context
241
+ ? getThemeColors(
242
+ context.brand.reshapedThemeColors || ({} as ReshapedThemeColors),
243
+ isDarkTheme
244
+ )
245
+ : getThemeColors({} as ReshapedThemeColors, isDarkTheme),
246
+ [context, isDarkTheme]
247
+ );
248
+
230
249
  if (isLoading) {
231
250
  return <DynamicOfferSkeleton displayLayout={"fixed"} />;
232
251
  }
@@ -264,12 +283,12 @@ export const MoneyLionOfferCarousel = (
264
283
  brand: context.brand,
265
284
  };
266
285
 
267
- const themeColor = {
268
- ...context.brand.themeColors,
269
- };
270
-
271
286
  return (
272
- <ThemeProvider themeColors={themeColor} fontFamily={fontFamily}>
287
+ <ThemeProvider
288
+ themeColors={themeColors}
289
+ fontFamily={fontFamily}
290
+ isDarkTheme={isDarkTheme}
291
+ >
273
292
  <EventHandlerProvider
274
293
  eventHandlers={{
275
294
  ...eventHandlers,
@@ -284,3 +303,20 @@ export const MoneyLionOfferCarousel = (
284
303
  </ThemeProvider>
285
304
  );
286
305
  };
306
+
307
+ export const MoneyLionOfferCarousel = (
308
+ props: MoneyLionOfferCarouselProps &
309
+ Omit<EventHandlerContextType, "rateTableUuid" | "leadUuid">
310
+ ) => {
311
+ const { fallbackUI, onError } = props;
312
+
313
+ const handleError = (err: CustomError): void => {
314
+ onError?.(err);
315
+ };
316
+
317
+ return (
318
+ <ErrorBoundary fallbackUI={fallbackUI} onError={handleError}>
319
+ <InternalMoneyLionOfferCarousel {...props} />
320
+ </ErrorBoundary>
321
+ );
322
+ };
@@ -36,50 +36,46 @@ export const localCnfContext: CnfContext = {
36
36
  icon: null,
37
37
  },
38
38
  type: "business",
39
- themeColors: {
40
- backgroundCritical: "#ff7200",
41
- backgroundCriticalFaded: "#fff2e8",
42
- backgroundCriticalHighlighted: "#ee6a00",
43
- backgroundDisabled: "#eeeeee",
44
- backgroundDisabledFaded: "#f6f6f6",
45
- backgroundElevationBase: "#ffffff",
46
- backgroundElevationOverlay: "#ffffff",
47
- backgroundElevationRaised: "#ffffff",
48
- backgroundNeutral: "#e2e2e2",
49
- backgroundNeutralFaded: "#f5f5f5",
50
- backgroundNeutralHighlighted: "#d7d7d7",
51
- backgroundPage: "#ffffff",
52
- backgroundPageFaded: "#f9f9f9",
53
- backgroundPositive: "#00e5c4",
54
- backgroundPositiveFaded: "#e8fffc",
55
- backgroundPositiveHighlighted: "#00d9b9",
56
- backgroundPrimary: "#00e5c4",
57
- backgroundPrimaryFaded: "#e8fffc",
58
- backgroundPrimaryHighlighted: "#00d9b9",
59
- backgroundWarning: "#facc15",
60
- backgroundWarningFaded: "#fffae9",
61
- backgroundWarningHighlighted: "#edc113",
62
- black: "#000000",
63
- borderCritical: "#d35d00",
64
- borderCriticalFaded: "#fce3ce",
65
- borderDisabled: "#e2e2e2",
66
- borderNeutral: "#bbbbbb",
67
- borderNeutralFaded: "#e1e1e1",
68
- borderPositive: "#00bfa3",
69
- borderPositiveFaded: "#b8faf2",
70
- borderPrimary: "#00bfa3",
71
- borderPrimaryFaded: "#b8faf2",
72
- borderWarning: "#cfa90f",
73
- borderWarningFaded: "#faedbb",
74
- brand: "#00e5c4",
75
- foregroundCritical: "#a94900",
76
- foregroundDisabled: "#cccccc",
77
- foregroundNeutral: "#181818",
78
- foregroundNeutralFaded: "#666666",
79
- foregroundPositive: "#007362",
80
- foregroundPrimary: "#007362",
81
- foregroundWarning: "#7b6305",
82
- white: "#ffffff",
39
+ // reshapedThemeColors is being used as fallback in the getThemeColors util
40
+ reshapedThemeColors: {
41
+ backgroundCritical: { hex: "#ff7200", hexDark: "#ff7200" },
42
+ backgroundCriticalFaded: { hex: "#fff2ec", hexDark: "#361e11" },
43
+ backgroundDisabled: { hex: "#eeeeed", hexDark: "#252523" },
44
+ backgroundDisabledFaded: { hex: "#f7f6f6", hexDark: "#1c1b19" },
45
+ backgroundElevationBase: { hex: "#ffffff", hexDark: "#171615" },
46
+ backgroundElevationOverlay: { hex: "#ffffff", hexDark: "#1e1e1c" },
47
+ backgroundElevationRaised: { hex: "#ffffff", hexDark: "#191917" },
48
+ backgroundNeutral: { hex: "#e2e2e2", hexDark: "#3f3c35" },
49
+ backgroundNeutralFaded: { hex: "#f4f4f4", hexDark: "#24221e" },
50
+ backgroundPage: { hex: "#ffffff", hexDark: "#0e0e0e" },
51
+ backgroundPageFaded: { hex: "#fbfbfb", hexDark: "#141413" },
52
+ backgroundPositive: { hex: "#00e5c4", hexDark: "#00e5c4" },
53
+ backgroundPositiveFaded: { hex: "#ebfff9", hexDark: "#122a24" },
54
+ backgroundPrimary: { hex: "#00e5c4", hexDark: "#00e5c4" },
55
+ backgroundPrimaryFaded: { hex: "#ebfff9", hexDark: "#122a24" },
56
+ backgroundWarning: { hex: "#facc15", hexDark: "#facc15" },
57
+ backgroundWarningFaded: { hex: "#fff6dd", hexDark: "#2b2410" },
58
+ black: { hex: "#000000" },
59
+ borderCritical: { hex: "#aa4a00", hexDark: "#f4b89b" },
60
+ borderCriticalFaded: { hex: "#f3dcd0", hexDark: "#553220" },
61
+ borderDisabled: { hex: "#e3e2e0", hexDark: "#282725" },
62
+ borderNeutral: { hex: "#0000001f", hexDark: "#ffffff24" },
63
+ borderNeutralFaded: { hex: "#00000014", hexDark: "#ffffff14" },
64
+ borderPositive: { hex: "#007c6a", hexDark: "#bbf7e7" },
65
+ borderPositiveFaded: { hex: "#cfede5", hexDark: "#21443c" },
66
+ borderPrimary: { hex: "#007c6a", hexDark: "#bbf7e7" },
67
+ borderPrimaryFaded: { hex: "#cfede5", hexDark: "#21443c" },
68
+ borderWarning: { hex: "#816802", hexDark: "#fbf3db" },
69
+ borderWarningFaded: { hex: "#ece2c4", hexDark: "#453c1e" },
70
+ brand: { hex: "#00e5c4" },
71
+ foregroundCritical: { hex: "#aa4a00", hexDark: "#f4b89b" },
72
+ foregroundDisabled: { hex: "#cdccc9", hexDark: "#4c4a47" },
73
+ foregroundNeutral: { hex: "#2e2e2e", hexDark: "#f4f4f4" },
74
+ foregroundNeutralFaded: { hex: "#6a6a6a", hexDark: "#c9c9c9" },
75
+ foregroundPositive: { hex: "#007c6a", hexDark: "#bbf7e7" },
76
+ foregroundPrimary: { hex: "#007c6a", hexDark: "#bbf7e7" },
77
+ foregroundWarning: { hex: "#816802", hexDark: "#fbf3db" },
78
+ white: { hex: "#ffffff" },
83
79
  },
84
80
  isLicensed: true,
85
81
  allowedMarks: { logo: true, name: true },