@developer_tribe/react-builder 1.2.27 → 1.2.29

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 (156) hide show
  1. package/dist/assets/samples/getSamples.d.ts +0 -3
  2. package/dist/build-components/BIcon/BIconProps.generated.d.ts +1 -2
  3. package/dist/build-components/CountDown/CountDownProps.generated.d.ts +2 -1
  4. package/dist/build-components/OnboardFooter/OnboardFooterProps.generated.d.ts +1 -2
  5. package/dist/build-components/OnboardSubtitle/OnboardSubtitleProps.generated.d.ts +1 -2
  6. package/dist/build-components/OnboardTitle/OnboardTitleProps.generated.d.ts +1 -2
  7. package/dist/build-components/PaywallCloseButton/PaywallCloseButtonProps.generated.d.ts +1 -2
  8. package/dist/build-components/PaywallOptions/usePaywallOptionParamsFactory.d.ts +1 -1
  9. package/dist/build-components/PriceTag/PriceTag.d.ts +5 -0
  10. package/dist/build-components/PriceTag/PriceTagProps.generated.d.ts +63 -0
  11. package/dist/build-components/Pricing/Pricing.d.ts +5 -0
  12. package/dist/build-components/Pricing/PricingProps.generated.d.ts +59 -0
  13. package/dist/build-components/Promo/Promo.d.ts +5 -0
  14. package/dist/build-components/Promo/PromoProps.generated.d.ts +59 -0
  15. package/dist/build-components/Text/TextProps.generated.d.ts +1 -2
  16. package/dist/build-components/index.d.ts +4 -1
  17. package/dist/build-components/patterns.generated.d.ts +1405 -202
  18. package/dist/components/BuilderProvider.d.ts +5 -3
  19. package/dist/components/ParamsProvider.d.ts +16 -8
  20. package/dist/hooks/useSyncHtmlThemeClass.d.ts +1 -1
  21. package/dist/index.cjs.js +4 -4
  22. package/dist/index.cjs.js.map +1 -1
  23. package/dist/index.d.ts +16 -3
  24. package/dist/index.esm.js +4 -4
  25. package/dist/index.esm.js.map +1 -1
  26. package/dist/index.web.cjs.js +4 -4
  27. package/dist/index.web.cjs.js.map +1 -1
  28. package/dist/index.web.esm.js +4 -4
  29. package/dist/index.web.esm.js.map +1 -1
  30. package/dist/logger.d.ts +18 -0
  31. package/dist/modals/InspectModal.d.ts +5 -0
  32. package/dist/modals/index.d.ts +1 -1
  33. package/dist/pages/ProjectPage.d.ts +3 -3
  34. package/dist/paywall/hooks/useCalculateLocalizedPrice.d.ts +4 -2
  35. package/dist/paywall/hooks/useDiscountRate.d.ts +3 -2
  36. package/dist/paywall/types/paywall-types.d.ts +7 -32
  37. package/dist/product-base/buildPaywallLocalizationParams.d.ts +16 -0
  38. package/dist/product-base/calculations.d.ts +29 -0
  39. package/dist/product-base/extractAndroidParams.d.ts +24 -0
  40. package/dist/product-base/extractIOSParams.d.ts +24 -0
  41. package/dist/product-base/index.d.ts +51 -0
  42. package/dist/product-base/periodLocalizationKeys.d.ts +44 -0
  43. package/dist/product-base/types.d.ts +155 -0
  44. package/dist/product-base/usePaywallLocalizationParams.d.ts +29 -0
  45. package/dist/store.d.ts +7 -1
  46. package/dist/styles.css +1 -1
  47. package/dist/types/PreviewConfig.d.ts +10 -16
  48. package/dist/utils/extractTextStyle/extractTextStyle.d.ts +2 -2
  49. package/dist/utils/extractTextStyle/extractTextStyleNative.d.ts +2 -2
  50. package/dist/utils/replaceLocalizationParams.d.ts +1 -1
  51. package/package.json +2 -2
  52. package/scripts/migrate-samples-to-current.ts +3 -3
  53. package/scripts/prebuild/utils/validateAllComponentsOrThrow.js +28 -12
  54. package/src/DeviceMockFrame.tsx +15 -10
  55. package/src/assets/meta.json +1 -1
  56. package/src/assets/samples/carousel-sample.json +6 -5
  57. package/src/assets/samples/getSamples.ts +16 -49
  58. package/src/assets/samples/paywall-1.json +64 -22
  59. package/src/assets/samples/paywall-2.json +0 -15
  60. package/src/assets/samples/paywall-app-delete-offer.json +0 -15
  61. package/src/assets/samples/paywall-app-open-offer.json +0 -15
  62. package/src/assets/samples/paywall-back-offer.json +0 -15
  63. package/src/assets/samples/paywall-notification-offer.json +0 -15
  64. package/src/assets/samples/simple-1.json +1 -16
  65. package/src/assets/samples/simple-2.json +0 -15
  66. package/src/assets/samples/unmigrated-builder-1.1.1.json +0 -3
  67. package/src/assets/samples/unmigrated-builder1.json +0 -3
  68. package/src/assets/samples/unvalidated-builder1.json +0 -3
  69. package/src/assets/samples/unvalidated-crash1.json +0 -3
  70. package/src/assets/samples/unvalidated-crashcomponent1.json +0 -3
  71. package/src/assets/samples/vpn-onboard-1.json +1 -34
  72. package/src/assets/samples/vpn-onboard-2.json +1 -34
  73. package/src/assets/samples/vpn-onboard-3.json +1 -42
  74. package/src/assets/samples/vpn-onboard-4.json +0 -73
  75. package/src/assets/samples/vpn-onboard-5.json +0 -73
  76. package/src/assets/samples/vpn-onboard-6.json +0 -73
  77. package/src/assets/samples/vpn-onboard-7.json +529 -0
  78. package/src/attribute-analyser/style/native/useExtractImageStyle.ts +1 -4
  79. package/src/attribute-analyser/style/native/useExtractTextStyle.ts +3 -12
  80. package/src/attribute-analyser/style/native/useExtractViewStyle.ts +1 -4
  81. package/src/attribute-analyser/style/web/useExtractImageStyle.ts +1 -4
  82. package/src/attribute-analyser/style/web/useExtractTextStyle.ts +3 -12
  83. package/src/attribute-analyser/style/web/useExtractViewStyle.ts +1 -4
  84. package/src/attributes-editor/useAttributesEditorModel.ts +5 -52
  85. package/src/build-components/BIcon/BIconProps.generated.ts +1 -2
  86. package/src/build-components/CarouselDots/CarouselDots.tsx +6 -13
  87. package/src/build-components/CountDown/CountDownProps.generated.ts +2 -1
  88. package/src/build-components/NavigationBarColor/NavigationBarColor.tsx +2 -2
  89. package/src/build-components/OnboardButton/OnboardButton.tsx +1 -2
  90. package/src/build-components/OnboardDot/OnboardDot.tsx +6 -18
  91. package/src/build-components/OnboardFooter/OnboardFooter.tsx +5 -3
  92. package/src/build-components/OnboardFooter/OnboardFooterProps.generated.ts +1 -2
  93. package/src/build-components/OnboardFooter/pattern.json +1 -1
  94. package/src/build-components/OnboardSubtitle/OnboardSubtitleProps.generated.ts +1 -2
  95. package/src/build-components/OnboardTitle/OnboardTitleProps.generated.ts +1 -2
  96. package/src/build-components/PaywallCloseButton/PaywallCloseButtonProps.generated.ts +1 -2
  97. package/src/build-components/PaywallOptions/PaywallOptions.tsx +3 -3
  98. package/src/build-components/PaywallOptions/usePaywallOptionParamsFactory.ts +26 -13
  99. package/src/build-components/PaywallProvider/PaywallProvider.tsx +51 -12
  100. package/src/build-components/PriceTag/PriceTag.tsx +25 -0
  101. package/src/build-components/PriceTag/PriceTagProps.generated.ts +83 -0
  102. package/src/build-components/PriceTag/pattern.json +53 -0
  103. package/src/build-components/Pricing/Pricing.tsx +13 -0
  104. package/src/build-components/Pricing/PricingProps.generated.ts +76 -0
  105. package/src/build-components/Pricing/pattern.json +25 -0
  106. package/src/build-components/Promo/Promo.tsx +13 -0
  107. package/src/build-components/Promo/PromoProps.generated.ts +76 -0
  108. package/src/build-components/Promo/pattern.json +25 -0
  109. package/src/build-components/RadioButton/RadioButton.tsx +3 -5
  110. package/src/build-components/RenderNode.generated.tsx +15 -0
  111. package/src/build-components/StatusBarColor/StatusBarColor.tsx +2 -2
  112. package/src/build-components/Text/Text.tsx +12 -5
  113. package/src/build-components/Text/TextProps.generated.ts +1 -2
  114. package/src/build-components/Text/pattern.json +3 -2
  115. package/src/build-components/index.ts +15 -0
  116. package/src/build-components/patterns.generated.ts +1454 -181
  117. package/src/components/BottomBar.tsx +42 -39
  118. package/src/components/BuilderProvider.tsx +41 -14
  119. package/src/components/LocalizationParamsProvider.tsx +1 -1
  120. package/src/components/ParamsProvider.tsx +36 -11
  121. package/src/hooks/useLocalize.ts +7 -4
  122. package/src/hooks/useParams.ts +1 -1
  123. package/src/hooks/useSyncHtmlThemeClass.ts +2 -2
  124. package/src/index.ts +54 -8
  125. package/src/logger.ts +39 -0
  126. package/src/modals/InspectModal.tsx +331 -0
  127. package/src/modals/ProductPresetsModal.tsx +7 -14
  128. package/src/modals/index.ts +1 -1
  129. package/src/pages/DebugJsonPage.tsx +9 -22
  130. package/src/pages/ProjectDebug.tsx +1 -1
  131. package/src/pages/ProjectPage.tsx +29 -11
  132. package/src/pages/tabs/SideTool.tsx +28 -104
  133. package/src/paywall/hooks/useCalculateLocalizedPrice.ts +8 -3
  134. package/src/paywall/hooks/useDiscountRate.ts +11 -3
  135. package/src/paywall/types/paywall-types.ts +7 -38
  136. package/src/product-base/buildPaywallLocalizationParams.ts +100 -0
  137. package/src/product-base/calculations.ts +93 -0
  138. package/src/product-base/extractAndroidParams.ts +207 -0
  139. package/src/product-base/extractIOSParams.ts +199 -0
  140. package/src/product-base/index.ts +64 -0
  141. package/src/product-base/mockProducts.json +489 -0
  142. package/src/product-base/periodLocalizationKeys.ts +114 -0
  143. package/src/product-base/types.ts +183 -0
  144. package/src/product-base/usePaywallLocalizationParams.ts +61 -0
  145. package/src/store.ts +18 -1
  146. package/src/styles/index.scss +1 -0
  147. package/src/styles/modals/_inspect-modal.scss +155 -0
  148. package/src/types/PreviewConfig.ts +157 -16
  149. package/src/utils/extractTextStyle/extractTextStyle.ts +14 -6
  150. package/src/utils/extractTextStyle/extractTextStyleNative.ts +8 -6
  151. package/src/utils/logRenderStore.ts +6 -10
  152. package/src/utils/parseColor.ts +0 -1
  153. package/src/utils/replaceLocalizationParams.ts +8 -4
  154. package/dist/modals/ScreenColorsModal.d.ts +0 -8
  155. package/src/assets/products.json +0 -98
  156. package/src/modals/ScreenColorsModal.tsx +0 -121
