@developer_tribe/react-builder 1.2.40 → 1.2.41
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/dist/attributes-editor/FallbackLocalizationField.d.ts +6 -0
- package/dist/index.cjs.js +1 -1
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.esm.js +1 -1
- package/dist/index.esm.js.map +1 -1
- package/dist/index.web.cjs.js +2 -2
- package/dist/index.web.cjs.js.map +1 -1
- package/dist/index.web.d.ts +8 -0
- package/dist/index.web.esm.js +2 -2
- package/dist/index.web.esm.js.map +1 -1
- package/dist/product-base/types.d.ts +3 -0
- package/dist/store.d.ts +25 -0
- package/dist/types/PreviewConfig.d.ts +1 -1
- package/package.json +1 -1
- package/scripts/public/bin.js +0 -0
- package/src/assets/meta.json +1 -1
- package/src/assets/prompt-scheme-onboard.generated.ts +1 -1
- package/src/assets/prompt-scheme-paywall.generated.ts +1 -1
- package/src/assets/samples/paywall-1.json +1 -1
- package/src/assets/samples/paywall-2.json +2 -2
- package/src/assets/samples/paywall-app-delete-offer.json +2 -2
- package/src/assets/samples/paywall-app-open-offer.json +2 -2
- package/src/assets/samples/paywall-back-offer.json +1 -1
- package/src/assets/samples/paywall-notification-offer.json +1 -1
- package/src/attributes-editor/AttributesEditorView.tsx +17 -6
- package/src/attributes-editor/FallbackLocalizationField.tsx +384 -0
- package/src/components/BottomBar.tsx +135 -31
- package/src/hooks/useLocalize.ts +3 -1
- package/src/index.web.ts +19 -0
- package/src/modals/InspectModal.tsx +112 -4
- package/src/product-base/buildPaywallLocalizationParams.ts +3 -0
- package/src/product-base/types.ts +3 -0
- package/src/store.ts +39 -0
- package/src/types/PreviewConfig.ts +6 -0
|
@@ -113,8 +113,41 @@ function LocalizationsTab({
|
|
|
113
113
|
);
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
+
const handleDownloadCSV = () => {
|
|
117
|
+
let csvContent = 'Key,Value,Source\n';
|
|
118
|
+
allKeys.forEach((key) => {
|
|
119
|
+
const hasCustom = key in langKeys;
|
|
120
|
+
const customValue = langKeys[key];
|
|
121
|
+
const defaultValue = defaultLangKeys[key];
|
|
122
|
+
|
|
123
|
+
const isCustom =
|
|
124
|
+
hasCustom && customValue !== defaultValue && customValue !== undefined;
|
|
125
|
+
const value = isCustom ? customValue : (defaultValue ?? '');
|
|
126
|
+
|
|
127
|
+
const escape = (str: string) => `"${String(str).replace(/"/g, '""')}"`;
|
|
128
|
+
csvContent += `${escape(key)},${escape(String(value))},${isCustom ? 'spreadsheet' : 'fallback'}\n`;
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
downloadCSV(`localizations-${language}.csv`, csvContent);
|
|
132
|
+
};
|
|
133
|
+
|
|
116
134
|
return (
|
|
117
135
|
<div className="inspect-modal__table-wrap">
|
|
136
|
+
<div
|
|
137
|
+
style={{
|
|
138
|
+
display: 'flex',
|
|
139
|
+
justifyContent: 'flex-end',
|
|
140
|
+
marginBottom: '8px',
|
|
141
|
+
}}
|
|
142
|
+
>
|
|
143
|
+
<button
|
|
144
|
+
type="button"
|
|
145
|
+
className="editor-button"
|
|
146
|
+
onClick={handleDownloadCSV}
|
|
147
|
+
>
|
|
148
|
+
Download CSV
|
|
149
|
+
</button>
|
|
150
|
+
</div>
|
|
118
151
|
<table className="inspect-modal__table">
|
|
119
152
|
<thead>
|
|
120
153
|
<tr>
|
|
@@ -148,7 +181,7 @@ function LocalizationsTab({
|
|
|
148
181
|
<span style={{ color: 'red' }}>!</span> fallback
|
|
149
182
|
</>
|
|
150
183
|
) : (
|
|
151
|
-
'
|
|
184
|
+
'spreadsheet'
|
|
152
185
|
)}
|
|
153
186
|
</span>
|
|
154
187
|
</td>
|
|
@@ -179,13 +212,43 @@ function ParamsTab({
|
|
|
179
212
|
if (!hasAny) {
|
|
180
213
|
return (
|
|
181
214
|
<p className="inspect-modal__empty">
|
|
182
|
-
No params available. Params are populated inside a
|
|
215
|
+
No params available. Params are populated inside a ParamsProvider.
|
|
183
216
|
</p>
|
|
184
217
|
);
|
|
185
218
|
}
|
|
186
219
|
|
|
220
|
+
const handleDownloadCSV = () => {
|
|
221
|
+
let csvContent = 'Param,Value,Type\n';
|
|
222
|
+
const escape = (str: string) => `"${String(str).replace(/"/g, '""')}"`;
|
|
223
|
+
|
|
224
|
+
flatEntries.forEach(([key, value]) => {
|
|
225
|
+
csvContent += `${escape(key)},${escape(formatValue(value))},Flat\n`;
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
nestedEntries.forEach(([key, value]) => {
|
|
229
|
+
csvContent += `${escape(key)},${escape(formatValue(value))},Nested\n`;
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
downloadCSV('params.csv', csvContent);
|
|
233
|
+
};
|
|
234
|
+
|
|
187
235
|
return (
|
|
188
236
|
<div className="inspect-modal__table-wrap">
|
|
237
|
+
<div
|
|
238
|
+
style={{
|
|
239
|
+
display: 'flex',
|
|
240
|
+
justifyContent: 'flex-end',
|
|
241
|
+
marginBottom: '8px',
|
|
242
|
+
}}
|
|
243
|
+
>
|
|
244
|
+
<button
|
|
245
|
+
type="button"
|
|
246
|
+
className="editor-button"
|
|
247
|
+
onClick={handleDownloadCSV}
|
|
248
|
+
>
|
|
249
|
+
Download CSV
|
|
250
|
+
</button>
|
|
251
|
+
</div>
|
|
189
252
|
<table className="inspect-modal__table">
|
|
190
253
|
<thead>
|
|
191
254
|
<tr>
|
|
@@ -249,8 +312,29 @@ function ColorsTab({
|
|
|
249
312
|
return <p className="inspect-modal__empty">No project colors defined.</p>;
|
|
250
313
|
}
|
|
251
314
|
|
|
315
|
+
const handleDownloadJSON = () => {
|
|
316
|
+
const data = projectColors ?? {};
|
|
317
|
+
const jsonContent = JSON.stringify(data, null, 2);
|
|
318
|
+
downloadJSON('colors.json', jsonContent);
|
|
319
|
+
};
|
|
320
|
+
|
|
252
321
|
return (
|
|
253
322
|
<div className="inspect-modal__table-wrap">
|
|
323
|
+
<div
|
|
324
|
+
style={{
|
|
325
|
+
display: 'flex',
|
|
326
|
+
justifyContent: 'flex-end',
|
|
327
|
+
marginBottom: '8px',
|
|
328
|
+
}}
|
|
329
|
+
>
|
|
330
|
+
<button
|
|
331
|
+
type="button"
|
|
332
|
+
className="editor-button"
|
|
333
|
+
onClick={handleDownloadJSON}
|
|
334
|
+
>
|
|
335
|
+
Download JSON
|
|
336
|
+
</button>
|
|
337
|
+
</div>
|
|
254
338
|
{staticEntries.length > 0 && (
|
|
255
339
|
<>
|
|
256
340
|
<h4 className="inspect-modal__section-title">Static Colors</h4>
|
|
@@ -284,7 +368,7 @@ function ColorsTab({
|
|
|
284
368
|
<span style={{ color: 'red' }}>!</span> fallback
|
|
285
369
|
</>
|
|
286
370
|
) : (
|
|
287
|
-
'
|
|
371
|
+
'added to project'
|
|
288
372
|
)}
|
|
289
373
|
</span>
|
|
290
374
|
</td>
|
|
@@ -331,7 +415,7 @@ function ColorsTab({
|
|
|
331
415
|
<span style={{ color: 'red' }}>!</span> fallback
|
|
332
416
|
</>
|
|
333
417
|
) : (
|
|
334
|
-
'
|
|
418
|
+
'added to project'
|
|
335
419
|
)}
|
|
336
420
|
</span>
|
|
337
421
|
</td>
|
|
@@ -357,3 +441,27 @@ function formatValue(v: unknown): string {
|
|
|
357
441
|
if (typeof v === 'number' || typeof v === 'boolean') return String(v);
|
|
358
442
|
return JSON.stringify(v);
|
|
359
443
|
}
|
|
444
|
+
|
|
445
|
+
function downloadCSV(filename: string, csvContent: string) {
|
|
446
|
+
const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
|
|
447
|
+
const url = URL.createObjectURL(blob);
|
|
448
|
+
const link = document.createElement('a');
|
|
449
|
+
link.setAttribute('href', url);
|
|
450
|
+
link.setAttribute('download', filename);
|
|
451
|
+
document.body.appendChild(link);
|
|
452
|
+
link.click();
|
|
453
|
+
document.body.removeChild(link);
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
function downloadJSON(filename: string, jsonContent: string) {
|
|
457
|
+
const blob = new Blob([jsonContent], {
|
|
458
|
+
type: 'application/json;charset=utf-8;',
|
|
459
|
+
});
|
|
460
|
+
const url = URL.createObjectURL(blob);
|
|
461
|
+
const link = document.createElement('a');
|
|
462
|
+
link.setAttribute('href', url);
|
|
463
|
+
link.setAttribute('download', filename);
|
|
464
|
+
document.body.appendChild(link);
|
|
465
|
+
link.click();
|
|
466
|
+
document.body.removeChild(link);
|
|
467
|
+
}
|
|
@@ -105,5 +105,8 @@ export function buildPaywallLocalizationParams(
|
|
|
105
105
|
productCurreny: extractedParams.currency,
|
|
106
106
|
productId: String(product.productId ?? ''),
|
|
107
107
|
productSelected: 'true',
|
|
108
|
+
subscribe: hasTrial
|
|
109
|
+
? resolve('base.builder.paywall.button.subscribe-free')
|
|
110
|
+
: resolve('base.builder.paywall.button.subscribe'),
|
|
108
111
|
};
|
|
109
112
|
}
|
|
@@ -116,6 +116,8 @@ export interface Product {
|
|
|
116
116
|
displayPrice?: string;
|
|
117
117
|
localizedPrice?: string;
|
|
118
118
|
price?: string;
|
|
119
|
+
promoPrice?: string;
|
|
120
|
+
localizedPromoPrice?: string;
|
|
119
121
|
currency?: string;
|
|
120
122
|
currencyCode?: string;
|
|
121
123
|
platform?: 'android' | 'ios';
|
|
@@ -169,6 +171,7 @@ export interface ProductParams {
|
|
|
169
171
|
productCurreny: string;
|
|
170
172
|
productId: string;
|
|
171
173
|
productSelected: string;
|
|
174
|
+
subscribe: string;
|
|
172
175
|
}
|
|
173
176
|
|
|
174
177
|
/** Keys excluded from single (per-option) params — these are global/context-level. */
|
package/src/store.ts
CHANGED
|
@@ -1,3 +1,18 @@
|
|
|
1
|
+
import type { ComponentType } from 'react';
|
|
2
|
+
|
|
3
|
+
export type LocalizationApiConfig = {
|
|
4
|
+
forgeUrl: string;
|
|
5
|
+
forgeToken: string;
|
|
6
|
+
forgeAppId?: string | number | null;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export type LanguageColumn = {
|
|
10
|
+
id: number;
|
|
11
|
+
code: string;
|
|
12
|
+
title: string;
|
|
13
|
+
iso_code: string;
|
|
14
|
+
is_right_alignment: boolean;
|
|
15
|
+
};
|
|
1
16
|
import { createWithEqualityFn } from 'zustand/traditional';
|
|
2
17
|
import { shallow } from 'zustand/shallow';
|
|
3
18
|
import type { Device } from './types/Device';
|
|
@@ -43,6 +58,8 @@ type RenderStore = {
|
|
|
43
58
|
setLocalization: (localization: Localication) => void;
|
|
44
59
|
isRtl: boolean;
|
|
45
60
|
setIsRtl: (isRtl: boolean) => void;
|
|
61
|
+
languageColumns: LanguageColumn[];
|
|
62
|
+
setLanguageColumns: (cols: LanguageColumn[]) => void;
|
|
46
63
|
previewMode: boolean;
|
|
47
64
|
setPreviewMode: (previewMode: boolean) => void;
|
|
48
65
|
// Mockable: products (persisted)
|
|
@@ -101,6 +118,18 @@ type RenderStore = {
|
|
|
101
118
|
|
|
102
119
|
favoriteDevices: string[];
|
|
103
120
|
toggleFavoriteDevice: (name: string) => void;
|
|
121
|
+
|
|
122
|
+
// Host-provided custom renderer for the "Text" (string children) field
|
|
123
|
+
renderStringChildrenField?: ComponentType<{
|
|
124
|
+
value: string;
|
|
125
|
+
onChange: (v: string) => void;
|
|
126
|
+
}>;
|
|
127
|
+
setRenderStringChildrenField: (
|
|
128
|
+
comp?: ComponentType<{ value: string; onChange: (v: string) => void }>,
|
|
129
|
+
) => void;
|
|
130
|
+
|
|
131
|
+
localizationApiConfig?: LocalizationApiConfig;
|
|
132
|
+
setLocalizationApiConfig: (config?: LocalizationApiConfig) => void;
|
|
104
133
|
};
|
|
105
134
|
|
|
106
135
|
export const useRenderStore = createWithEqualityFn<RenderStore>()(
|
|
@@ -129,6 +158,8 @@ export const useRenderStore = createWithEqualityFn<RenderStore>()(
|
|
|
129
158
|
setLocalization: (localization) => set({ localization }),
|
|
130
159
|
isRtl: false,
|
|
131
160
|
setIsRtl: (isRtl) => set({ isRtl }),
|
|
161
|
+
languageColumns: [],
|
|
162
|
+
setLanguageColumns: (cols) => set({ languageColumns: cols }),
|
|
132
163
|
previewMode: false,
|
|
133
164
|
setPreviewMode: (previewMode) => set({ previewMode }),
|
|
134
165
|
products: [],
|
|
@@ -296,6 +327,14 @@ export const useRenderStore = createWithEqualityFn<RenderStore>()(
|
|
|
296
327
|
: [...devs, name],
|
|
297
328
|
};
|
|
298
329
|
}),
|
|
330
|
+
|
|
331
|
+
renderStringChildrenField: undefined,
|
|
332
|
+
setRenderStringChildrenField: (comp) =>
|
|
333
|
+
set({ renderStringChildrenField: comp }),
|
|
334
|
+
|
|
335
|
+
localizationApiConfig: undefined,
|
|
336
|
+
setLocalizationApiConfig: (config) =>
|
|
337
|
+
set({ localizationApiConfig: config }),
|
|
299
338
|
}),
|
|
300
339
|
{
|
|
301
340
|
name: 'render-store',
|
|
@@ -15,6 +15,8 @@ export type LocalizationKey =
|
|
|
15
15
|
| 'base.builder.paywall.promo.default.text'
|
|
16
16
|
| 'base.builder.paywall.promo.freeTrial.text'
|
|
17
17
|
| 'base.builder.paywall.promo.regular.text'
|
|
18
|
+
| 'base.builder.paywall.button.subscribe'
|
|
19
|
+
| 'base.builder.paywall.button.subscribe-free'
|
|
18
20
|
// onboard – titles
|
|
19
21
|
| 'base.onboard.title.one-page'
|
|
20
22
|
| 'base.onboard.title.two-page'
|
|
@@ -79,6 +81,8 @@ export const defaultLocalization: Localication = {
|
|
|
79
81
|
'@trialPeriod-@trialPeriodUnit free trial',
|
|
80
82
|
'base.builder.paywall.promo.regular.text':
|
|
81
83
|
'@localizedPrice @localizedPeriod',
|
|
84
|
+
'base.builder.paywall.button.subscribe': 'Subscribe',
|
|
85
|
+
'base.builder.paywall.button.subscribe-free': 'Subscribe with Free Trial',
|
|
82
86
|
// onboard – titles
|
|
83
87
|
'base.onboard.title.one-page': 'Secure your connection',
|
|
84
88
|
'base.onboard.title.two-page': 'Access content worldwide',
|
|
@@ -146,6 +150,8 @@ export const defaultLocalization: Localication = {
|
|
|
146
150
|
'@trialPeriod @trialPeriodUnit ücretsiz deneme',
|
|
147
151
|
'base.builder.paywall.promo.regular.text':
|
|
148
152
|
'@localizedPrice @localizedPeriod',
|
|
153
|
+
'base.builder.paywall.button.subscribe': 'Abone Ol',
|
|
154
|
+
'base.builder.paywall.button.subscribe-free': 'Ücretsiz Denemeyi Başlat',
|
|
149
155
|
// onboard – titles
|
|
150
156
|
'base.onboard.title.five-page': 'Deneyiminizi geliştirin',
|
|
151
157
|
'base.onboard.title.six-page': 'Her şey hazır!',
|