zh-web-sdk 2.16.1 → 2.17.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 +225 -32
- package/package.json +6 -1
- package/.eslintrc.js +0 -12
- package/.github/CHANGELOG_TEMPLATE.md +0 -73
- package/.github/PULL_REQUEST_TEMPLATE.md +0 -10
- package/.github/backup/publish-tag.yaml +0 -14
- package/.github/workflows/build.yaml +0 -13
- package/.github/workflows/pr.yaml +0 -14
- package/.github/workflows/publish.yaml +0 -13
- package/.github/workflows/security.yml +0 -15
- package/.github/workflows/tag.yaml +0 -14
- package/RELEASING.md +0 -39
- package/jest.config.js +0 -8
- package/jest.setup.js +0 -24
- package/scripts/build.js +0 -34
- package/scripts/zip.js +0 -49
- package/src/__tests__/jwt-auth-detection.test.ts +0 -96
- package/src/api/convert-token.ts +0 -23
- package/src/constants.ts +0 -2
- package/src/hooks/__tests__/use-window-size.test.tsx +0 -26
- package/src/hooks/use-window-size.ts +0 -19
- package/src/iframe-container/AppContainer.tsx +0 -495
- package/src/iframe-container/__tests__/AppContainer.test.tsx +0 -300
- package/src/iframe-container/hooks/__tests__/use-style-updates.test.ts +0 -430
- package/src/iframe-container/hooks/use-style-updates.ts +0 -82
- package/src/index.tsx +0 -645
- package/src/redux/actions/index.ts +0 -27
- package/src/redux/reducers/constants.ts +0 -10
- package/src/redux/reducers/crypto-account-link-payouts.ts +0 -60
- package/src/redux/reducers/crypto-account-link.ts +0 -60
- package/src/redux/reducers/crypto-buy.ts +0 -75
- package/src/redux/reducers/crypto-sell.ts +0 -64
- package/src/redux/reducers/crypto-withdrawals.ts +0 -64
- package/src/redux/reducers/fiat-account-link.ts +0 -60
- package/src/redux/reducers/fiat-deposits.ts +0 -64
- package/src/redux/reducers/fiat-withdrawals.ts +0 -64
- package/src/redux/reducers/fund.ts +0 -75
- package/src/redux/reducers/index.ts +0 -35
- package/src/redux/reducers/onboarding.ts +0 -74
- package/src/redux/reducers/pay.ts +0 -64
- package/src/redux/reducers/payouts.ts +0 -64
- package/src/redux/reducers/profile.ts +0 -63
- package/src/redux/store/index.ts +0 -10
- package/src/styles.ts +0 -108
- package/src/types.ts +0 -578
- package/src/utils/auth-to-fund-mapper.ts +0 -174
- package/src/utils/strings.ts +0 -19
- package/src/utils/test-utils.tsx +0 -36
- package/src/utils/world-app-utils.ts +0 -8
- package/src/utils.ts +0 -27
- package/tsconfig.json +0 -26
|
@@ -1,430 +0,0 @@
|
|
|
1
|
-
import { renderHook, act } from "@testing-library/react";
|
|
2
|
-
import { useStyleUpdates, type StyleConfig } from "../use-style-updates";
|
|
3
|
-
|
|
4
|
-
// Jest mock for setTimeout
|
|
5
|
-
jest.useFakeTimers();
|
|
6
|
-
|
|
7
|
-
describe("useStyleUpdates", () => {
|
|
8
|
-
const defaultStyles: StyleConfig = {
|
|
9
|
-
appWrapperStyle: { position: "fixed", zIndex: 999999 },
|
|
10
|
-
modalStyle: { padding: 0, backgroundColor: "#FFF" },
|
|
11
|
-
iframeWrapperStyle: { overflow: "hidden" },
|
|
12
|
-
iframeStyle: { width: "100%", height: "100%" },
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
const zeroHashAppURL = "https://app.example.com/";
|
|
16
|
-
|
|
17
|
-
beforeEach(() => {
|
|
18
|
-
// Reset console.log mock and window.location.origin
|
|
19
|
-
jest.clearAllMocks();
|
|
20
|
-
jest.clearAllTimers();
|
|
21
|
-
Object.defineProperty(window, "location", {
|
|
22
|
-
value: {
|
|
23
|
-
origin: "http://localhost",
|
|
24
|
-
},
|
|
25
|
-
writable: true,
|
|
26
|
-
});
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
afterEach(() => {
|
|
30
|
-
jest.clearAllTimers();
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
describe("initial state", () => {
|
|
34
|
-
it("should initialize with default styles", () => {
|
|
35
|
-
const { result } = renderHook(() =>
|
|
36
|
-
useStyleUpdates(zeroHashAppURL, defaultStyles)
|
|
37
|
-
);
|
|
38
|
-
|
|
39
|
-
expect(result.current.styles).toEqual(defaultStyles);
|
|
40
|
-
expect(result.current.stylesLoaded).toBe(false);
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
it("should have handleStyleConfig function", () => {
|
|
44
|
-
const { result } = renderHook(() =>
|
|
45
|
-
useStyleUpdates(zeroHashAppURL, defaultStyles)
|
|
46
|
-
);
|
|
47
|
-
|
|
48
|
-
expect(typeof result.current.handleStyleConfig).toBe("function");
|
|
49
|
-
});
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
describe("handleStyleConfig with valid origins", () => {
|
|
53
|
-
it("should accept styles from matching zeroHashAppURL origin", () => {
|
|
54
|
-
const { result } = renderHook(() =>
|
|
55
|
-
useStyleUpdates(zeroHashAppURL, defaultStyles)
|
|
56
|
-
);
|
|
57
|
-
|
|
58
|
-
const incomingStyles: Partial<StyleConfig> = {
|
|
59
|
-
iframeStyle: { borderRadius: "8px" },
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
let success = false;
|
|
63
|
-
act(() => {
|
|
64
|
-
success = result.current.handleStyleConfig(
|
|
65
|
-
incomingStyles,
|
|
66
|
-
"https://app.example.com"
|
|
67
|
-
);
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
expect(success).toBe(true);
|
|
71
|
-
expect(result.current.stylesLoaded).toBe(true);
|
|
72
|
-
expect(result.current.styles.iframeStyle.borderRadius).toBe("8px");
|
|
73
|
-
expect(result.current.styles.iframeStyle.width).toBe("100%");
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
it("should accept styles from window.location.origin", () => {
|
|
77
|
-
const { result } = renderHook(() =>
|
|
78
|
-
useStyleUpdates(zeroHashAppURL, defaultStyles)
|
|
79
|
-
);
|
|
80
|
-
|
|
81
|
-
const incomingStyles: Partial<StyleConfig> = {
|
|
82
|
-
modalStyle: { padding: "20px" },
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
let success = false;
|
|
86
|
-
act(() => {
|
|
87
|
-
success = result.current.handleStyleConfig(
|
|
88
|
-
incomingStyles,
|
|
89
|
-
"http://localhost"
|
|
90
|
-
);
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
expect(success).toBe(true);
|
|
94
|
-
expect(result.current.stylesLoaded).toBe(true);
|
|
95
|
-
expect(result.current.styles.modalStyle.padding).toBe("20px");
|
|
96
|
-
expect(result.current.styles.modalStyle.backgroundColor).toBe("#FFF");
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
it("should merge partial styles with defaults", () => {
|
|
100
|
-
const { result } = renderHook(() =>
|
|
101
|
-
useStyleUpdates(zeroHashAppURL, defaultStyles)
|
|
102
|
-
);
|
|
103
|
-
|
|
104
|
-
const incomingStyles: Partial<StyleConfig> = {
|
|
105
|
-
appWrapperStyle: { opacity: 0.9 },
|
|
106
|
-
iframeStyle: { border: "1px solid red" },
|
|
107
|
-
};
|
|
108
|
-
|
|
109
|
-
act(() => {
|
|
110
|
-
result.current.handleStyleConfig(
|
|
111
|
-
incomingStyles,
|
|
112
|
-
"https://app.example.com"
|
|
113
|
-
);
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
expect(result.current.styles.appWrapperStyle).toEqual({
|
|
117
|
-
position: "fixed",
|
|
118
|
-
zIndex: 999999,
|
|
119
|
-
opacity: 0.9,
|
|
120
|
-
});
|
|
121
|
-
expect(result.current.styles.iframeStyle).toEqual({
|
|
122
|
-
width: "100%",
|
|
123
|
-
height: "100%",
|
|
124
|
-
border: "1px solid red",
|
|
125
|
-
});
|
|
126
|
-
expect(result.current.styles.modalStyle).toEqual(defaultStyles.modalStyle);
|
|
127
|
-
expect(result.current.styles.iframeWrapperStyle).toEqual(
|
|
128
|
-
defaultStyles.iframeWrapperStyle
|
|
129
|
-
);
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
it("should override existing styles when called multiple times", () => {
|
|
133
|
-
const { result } = renderHook(() =>
|
|
134
|
-
useStyleUpdates(zeroHashAppURL, defaultStyles)
|
|
135
|
-
);
|
|
136
|
-
|
|
137
|
-
// First update
|
|
138
|
-
act(() => {
|
|
139
|
-
result.current.handleStyleConfig(
|
|
140
|
-
{ iframeStyle: { borderRadius: "8px" } },
|
|
141
|
-
"https://app.example.com"
|
|
142
|
-
);
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
expect(result.current.styles.iframeStyle.borderRadius).toBe("8px");
|
|
146
|
-
|
|
147
|
-
// Second update - should merge, not replace
|
|
148
|
-
act(() => {
|
|
149
|
-
result.current.handleStyleConfig(
|
|
150
|
-
{ iframeStyle: { border: "1px solid blue" } },
|
|
151
|
-
"https://app.example.com"
|
|
152
|
-
);
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
expect(result.current.styles.iframeStyle.borderRadius).toBe("8px");
|
|
156
|
-
expect(result.current.styles.iframeStyle.border).toBe("1px solid blue");
|
|
157
|
-
expect(result.current.styles.iframeStyle.width).toBe("100%");
|
|
158
|
-
});
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
describe("handleStyleConfig with invalid origins", () => {
|
|
162
|
-
it("should reject styles from mismatched origin", () => {
|
|
163
|
-
const { result } = renderHook(() =>
|
|
164
|
-
useStyleUpdates(zeroHashAppURL, defaultStyles)
|
|
165
|
-
);
|
|
166
|
-
|
|
167
|
-
const incomingStyles: Partial<StyleConfig> = {
|
|
168
|
-
iframeStyle: { borderRadius: "16px" },
|
|
169
|
-
};
|
|
170
|
-
|
|
171
|
-
let success = false;
|
|
172
|
-
act(() => {
|
|
173
|
-
success = result.current.handleStyleConfig(
|
|
174
|
-
incomingStyles,
|
|
175
|
-
"https://untrusted.com"
|
|
176
|
-
);
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
expect(success).toBe(false);
|
|
180
|
-
expect(result.current.stylesLoaded).toBe(false);
|
|
181
|
-
expect(result.current.styles).toEqual(defaultStyles);
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
it("should not modify state when origin validation fails", () => {
|
|
185
|
-
const { result } = renderHook(() =>
|
|
186
|
-
useStyleUpdates(zeroHashAppURL, defaultStyles)
|
|
187
|
-
);
|
|
188
|
-
|
|
189
|
-
act(() => {
|
|
190
|
-
result.current.handleStyleConfig(
|
|
191
|
-
{ modalStyle: { backgroundColor: "#000" } },
|
|
192
|
-
"https://malicious.com"
|
|
193
|
-
);
|
|
194
|
-
});
|
|
195
|
-
|
|
196
|
-
expect(result.current.styles.modalStyle.backgroundColor).toBe("#FFF");
|
|
197
|
-
expect(result.current.stylesLoaded).toBe(false);
|
|
198
|
-
});
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
describe("style merging behavior", () => {
|
|
202
|
-
it("should preserve all style properties when merging partial updates", () => {
|
|
203
|
-
const { result } = renderHook(() =>
|
|
204
|
-
useStyleUpdates(zeroHashAppURL, defaultStyles)
|
|
205
|
-
);
|
|
206
|
-
|
|
207
|
-
const complexStyles: Partial<StyleConfig> = {
|
|
208
|
-
modalStyle: {
|
|
209
|
-
padding: "20px",
|
|
210
|
-
backgroundColor: "#000",
|
|
211
|
-
height: "calc(100% - 50px)",
|
|
212
|
-
maxWidth: "calc(100% - 60px)",
|
|
213
|
-
},
|
|
214
|
-
appWrapperStyle: { zIndex: 9999 },
|
|
215
|
-
iframeWrapperStyle: { overflow: "visible" },
|
|
216
|
-
iframeStyle: { borderRadius: "8px" },
|
|
217
|
-
};
|
|
218
|
-
|
|
219
|
-
act(() => {
|
|
220
|
-
result.current.handleStyleConfig(
|
|
221
|
-
complexStyles,
|
|
222
|
-
"https://app.example.com"
|
|
223
|
-
);
|
|
224
|
-
});
|
|
225
|
-
|
|
226
|
-
expect(result.current.styles.modalStyle).toEqual(complexStyles.modalStyle);
|
|
227
|
-
expect(result.current.styles.appWrapperStyle).toEqual({
|
|
228
|
-
position: "fixed",
|
|
229
|
-
zIndex: 9999,
|
|
230
|
-
});
|
|
231
|
-
expect(result.current.styles.iframeWrapperStyle).toEqual({
|
|
232
|
-
overflow: "visible",
|
|
233
|
-
});
|
|
234
|
-
expect(result.current.styles.iframeStyle).toEqual({
|
|
235
|
-
width: "100%",
|
|
236
|
-
height: "100%",
|
|
237
|
-
borderRadius: "8px",
|
|
238
|
-
});
|
|
239
|
-
});
|
|
240
|
-
|
|
241
|
-
it("should not include undefined styles from incoming updates", () => {
|
|
242
|
-
const { result } = renderHook(() =>
|
|
243
|
-
useStyleUpdates(zeroHashAppURL, defaultStyles)
|
|
244
|
-
);
|
|
245
|
-
|
|
246
|
-
const incomingStyles: Partial<StyleConfig> = {
|
|
247
|
-
iframeStyle: { width: "50%" },
|
|
248
|
-
// modalStyle is intentionally not included
|
|
249
|
-
};
|
|
250
|
-
|
|
251
|
-
act(() => {
|
|
252
|
-
result.current.handleStyleConfig(
|
|
253
|
-
incomingStyles,
|
|
254
|
-
"https://app.example.com"
|
|
255
|
-
);
|
|
256
|
-
});
|
|
257
|
-
|
|
258
|
-
expect(result.current.styles.iframeStyle).toEqual({
|
|
259
|
-
width: "50%",
|
|
260
|
-
height: "100%",
|
|
261
|
-
});
|
|
262
|
-
expect(result.current.styles.modalStyle).toEqual(defaultStyles.modalStyle);
|
|
263
|
-
});
|
|
264
|
-
});
|
|
265
|
-
|
|
266
|
-
describe("stylesLoaded flag", () => {
|
|
267
|
-
it("should set stylesLoaded to true after successful style config", () => {
|
|
268
|
-
const { result } = renderHook(() =>
|
|
269
|
-
useStyleUpdates(zeroHashAppURL, defaultStyles)
|
|
270
|
-
);
|
|
271
|
-
|
|
272
|
-
expect(result.current.stylesLoaded).toBe(false);
|
|
273
|
-
|
|
274
|
-
act(() => {
|
|
275
|
-
result.current.handleStyleConfig(
|
|
276
|
-
{ iframeStyle: { borderRadius: "8px" } },
|
|
277
|
-
"https://app.example.com"
|
|
278
|
-
);
|
|
279
|
-
});
|
|
280
|
-
|
|
281
|
-
expect(result.current.stylesLoaded).toBe(true);
|
|
282
|
-
});
|
|
283
|
-
|
|
284
|
-
it("should remain true after multiple successful updates", () => {
|
|
285
|
-
const { result } = renderHook(() =>
|
|
286
|
-
useStyleUpdates(zeroHashAppURL, defaultStyles)
|
|
287
|
-
);
|
|
288
|
-
|
|
289
|
-
act(() => {
|
|
290
|
-
result.current.handleStyleConfig(
|
|
291
|
-
{ iframeStyle: { borderRadius: "8px" } },
|
|
292
|
-
"https://app.example.com"
|
|
293
|
-
);
|
|
294
|
-
});
|
|
295
|
-
|
|
296
|
-
expect(result.current.stylesLoaded).toBe(true);
|
|
297
|
-
|
|
298
|
-
act(() => {
|
|
299
|
-
result.current.handleStyleConfig(
|
|
300
|
-
{ modalStyle: { padding: "10px" } },
|
|
301
|
-
"https://app.example.com"
|
|
302
|
-
);
|
|
303
|
-
});
|
|
304
|
-
|
|
305
|
-
expect(result.current.stylesLoaded).toBe(true);
|
|
306
|
-
});
|
|
307
|
-
|
|
308
|
-
it("should remain false after failed origin validation", () => {
|
|
309
|
-
const { result } = renderHook(() =>
|
|
310
|
-
useStyleUpdates(zeroHashAppURL, defaultStyles)
|
|
311
|
-
);
|
|
312
|
-
|
|
313
|
-
act(() => {
|
|
314
|
-
result.current.handleStyleConfig(
|
|
315
|
-
{ iframeStyle: { borderRadius: "8px" } },
|
|
316
|
-
"https://untrusted.com"
|
|
317
|
-
);
|
|
318
|
-
});
|
|
319
|
-
|
|
320
|
-
expect(result.current.stylesLoaded).toBe(false);
|
|
321
|
-
});
|
|
322
|
-
});
|
|
323
|
-
|
|
324
|
-
describe("timeout fallback", () => {
|
|
325
|
-
it("should set stylesLoaded to true after 4.5 seconds if STYLE_CONFIG is not received", () => {
|
|
326
|
-
const { result } = renderHook(() =>
|
|
327
|
-
useStyleUpdates(zeroHashAppURL, defaultStyles)
|
|
328
|
-
);
|
|
329
|
-
|
|
330
|
-
expect(result.current.stylesLoaded).toBe(false);
|
|
331
|
-
|
|
332
|
-
act(() => {
|
|
333
|
-
jest.advanceTimersByTime(4500);
|
|
334
|
-
});
|
|
335
|
-
|
|
336
|
-
expect(result.current.stylesLoaded).toBe(true);
|
|
337
|
-
});
|
|
338
|
-
|
|
339
|
-
it("should not change stylesLoaded if STYLE_CONFIG is received before timeout", () => {
|
|
340
|
-
const { result } = renderHook(() =>
|
|
341
|
-
useStyleUpdates(zeroHashAppURL, defaultStyles)
|
|
342
|
-
);
|
|
343
|
-
|
|
344
|
-
expect(result.current.stylesLoaded).toBe(false);
|
|
345
|
-
|
|
346
|
-
// Receive STYLE_CONFIG before timeout
|
|
347
|
-
act(() => {
|
|
348
|
-
result.current.handleStyleConfig(
|
|
349
|
-
{ iframeStyle: { borderRadius: "8px" } },
|
|
350
|
-
"https://app.example.com"
|
|
351
|
-
);
|
|
352
|
-
});
|
|
353
|
-
|
|
354
|
-
expect(result.current.stylesLoaded).toBe(true);
|
|
355
|
-
|
|
356
|
-
// Advance timers past the timeout
|
|
357
|
-
act(() => {
|
|
358
|
-
jest.advanceTimersByTime(5000);
|
|
359
|
-
});
|
|
360
|
-
|
|
361
|
-
// Should still be true
|
|
362
|
-
expect(result.current.stylesLoaded).toBe(true);
|
|
363
|
-
});
|
|
364
|
-
|
|
365
|
-
it("should preserve default styles until timeout triggers", () => {
|
|
366
|
-
const { result } = renderHook(() =>
|
|
367
|
-
useStyleUpdates(zeroHashAppURL, defaultStyles)
|
|
368
|
-
);
|
|
369
|
-
|
|
370
|
-
expect(result.current.styles).toEqual(defaultStyles);
|
|
371
|
-
|
|
372
|
-
act(() => {
|
|
373
|
-
jest.advanceTimersByTime(4500);
|
|
374
|
-
});
|
|
375
|
-
|
|
376
|
-
// Styles should remain unchanged (defaults)
|
|
377
|
-
expect(result.current.styles).toEqual(defaultStyles);
|
|
378
|
-
expect(result.current.stylesLoaded).toBe(true);
|
|
379
|
-
});
|
|
380
|
-
|
|
381
|
-
it("should clean up timeout on unmount", () => {
|
|
382
|
-
const clearTimeoutSpy = jest.spyOn(global, "clearTimeout");
|
|
383
|
-
|
|
384
|
-
const { unmount } = renderHook(() =>
|
|
385
|
-
useStyleUpdates(zeroHashAppURL, defaultStyles)
|
|
386
|
-
);
|
|
387
|
-
|
|
388
|
-
unmount();
|
|
389
|
-
|
|
390
|
-
expect(clearTimeoutSpy).toHaveBeenCalled();
|
|
391
|
-
clearTimeoutSpy.mockRestore();
|
|
392
|
-
});
|
|
393
|
-
});
|
|
394
|
-
|
|
395
|
-
describe("origin validation scenarios", () => {
|
|
396
|
-
it("should handle zeroHashAppURL with trailing slash", () => {
|
|
397
|
-
const { result } = renderHook(() =>
|
|
398
|
-
useStyleUpdates("https://app.example.com/", defaultStyles)
|
|
399
|
-
);
|
|
400
|
-
|
|
401
|
-
let success = false;
|
|
402
|
-
act(() => {
|
|
403
|
-
success = result.current.handleStyleConfig(
|
|
404
|
-
{ iframeStyle: { width: "50%" } },
|
|
405
|
-
"https://app.example.com"
|
|
406
|
-
);
|
|
407
|
-
});
|
|
408
|
-
|
|
409
|
-
expect(success).toBe(true);
|
|
410
|
-
expect(result.current.styles.iframeStyle.width).toBe("50%");
|
|
411
|
-
});
|
|
412
|
-
|
|
413
|
-
it("should handle zeroHashAppURL without trailing slash", () => {
|
|
414
|
-
const { result } = renderHook(() =>
|
|
415
|
-
useStyleUpdates("https://app.example.com", defaultStyles)
|
|
416
|
-
);
|
|
417
|
-
|
|
418
|
-
let success = false;
|
|
419
|
-
act(() => {
|
|
420
|
-
success = result.current.handleStyleConfig(
|
|
421
|
-
{ iframeStyle: { width: "50%" } },
|
|
422
|
-
"https://app.example.com"
|
|
423
|
-
);
|
|
424
|
-
});
|
|
425
|
-
|
|
426
|
-
expect(success).toBe(true);
|
|
427
|
-
expect(result.current.styles.iframeStyle.width).toBe("50%");
|
|
428
|
-
});
|
|
429
|
-
});
|
|
430
|
-
});
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import { CSSProperties, useCallback, useEffect, useState } from "react";
|
|
2
|
-
|
|
3
|
-
export type StyleConfig = {
|
|
4
|
-
appWrapperStyle: CSSProperties;
|
|
5
|
-
modalStyle: CSSProperties;
|
|
6
|
-
iframeWrapperStyle: CSSProperties;
|
|
7
|
-
iframeStyle: CSSProperties;
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Hook to manage style state and updates from postMessage events.
|
|
12
|
-
*
|
|
13
|
-
* Encapsulates:
|
|
14
|
-
* - Style state management (current styles and loaded status)
|
|
15
|
-
* - Style merging logic via postMessage
|
|
16
|
-
* - Origin validation
|
|
17
|
-
* - Fallback timeout to ensure modal displays even if STYLE_CONFIG is not received
|
|
18
|
-
*
|
|
19
|
-
* @param zeroHashAppURL - The app URL used for origin validation
|
|
20
|
-
* @param defaultStyles - Default style configuration to use as fallback
|
|
21
|
-
* @returns Object containing current styles, loaded status, and handler function
|
|
22
|
-
*/
|
|
23
|
-
export const useStyleUpdates = (
|
|
24
|
-
zeroHashAppURL: string,
|
|
25
|
-
defaultStyles: StyleConfig,
|
|
26
|
-
) => {
|
|
27
|
-
const [styles, setStyles] = useState<StyleConfig>(defaultStyles);
|
|
28
|
-
const [stylesLoaded, setStylesLoaded] = useState(false);
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Fallback timeout to ensure modal is displayed even if STYLE_CONFIG postMessage
|
|
32
|
-
* is not received or the app crashes before sending it. After 4.5 seconds,
|
|
33
|
-
* if stylesLoaded is still false, we mark it as true to show the modal with default styles.
|
|
34
|
-
*/
|
|
35
|
-
useEffect(() => {
|
|
36
|
-
const timeoutId = setTimeout(() => {
|
|
37
|
-
setStylesLoaded((prevState) => prevState || true);
|
|
38
|
-
}, 4500);
|
|
39
|
-
|
|
40
|
-
return () => clearTimeout(timeoutId);
|
|
41
|
-
}, []);
|
|
42
|
-
|
|
43
|
-
const handleStyleConfig = useCallback(
|
|
44
|
-
(incomingStyles: Partial<StyleConfig>, eventOrigin: string): boolean => {
|
|
45
|
-
const zhAppsURLOrigin = new URL(zeroHashAppURL).origin;
|
|
46
|
-
/**
|
|
47
|
-
* Here we have 2 scenarios, one where the postMessage comes from sdk-ui-apps and another one where
|
|
48
|
-
* the postMessage comes from Connect (Auth).
|
|
49
|
-
* 1. In the first scenario, the eventOrigin will always be the same as zhAppsURLOrigin, which is expected and valid.
|
|
50
|
-
* 2. In the second scenario, the eventOrigin will always be the same as window.location.origin, which is also expected
|
|
51
|
-
* and valid since Connect (Auth) is served from the same origin as the main app (no iframe).
|
|
52
|
-
*/
|
|
53
|
-
const isValidOrigin =
|
|
54
|
-
eventOrigin === zhAppsURLOrigin ||
|
|
55
|
-
eventOrigin === window.location.origin;
|
|
56
|
-
|
|
57
|
-
if (!isValidOrigin) {
|
|
58
|
-
return false;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
setStyles((prev) => ({
|
|
62
|
-
appWrapperStyle: incomingStyles.appWrapperStyle
|
|
63
|
-
? { ...prev.appWrapperStyle, ...incomingStyles.appWrapperStyle }
|
|
64
|
-
: prev.appWrapperStyle,
|
|
65
|
-
modalStyle: incomingStyles.modalStyle
|
|
66
|
-
? { ...prev.modalStyle, ...incomingStyles.modalStyle }
|
|
67
|
-
: prev.modalStyle,
|
|
68
|
-
iframeWrapperStyle: incomingStyles.iframeWrapperStyle
|
|
69
|
-
? { ...prev.iframeWrapperStyle, ...incomingStyles.iframeWrapperStyle }
|
|
70
|
-
: prev.iframeWrapperStyle,
|
|
71
|
-
iframeStyle: incomingStyles.iframeStyle
|
|
72
|
-
? { ...prev.iframeStyle, ...incomingStyles.iframeStyle }
|
|
73
|
-
: prev.iframeStyle,
|
|
74
|
-
}));
|
|
75
|
-
setStylesLoaded(true);
|
|
76
|
-
return true;
|
|
77
|
-
},
|
|
78
|
-
[zeroHashAppURL],
|
|
79
|
-
);
|
|
80
|
-
|
|
81
|
-
return { styles, stylesLoaded, handleStyleConfig };
|
|
82
|
-
};
|