@@ -0,0 +1,199 @@
1
+ import { convertIOSPeriodUnit } from './periodLocalizationKeys';
2
+ import { iapLogger } from '../logger';
3
+ import {
4
+ calculateDiscount,
5
+ calculatePricePerMonth,
6
+ calculatePricePerYear,
7
+ } from './calculations';
8
+ import type { Product, IOSDiscount, IOSIntroductoryPrice } from './types';
9
+
10
+ export interface IOSParams {
11
+ price: string;
12
+ promoPrice: string;
13
+ currency: string;
14
+ localizedPrice: string;
15
+ period: string;
16
+ periodValue: string;
17
+ periodType: string;
18
+ promoPeriod: string;
19
+ promoCycles: string;
20
+ promoPeriodUnit: string;
21
+ hasTrial: string;
22
+ trialPeriod: string;
23
+ trialPeriodUnit: string;
24
+ discountPercentage: string;
25
+ pricePerMonth: string;
26
+ pricePerYear: string;
27
+ }
28
+
29
+ function isFreeTrialIntro(introPrice: IOSIntroductoryPrice): boolean {
30
+ return (
31
+ introPrice.type === 'free_trial' ||
32
+ parseFloat(introPrice.price || introPrice.priceIOS || '0') === 0
33
+ );
34
+ }
35
+
36
+ function extractPromoCyclesAndPeriod(
37
+ cycles: number,
38
+ periodUnit: string,
39
+ ): { promoPeriod: string; promoCycles: string; promoPeriodUnit: string } {
40
+ return {
41
+ promoPeriod: `${cycles} ${periodUnit}${cycles > 1 ? 's' : ''}`,
42
+ promoCycles: String(cycles),
43
+ promoPeriodUnit: periodUnit,
44
+ };
45
+ }
46
+
47
+ /**
48
+ * iOS product'tan params'ları extract eder
49
+ * introductoryPrice ve discounts'tan trial/promo bilgilerini parse eder
50
+ */
51
+ export function extractIOSParams(
52
+ product: Product,
53
+ offerId?: string,
54
+ ): IOSParams {
55
+ try {
56
+ const price = String(product.price || product.localizedPrice || '').replace(
57
+ /[^0-9.]/g,
58
+ '',
59
+ );
60
+ const currency = product.currency || product.currencyCode || '';
61
+ const localizedPrice = product.localizedPrice || '';
62
+
63
+ const periodUnit = convertIOSPeriodUnit(
64
+ product.subscriptionPeriodUnitIOS || 'MONTH',
65
+ );
66
+ const periodValue = String(product.subscriptionPeriodNumberIOS || 1);
67
+ const periodType = `${periodValue} ${periodUnit}${parseInt(periodValue, 10) > 1 ? 's' : ''}`;
68
+
69
+ const introPrice =
70
+ product.introductoryPrice || product.introductoryPriceIOS;
71
+ const hasIntro = !!introPrice;
72
+ const isTrial = hasIntro && isFreeTrialIntro(introPrice);
73
+
74
+ let hasTrial = 'false';
75
+ let trialPeriod = '';
76
+ let trialPeriodUnit = '';
77
+ let promoPrice = '';
78
+ let promoPeriod = '';
79
+ let promoCycles = '';
80
+ let promoPeriodUnit = '';
81
+
82
+ if (isTrial) {
83
+ hasTrial = 'true';
84
+ trialPeriod = String(
85
+ introPrice.subscriptionPeriodNumberIOS ||
86
+ introPrice.numberOfPeriods ||
87
+ 7,
88
+ );
89
+ trialPeriodUnit = convertIOSPeriodUnit(
90
+ introPrice.subscriptionPeriodUnitIOS ||
91
+ introPrice.subscriptionPeriod ||
92
+ 'DAY',
93
+ );
94
+ } else if (hasIntro) {
95
+ promoPrice = String(
96
+ introPrice.price || introPrice.priceIOS || '',
97
+ ).replace(/[^0-9.]/g, '');
98
+ const cycles = introPrice.numberOfPeriods || 1;
99
+ const unit = convertIOSPeriodUnit(
100
+ introPrice.subscriptionPeriodUnitIOS ||
101
+ introPrice.subscriptionPeriod ||
102
+ 'MONTH',
103
+ );
104
+ const extracted = extractPromoCyclesAndPeriod(cycles, unit);
105
+ promoPeriod = extracted.promoPeriod;
106
+ promoCycles = extracted.promoCycles;
107
+ promoPeriodUnit = extracted.promoPeriodUnit;
108
+ }
109
+
110
+ // Promotional offers (discounts) - offerId ile eşleşen discount
111
+ if (offerId && product.discounts) {
112
+ const discount = product.discounts.find(
113
+ (d: IOSDiscount) => d.identifier === offerId,
114
+ );
115
+
116
+ if (discount) {
117
+ promoPrice = String(discount.price || '').replace(/[^0-9.]/g, '');
118
+ const cycles = discount.numberOfPeriods || 1;
119
+ const unit = convertIOSPeriodUnit(
120
+ discount.subscriptionPeriod || 'MONTH',
121
+ );
122
+ const extracted = extractPromoCyclesAndPeriod(cycles, unit);
123
+ promoPeriod = extracted.promoPeriod;
124
+ promoCycles = extracted.promoCycles;
125
+ promoPeriodUnit = extracted.promoPeriodUnit;
126
+ } else {
127
+ iapLogger.error(
128
+ ['extractIOSParams'],
129
+ 'Requested offer not found in discounts',
130
+ {
131
+ productId: product.id || product.productId,
132
+ requestedOfferId: offerId,
133
+ availableDiscounts: product.discounts.map(
134
+ (d: IOSDiscount) => d.identifier,
135
+ ),
136
+ },
137
+ { remote: true },
138
+ );
139
+ }
140
+ }
141
+
142
+ const discountPercentage = calculateDiscount(price, promoPrice);
143
+ const priceNum = parseFloat(price);
144
+ const pricePerMonth = calculatePricePerMonth(priceNum, periodUnit);
145
+ const pricePerYear = calculatePricePerYear(priceNum, periodUnit);
146
+
147
+ return {
148
+ price,
149
+ promoPrice,
150
+ currency,
151
+ localizedPrice,
152
+ period: periodUnit,
153
+ periodValue,
154
+ periodType,
155
+ promoPeriod,
156
+ promoCycles,
157
+ promoPeriodUnit,
158
+ hasTrial,
159
+ trialPeriod,
160
+ trialPeriodUnit,
161
+ discountPercentage,
162
+ pricePerMonth,
163
+ pricePerYear,
164
+ };
165
+ } catch (error) {
166
+ iapLogger.error(
167
+ ['extractIOSParams'],
168
+ 'Failed to extract iOS params',
169
+ {
170
+ productId: product?.id || product?.productId,
171
+ error: error instanceof Error ? error.message : String(error),
172
+ },
173
+ { remote: true },
174
+ );
175
+ return getEmptyParams();
176
+ }
177
+ }
178
+
179
+ /** Boş params döner (fallback) */
180
+ function getEmptyParams(): IOSParams {
181
+ return {
182
+ price: '',
183
+ promoPrice: '',
184
+ currency: '',
185
+ localizedPrice: '',
186
+ period: 'month',
187
+ periodValue: '1',
188
+ periodType: '1 month',
189
+ promoPeriod: '',
190
+ promoCycles: '',
191
+ promoPeriodUnit: '',
192
+ hasTrial: 'false',
193
+ trialPeriod: '',
194
+ trialPeriodUnit: '',
195
+ discountPercentage: '',
196
+ pricePerMonth: '',
197
+ pricePerYear: '',
198
+ };
199
+ }
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Product base — centralized product utilities for paywall.
3
+ *
4
+ * This module is the single source of truth for product extraction, calculation
5
+ * and localization logic. It is consumed by:
6
+ * - This library's own web builder (PaywallProvider, ProductPresetsModal)
7
+ * - The core React Native project via `@developer_tribe/react-builder` exports
8
+ *
9
+ * Everything here is RN-safe (no DOM, no SCSS, no window/document).
10
+ *
11
+ * Includes:
12
+ * - types.ts : Product, PricingPhase, SubscriptionOffer, IOSDiscount, etc.
13
+ * - calculations.ts : extractPrice, calculateDiscount, pricePerMonth/Year
14
+ * - periodLocalizationKeys.ts : PERIOD_LOCALIZATION_KEYS, parseBillingPeriod, convertIOSPeriodUnit
15
+ * - extractAndroidParams.ts : Android pricingPhases extraction (trial, promo, regular)
16
+ * - extractIOSParams.ts : iOS introductoryPrice/discounts extraction
17
+ * - buildPaywallLocalizationParams.ts : Pure function — platform injected from outside
18
+ * - usePaywallLocalizationParams.ts : Generic React hook — all deps via config param
19
+ * - mockProducts.json : Mock product data for testing (Android + iOS)
20
+ */
21
+
22
+ export * from './types';
23
+ export * from './calculations';
24
+ export * from './periodLocalizationKeys';
25
+ export * from './extractAndroidParams';
26
+ export * from './extractIOSParams';
27
+ export * from './buildPaywallLocalizationParams';
28
+ export * from './usePaywallLocalizationParams';
29
+
30
+ /* ── Mock Products ── */
31
+
32
+ import presetsJson from './mockProducts.json';
33
+ import type { Product } from './types';
34
+
35
+ /** Preset map: preset key → product array. */
36
+ export type MockProductPresets = Record<string, Product[]>;
37
+
38
+ /**
39
+ * Returns a deep-copy of all mock product presets.
40
+ *
41
+ * Use this instead of importing `mockProducts.json` directly so that:
42
+ * 1. Consumers don't couple to a JSON file path.
43
+ * 2. Each call returns a fresh copy (safe to mutate).
44
+ *
45
+ * @example
46
+ * import { getMockProducts } from '@developer_tribe/react-builder';
47
+ * const presets = getMockProducts(); // { 'preset-1': [...], ... }
48
+ */
49
+ export function getMockProducts(): MockProductPresets {
50
+ return JSON.parse(JSON.stringify(presetsJson)) as MockProductPresets;
51
+ }
52
+
53
+ /**
54
+ * Returns the product list for a specific preset key (deep-copied).
55
+ * Returns an empty array if the key doesn't exist.
56
+ *
57
+ * @example
58
+ * import { getMockProductsByPreset } from '@developer_tribe/react-builder';
59
+ * const products = getMockProductsByPreset('preset-1');
60
+ */
61
+ export function getMockProductsByPreset(presetKey: string): Product[] {
62
+ const all = getMockProducts();
63
+ return all[presetKey] ?? [];
64
+ }