@pushwoosh/smart-components-kit 1.5.2 → 1.6.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/MediaStorage/CanvaImportDrawer.js +18 -42
- package/MediaStorage/MediaStorage.js +56 -15
- package/MediaStorage/canva.d.ts +12 -0
- package/MediaStorage/canva.js +28 -1
- package/MediaStorage/canvaEdit.d.ts +30 -0
- package/MediaStorage/canvaEdit.js +50 -0
- package/MediaStorage/hooks.d.ts +12 -0
- package/MediaStorage/hooks.js +120 -0
- package/MediaStorage/polyglot/messages_ar.js +11 -1
- package/MediaStorage/polyglot/messages_bn.js +11 -1
- package/MediaStorage/polyglot/messages_de.js +11 -1
- package/MediaStorage/polyglot/messages_en.js +11 -1
- package/MediaStorage/polyglot/messages_es.js +11 -1
- package/MediaStorage/polyglot/messages_fr.js +11 -1
- package/MediaStorage/polyglot/messages_he.js +11 -1
- package/MediaStorage/polyglot/messages_hi.js +11 -1
- package/MediaStorage/polyglot/messages_ja.js +11 -1
- package/MediaStorage/polyglot/messages_ko.js +11 -1
- package/MediaStorage/polyglot/messages_pt.js +11 -1
- package/MediaStorage/polyglot/messages_ru.js +11 -1
- package/MediaStorage/polyglot/messages_th.js +11 -1
- package/MediaStorage/polyglot/messages_zh.js +11 -1
- package/MediaStorage/polyglot/types.d.ts +19 -0
- package/MediaStorage/styles.d.ts +1 -0
- package/MediaStorage/styles.js +5 -1
- package/package.json +4 -4
|
@@ -5,18 +5,12 @@ import { FlexContainer, useAsync, Vertical } from '@pushwoosh/kit-helpers';
|
|
|
5
5
|
import { CloseIcon } from '@pushwoosh/kit-icons';
|
|
6
6
|
import { Text } from '@pushwoosh/kit-typography';
|
|
7
7
|
import { useSPAContext } from '@pushwoosh/spa-context';
|
|
8
|
-
import { ConsentClosedError, connectCanva, disconnectCanva, PopupBlockedError, UnsafeReturnPageError } from './canva';
|
|
8
|
+
import { ConsentClosedError, connectCanva, disconnectCanva, errorMessage, PopupBlockedError, UnsafeReturnPageError, waitForImport } from './canva';
|
|
9
9
|
import { togglePages } from './canvaPages';
|
|
10
10
|
import { useLang } from './polyglot';
|
|
11
11
|
import { Chips, DesignCaption, DesignTile, EmptyState, FieldLabel, Grid, Segment, SegmentItem, TileImage } from './styles';
|
|
12
12
|
const MAX_PAGES = 10;
|
|
13
13
|
const SEARCH_DELAY_MS = 400;
|
|
14
|
-
const POLL_INTERVAL_MS = 1500;
|
|
15
|
-
const IMPORT_TIMEOUT_MS = 10 * 60 * 1000;
|
|
16
|
-
const errorMessage = (error, fallback) => error instanceof Error && error.message ? error.message : fallback;
|
|
17
|
-
const sleep = ms => new Promise(resolve => {
|
|
18
|
-
window.setTimeout(resolve, ms);
|
|
19
|
-
});
|
|
20
14
|
/** Drawer that connects the user's Canva and imports pages of a chosen design into the library. */
|
|
21
15
|
export const CanvaImportDrawer = ({
|
|
22
16
|
application,
|
|
@@ -162,41 +156,23 @@ export const CanvaImportDrawer = ({
|
|
|
162
156
|
pages,
|
|
163
157
|
format
|
|
164
158
|
});
|
|
165
|
-
const
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
openToast({
|
|
183
|
-
title: lang({
|
|
184
|
-
message: 'SMART.MEDIA_STORAGE.CANVA.SUCCESS'
|
|
185
|
-
}),
|
|
186
|
-
type: 'success'
|
|
187
|
-
});
|
|
188
|
-
onImported(state.files ?? []);
|
|
189
|
-
if (isOpenRef.current) onClose();
|
|
190
|
-
return;
|
|
191
|
-
}
|
|
192
|
-
if (state.state === 'CANVA_IMPORT_STATE_UPLOADING') {
|
|
193
|
-
setProgress(lang({
|
|
194
|
-
message: 'SMART.MEDIA_STORAGE.CANVA.IMPORTING',
|
|
195
|
-
done: state.pagesDone,
|
|
196
|
-
total: state.pagesTotal
|
|
197
|
-
}));
|
|
198
|
-
}
|
|
199
|
-
}
|
|
159
|
+
const files = await waitForImport(rpcGateway, importId, {
|
|
160
|
+
isCancelled: () => runRef.current !== run,
|
|
161
|
+
onProgress: (done, total) => setProgress(lang({
|
|
162
|
+
message: 'SMART.MEDIA_STORAGE.CANVA.IMPORTING',
|
|
163
|
+
done,
|
|
164
|
+
total
|
|
165
|
+
}))
|
|
166
|
+
});
|
|
167
|
+
if (!files) return;
|
|
168
|
+
openToast({
|
|
169
|
+
title: lang({
|
|
170
|
+
message: 'SMART.MEDIA_STORAGE.CANVA.SUCCESS'
|
|
171
|
+
}),
|
|
172
|
+
type: 'success'
|
|
173
|
+
});
|
|
174
|
+
onImported(files);
|
|
175
|
+
if (isOpenRef.current) onClose();
|
|
200
176
|
} catch (error) {
|
|
201
177
|
if (runRef.current === run) {
|
|
202
178
|
openToast({
|
|
@@ -2,15 +2,16 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
2
2
|
import { useEffect, useRef, useState } from 'react';
|
|
3
3
|
import { Button, Checkbox, DropdownMenuButton, DropdownMenuItem, DropdownMenuSection, ModalConfirm, useToast } from '@pushwoosh/dumb-components';
|
|
4
4
|
import { FlexContainer, useAsync } from '@pushwoosh/kit-helpers';
|
|
5
|
-
import { CheckIcon, EditIcon, TrashIcon, UploadIcon } from '@pushwoosh/kit-icons';
|
|
5
|
+
import { CheckIcon, DropdownIcon, EditIcon, OpenIcon, TrashIcon, UploadIcon } from '@pushwoosh/kit-icons';
|
|
6
6
|
import { Text } from '@pushwoosh/kit-typography';
|
|
7
7
|
import { useSPAContext } from '@pushwoosh/spa-context';
|
|
8
|
+
import { CANVA_DESIGN_PRESETS } from './canvaEdit';
|
|
8
9
|
import { CanvaImportDrawer } from './CanvaImportDrawer';
|
|
9
10
|
import { CreateCropDrawer } from './CreateCropDrawer';
|
|
10
|
-
import { useDeleteMediaFile, useDeleteMediaFiles } from './hooks';
|
|
11
|
+
import { useCanvaEdit, useDeleteMediaFile, useDeleteMediaFiles } from './hooks';
|
|
11
12
|
import { formatBytes, getCropCaption, getSourceLabel, getThumbUrl, hasVersions } from './mediaFile.utils';
|
|
12
13
|
import { Lang, useLang } from './polyglot';
|
|
13
|
-
import { CountBadge, Dropzone, DropzoneRow, EmptyState, Grid, HiddenInput, SelectionBar, SelectionCount, SourceBadge, Tile, TileActions, TileBadges, TileCheckbox, TileImage, UsageLine, WarningBadge } from './styles';
|
|
14
|
+
import { CanvaActions, CountBadge, Dropzone, DropzoneRow, EmptyState, Grid, HiddenInput, SelectionBar, SelectionCount, SourceBadge, Tile, TileActions, TileBadges, TileCheckbox, TileImage, UsageLine, WarningBadge } from './styles';
|
|
14
15
|
const UPLOAD_PATH = '/api/media/upload';
|
|
15
16
|
const ALLOWED_IMAGE_EXTENSIONS = ['.jpg', '.jpeg', '.png', '.gif', '.webp'];
|
|
16
17
|
const isAllowedImage = file => {
|
|
@@ -85,6 +86,14 @@ export const MediaStorage = ({
|
|
|
85
86
|
const [isCanvaOpen, setIsCanvaOpen] = useState(false);
|
|
86
87
|
const canvaStatusAsync = useAsync(() => rpcGateway.canva.GetStatus({}), [rpcGateway, canvaToken]);
|
|
87
88
|
const canvaStatus = canvaStatusAsync.value;
|
|
89
|
+
const isCanvaReady = Boolean(canvaStatus?.available && canvaStatus.connected && canvaStatus.tokenValid);
|
|
90
|
+
const showImportedFirst = () => {
|
|
91
|
+
if (pageRef.current !== 0) {
|
|
92
|
+
onPageChange(0);
|
|
93
|
+
}
|
|
94
|
+
setReloadToken(token => token + 1);
|
|
95
|
+
};
|
|
96
|
+
const canvaEdit = useCanvaEdit(application, Boolean(canvaStatus?.available), showImportedFirst);
|
|
88
97
|
const {
|
|
89
98
|
loading
|
|
90
99
|
} = listAsync;
|
|
@@ -271,12 +280,35 @@ export const MediaStorage = ({
|
|
|
271
280
|
}) : lang({
|
|
272
281
|
message: 'SMART.MEDIA_STORAGE.DROPZONE_HINT'
|
|
273
282
|
})]
|
|
274
|
-
}), canvaStatus?.available &&
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
283
|
+
}), canvaStatus?.available && _jsxs(CanvaActions, {
|
|
284
|
+
children: [_jsx(Button, {
|
|
285
|
+
color: "secondary",
|
|
286
|
+
onClick: () => setIsCanvaOpen(true),
|
|
287
|
+
children: lang({
|
|
288
|
+
message: 'SMART.MEDIA_STORAGE.CANVA.BUTTON'
|
|
289
|
+
})
|
|
290
|
+
}), isCanvaReady && _jsx(DropdownMenuButton, {
|
|
291
|
+
color: "secondary",
|
|
292
|
+
label: lang({
|
|
293
|
+
message: 'SMART.MEDIA_STORAGE.CANVA.CREATE'
|
|
294
|
+
}),
|
|
295
|
+
rightIcon: _jsx(DropdownIcon, {
|
|
296
|
+
direction: "down",
|
|
297
|
+
size: "small"
|
|
298
|
+
}),
|
|
299
|
+
isLoading: canvaEdit.isSaving,
|
|
300
|
+
menuPlacement: "bottom-end",
|
|
301
|
+
children: _jsx(DropdownMenuSection, {
|
|
302
|
+
children: CANVA_DESIGN_PRESETS.map(preset => _jsx(DropdownMenuItem, {
|
|
303
|
+
onClick: () => void canvaEdit.create(preset),
|
|
304
|
+
children: lang({
|
|
305
|
+
message: preset.messageKey,
|
|
306
|
+
width: preset.width,
|
|
307
|
+
height: preset.height
|
|
308
|
+
})
|
|
309
|
+
}, preset.messageKey))
|
|
310
|
+
})
|
|
311
|
+
})]
|
|
280
312
|
})]
|
|
281
313
|
}), _jsx(HiddenInput, {
|
|
282
314
|
ref: uploadInputRef,
|
|
@@ -399,6 +431,20 @@ export const MediaStorage = ({
|
|
|
399
431
|
message: 'SMART.MEDIA_STORAGE.CREATE_CROP_HINT'
|
|
400
432
|
}),
|
|
401
433
|
onClick: () => setCreateCropFor(file)
|
|
434
|
+
}), isCanvaReady && _jsx(Button, {
|
|
435
|
+
color: "secondary",
|
|
436
|
+
size: "compact",
|
|
437
|
+
icon: _jsx(OpenIcon, {
|
|
438
|
+
size: "small",
|
|
439
|
+
view: "lined"
|
|
440
|
+
}),
|
|
441
|
+
title: lang({
|
|
442
|
+
message: 'SMART.MEDIA_STORAGE.CANVA.EDIT'
|
|
443
|
+
}),
|
|
444
|
+
"aria-label": lang({
|
|
445
|
+
message: 'SMART.MEDIA_STORAGE.CANVA.EDIT'
|
|
446
|
+
}),
|
|
447
|
+
onClick: () => void canvaEdit.edit(file)
|
|
402
448
|
}), _jsx(Button, {
|
|
403
449
|
color: "secondary",
|
|
404
450
|
size: "compact",
|
|
@@ -457,12 +503,7 @@ export const MediaStorage = ({
|
|
|
457
503
|
status: canvaStatus,
|
|
458
504
|
onStatusChange: () => setCanvaToken(token => token + 1),
|
|
459
505
|
onClose: () => setIsCanvaOpen(false),
|
|
460
|
-
onImported:
|
|
461
|
-
if (pageRef.current !== 0) {
|
|
462
|
-
onPageChange(0);
|
|
463
|
-
}
|
|
464
|
-
setReloadToken(token => token + 1);
|
|
465
|
-
}
|
|
506
|
+
onImported: showImportedFirst
|
|
466
507
|
}), _jsx(CreateCropDrawer, {
|
|
467
508
|
application: application,
|
|
468
509
|
original: createCropFor,
|
package/MediaStorage/canva.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { API as RpcGatewayAPI } from '@pushwoosh/rpc-v2-http-api-data';
|
|
2
|
+
import type { MediaFile } from '@pushwoosh/rpc-v2-http-api-data/media_files';
|
|
2
3
|
/** Error raised when the browser refused to open the Canva consent window. */
|
|
3
4
|
export declare class PopupBlockedError extends Error {
|
|
4
5
|
}
|
|
@@ -16,3 +17,14 @@ export declare const isStaticText: (contentType: string | null) => boolean;
|
|
|
16
17
|
export declare const connectCanva: (rpcGateway: RpcGatewayAPI) => Promise<void>;
|
|
17
18
|
/** Revokes and forgets the signed-in user's Canva connection. */
|
|
18
19
|
export declare const disconnectCanva: (rpcGateway: RpcGatewayAPI) => Promise<unknown>;
|
|
20
|
+
/** Error raised when an import is still not stored after the polling window. */
|
|
21
|
+
export declare class ImportTimeoutError extends Error {
|
|
22
|
+
}
|
|
23
|
+
export declare const errorMessage: (error: unknown, fallback: string) => string;
|
|
24
|
+
type WaitOptions = {
|
|
25
|
+
isCancelled: () => boolean;
|
|
26
|
+
onProgress?: (done: number, total: number) => void;
|
|
27
|
+
};
|
|
28
|
+
/** Polls a Canva import until it is stored; null when the caller cancelled. */
|
|
29
|
+
export declare const waitForImport: (rpcGateway: RpcGatewayAPI, importId: string, { isCancelled, onProgress }: WaitOptions) => Promise<MediaFile[] | null>;
|
|
30
|
+
export {};
|
package/MediaStorage/canva.js
CHANGED
|
@@ -83,4 +83,31 @@ export const connectCanva = async rpcGateway => {
|
|
|
83
83
|
/** Revokes and forgets the signed-in user's Canva connection. */
|
|
84
84
|
export const disconnectCanva = rpcGateway => rpcGateway.integrations.DeleteOAuthIntegration({
|
|
85
85
|
provider: PROVIDER
|
|
86
|
-
});
|
|
86
|
+
});
|
|
87
|
+
const IMPORT_POLL_INTERVAL_MS = 1500;
|
|
88
|
+
const IMPORT_TIMEOUT_MS = 10 * 60 * 1000;
|
|
89
|
+
/** Error raised when an import is still not stored after the polling window. */
|
|
90
|
+
export class ImportTimeoutError extends Error {}
|
|
91
|
+
export const errorMessage = (error, fallback) => error instanceof Error && error.message ? error.message : fallback;
|
|
92
|
+
const sleep = ms => new Promise(resolve => {
|
|
93
|
+
setTimeout(resolve, ms);
|
|
94
|
+
});
|
|
95
|
+
/** Polls a Canva import until it is stored; null when the caller cancelled. */
|
|
96
|
+
export const waitForImport = async (rpcGateway, importId, {
|
|
97
|
+
isCancelled,
|
|
98
|
+
onProgress
|
|
99
|
+
}) => {
|
|
100
|
+
const startedAt = Date.now();
|
|
101
|
+
for (;;) {
|
|
102
|
+
await sleep(IMPORT_POLL_INTERVAL_MS);
|
|
103
|
+
if (isCancelled()) return null;
|
|
104
|
+
if (Date.now() - startedAt > IMPORT_TIMEOUT_MS) throw new ImportTimeoutError();
|
|
105
|
+
const state = await rpcGateway.canva.GetImport({
|
|
106
|
+
importId
|
|
107
|
+
});
|
|
108
|
+
if (isCancelled()) return null;
|
|
109
|
+
if (state.state === 'CANVA_IMPORT_STATE_FAILED') throw new Error(state.error);
|
|
110
|
+
if (state.state === 'CANVA_IMPORT_STATE_DONE') return state.files ?? [];
|
|
111
|
+
if (state.state === 'CANVA_IMPORT_STATE_UPLOADING') onProgress?.(state.pagesDone, state.pagesTotal);
|
|
112
|
+
}
|
|
113
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { API as RpcGatewayAPI } from '@pushwoosh/rpc-v2-http-api-data';
|
|
2
|
+
import type { StartCanvaEditRequest } from '@pushwoosh/rpc-v2-http-api-data/canva';
|
|
3
|
+
/** Query parameter our Canva return page adds to the control panel URL. */
|
|
4
|
+
export declare const CANVA_RETURN_PARAM = "canva_return";
|
|
5
|
+
/** Sizes offered for a new Canva design, per channel. */
|
|
6
|
+
export declare const CANVA_DESIGN_PRESETS: readonly [{
|
|
7
|
+
readonly messageKey: "SMART.MEDIA_STORAGE.CANVA.PRESET_PUSH";
|
|
8
|
+
readonly width: 1024;
|
|
9
|
+
readonly height: 512;
|
|
10
|
+
}, {
|
|
11
|
+
readonly messageKey: "SMART.MEDIA_STORAGE.CANVA.PRESET_INAPP";
|
|
12
|
+
readonly width: 1080;
|
|
13
|
+
readonly height: 1920;
|
|
14
|
+
}, {
|
|
15
|
+
readonly messageKey: "SMART.MEDIA_STORAGE.CANVA.PRESET_EMAIL";
|
|
16
|
+
readonly width: 600;
|
|
17
|
+
readonly height: 300;
|
|
18
|
+
}];
|
|
19
|
+
export type CanvaDesignPreset = (typeof CANVA_DESIGN_PRESETS)[number];
|
|
20
|
+
/** The Media Library page an edit comes back to, wherever the picker was opened. */
|
|
21
|
+
export declare const mediaLibraryUrl: (origin: string, application: string) => string;
|
|
22
|
+
/** Reads the token Canva sent the user back with and drops it from the address bar, so a reload does not replay it. */
|
|
23
|
+
export declare const takeCanvaReturn: (location: Pick<Location, "href">, history: Pick<History, "replaceState" | "state">) => string | null;
|
|
24
|
+
/**
|
|
25
|
+
* Opens Canva's editor in a new tab. The tab is opened before the request so the browser treats it
|
|
26
|
+
* as the user's click; Canva later brings that tab back to the Media Library.
|
|
27
|
+
*/
|
|
28
|
+
export declare const openInCanva: (rpcGateway: RpcGatewayAPI, request: StartCanvaEditRequest) => Promise<{
|
|
29
|
+
copied: boolean;
|
|
30
|
+
}>;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { PopupBlockedError } from './canva';
|
|
2
|
+
/** Query parameter our Canva return page adds to the control panel URL. */
|
|
3
|
+
export const CANVA_RETURN_PARAM = 'canva_return';
|
|
4
|
+
/** Sizes offered for a new Canva design, per channel. */
|
|
5
|
+
export const CANVA_DESIGN_PRESETS = [{
|
|
6
|
+
messageKey: 'SMART.MEDIA_STORAGE.CANVA.PRESET_PUSH',
|
|
7
|
+
width: 1024,
|
|
8
|
+
height: 512
|
|
9
|
+
}, {
|
|
10
|
+
messageKey: 'SMART.MEDIA_STORAGE.CANVA.PRESET_INAPP',
|
|
11
|
+
width: 1080,
|
|
12
|
+
height: 1920
|
|
13
|
+
}, {
|
|
14
|
+
messageKey: 'SMART.MEDIA_STORAGE.CANVA.PRESET_EMAIL',
|
|
15
|
+
width: 600,
|
|
16
|
+
height: 300
|
|
17
|
+
}];
|
|
18
|
+
/** The Media Library page an edit comes back to, wherever the picker was opened. */
|
|
19
|
+
export const mediaLibraryUrl = (origin, application) => `${origin}/applications/${encodeURIComponent(application)}/content/media-storage`;
|
|
20
|
+
/** Reads the token Canva sent the user back with and drops it from the address bar, so a reload does not replay it. */
|
|
21
|
+
export const takeCanvaReturn = (location, history) => {
|
|
22
|
+
const url = new URL(location.href);
|
|
23
|
+
const token = url.searchParams.get(CANVA_RETURN_PARAM);
|
|
24
|
+
if (!token) return null;
|
|
25
|
+
url.searchParams.delete(CANVA_RETURN_PARAM);
|
|
26
|
+
history.replaceState(history.state, '', url.toString());
|
|
27
|
+
return token;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Opens Canva's editor in a new tab. The tab is opened before the request so the browser treats it
|
|
31
|
+
* as the user's click; Canva later brings that tab back to the Media Library.
|
|
32
|
+
*/
|
|
33
|
+
export const openInCanva = async (rpcGateway, request) => {
|
|
34
|
+
const tab = window.open('', '_blank');
|
|
35
|
+
if (!tab) throw new PopupBlockedError();
|
|
36
|
+
try {
|
|
37
|
+
const {
|
|
38
|
+
editUrl,
|
|
39
|
+
copied
|
|
40
|
+
} = await rpcGateway.canva.StartEdit(request);
|
|
41
|
+
tab.opener = null;
|
|
42
|
+
tab.location.href = editUrl;
|
|
43
|
+
return {
|
|
44
|
+
copied
|
|
45
|
+
};
|
|
46
|
+
} catch (error) {
|
|
47
|
+
tab.close();
|
|
48
|
+
throw error;
|
|
49
|
+
}
|
|
50
|
+
};
|
package/MediaStorage/hooks.d.ts
CHANGED
|
@@ -1,4 +1,16 @@
|
|
|
1
|
+
import type { MediaFile } from '@pushwoosh/rpc-v2-http-api-data/media_files';
|
|
2
|
+
import { type CanvaDesignPreset } from './canvaEdit';
|
|
1
3
|
/** Deletes one media file with its own toast; resolves to `true` on success. */
|
|
2
4
|
export declare function useDeleteMediaFile(application: string): (uuid: string) => Promise<boolean>;
|
|
3
5
|
/** Deletes media files in a bounded-concurrency batch; resolves to the number deleted. */
|
|
4
6
|
export declare function useDeleteMediaFiles(application: string): (uuids: string[]) => Promise<number>;
|
|
7
|
+
type CanvaEdit = {
|
|
8
|
+
/** Opens an image of the library in Canva; the result comes back as its new version. */
|
|
9
|
+
edit: (file: MediaFile) => Promise<void>;
|
|
10
|
+
/** Opens a blank Canva design of a preset size; the result comes back as a new image. */
|
|
11
|
+
create: (preset: CanvaDesignPreset) => Promise<void>;
|
|
12
|
+
isSaving: boolean;
|
|
13
|
+
};
|
|
14
|
+
/** Sends images to Canva and, on the page Canva returns to, stores what the user brought back. */
|
|
15
|
+
export declare function useCanvaEdit(application: string, isAvailable: boolean, onSaved: () => void): CanvaEdit;
|
|
16
|
+
export {};
|
package/MediaStorage/hooks.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
import { useEffect, useRef, useState } from 'react';
|
|
1
2
|
import { useToast } from '@pushwoosh/dumb-components';
|
|
2
3
|
import { usePersistentFunction } from '@pushwoosh/kit-helpers';
|
|
3
4
|
import { useSPAContext } from '@pushwoosh/spa-context';
|
|
5
|
+
import { errorMessage, PopupBlockedError, waitForImport } from './canva';
|
|
6
|
+
import { mediaLibraryUrl, openInCanva, takeCanvaReturn } from './canvaEdit';
|
|
4
7
|
import { useLang } from './polyglot';
|
|
5
8
|
/** Deletes one media file with its own toast; resolves to `true` on success. */
|
|
6
9
|
export function useDeleteMediaFile(application) {
|
|
@@ -84,4 +87,121 @@ export function useDeleteMediaFiles(application) {
|
|
|
84
87
|
}
|
|
85
88
|
return deleted;
|
|
86
89
|
});
|
|
90
|
+
}
|
|
91
|
+
/** Sends images to Canva and, on the page Canva returns to, stores what the user brought back. */
|
|
92
|
+
export function useCanvaEdit(application, isAvailable, onSaved) {
|
|
93
|
+
const {
|
|
94
|
+
rpcGateway
|
|
95
|
+
} = useSPAContext();
|
|
96
|
+
const {
|
|
97
|
+
openToast
|
|
98
|
+
} = useToast();
|
|
99
|
+
const lang = useLang();
|
|
100
|
+
const [isSaving, setIsSaving] = useState(false);
|
|
101
|
+
const mountedRef = useRef(false);
|
|
102
|
+
const returnTokenRef = useRef(null);
|
|
103
|
+
const handleSaved = usePersistentFunction(onSaved);
|
|
104
|
+
useEffect(() => {
|
|
105
|
+
mountedRef.current = true;
|
|
106
|
+
return () => {
|
|
107
|
+
mountedRef.current = false;
|
|
108
|
+
};
|
|
109
|
+
}, []);
|
|
110
|
+
useEffect(() => {
|
|
111
|
+
returnTokenRef.current ??= takeCanvaReturn(window.location, window.history);
|
|
112
|
+
}, []);
|
|
113
|
+
const fail = (error, fallback) => {
|
|
114
|
+
const title = error instanceof PopupBlockedError ? lang({
|
|
115
|
+
message: 'SMART.MEDIA_STORAGE.CANVA.POPUP_BLOCKED'
|
|
116
|
+
}) : errorMessage(error, lang({
|
|
117
|
+
message: fallback
|
|
118
|
+
}));
|
|
119
|
+
openToast({
|
|
120
|
+
title,
|
|
121
|
+
type: 'error'
|
|
122
|
+
});
|
|
123
|
+
};
|
|
124
|
+
useEffect(() => {
|
|
125
|
+
if (!isAvailable) return;
|
|
126
|
+
const token = returnTokenRef.current;
|
|
127
|
+
if (!token) return;
|
|
128
|
+
returnTokenRef.current = null;
|
|
129
|
+
setIsSaving(true);
|
|
130
|
+
openToast({
|
|
131
|
+
title: lang({
|
|
132
|
+
message: 'SMART.MEDIA_STORAGE.CANVA.SAVING'
|
|
133
|
+
}),
|
|
134
|
+
type: 'info'
|
|
135
|
+
});
|
|
136
|
+
void (async () => {
|
|
137
|
+
try {
|
|
138
|
+
const {
|
|
139
|
+
importId
|
|
140
|
+
} = await rpcGateway.canva.CompleteEdit({
|
|
141
|
+
correlationJwt: token
|
|
142
|
+
});
|
|
143
|
+
const files = await waitForImport(rpcGateway, importId, {
|
|
144
|
+
isCancelled: () => !mountedRef.current
|
|
145
|
+
});
|
|
146
|
+
if (!files) return;
|
|
147
|
+
openToast({
|
|
148
|
+
title: lang({
|
|
149
|
+
message: 'SMART.MEDIA_STORAGE.CANVA.SAVED'
|
|
150
|
+
}),
|
|
151
|
+
type: 'success'
|
|
152
|
+
});
|
|
153
|
+
handleSaved();
|
|
154
|
+
} catch (error) {
|
|
155
|
+
if (mountedRef.current) fail(error, 'SMART.MEDIA_STORAGE.CANVA.SAVE_ERROR');
|
|
156
|
+
} finally {
|
|
157
|
+
if (mountedRef.current) setIsSaving(false);
|
|
158
|
+
}
|
|
159
|
+
})();
|
|
160
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
161
|
+
}, [isAvailable]);
|
|
162
|
+
const returnUrl = mediaLibraryUrl(window.location.origin, application);
|
|
163
|
+
const edit = usePersistentFunction(async file => {
|
|
164
|
+
try {
|
|
165
|
+
const {
|
|
166
|
+
copied
|
|
167
|
+
} = await openInCanva(rpcGateway, {
|
|
168
|
+
application,
|
|
169
|
+
target: {
|
|
170
|
+
type: 'mediaUuid',
|
|
171
|
+
data: file.uuid
|
|
172
|
+
},
|
|
173
|
+
returnUrl
|
|
174
|
+
});
|
|
175
|
+
if (copied) openToast({
|
|
176
|
+
title: lang({
|
|
177
|
+
message: 'SMART.MEDIA_STORAGE.CANVA.EDIT_COPY'
|
|
178
|
+
}),
|
|
179
|
+
type: 'info'
|
|
180
|
+
});
|
|
181
|
+
} catch (error) {
|
|
182
|
+
fail(error, 'SMART.MEDIA_STORAGE.CANVA.EDIT_ERROR');
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
const create = usePersistentFunction(async preset => {
|
|
186
|
+
try {
|
|
187
|
+
await openInCanva(rpcGateway, {
|
|
188
|
+
application,
|
|
189
|
+
target: {
|
|
190
|
+
type: 'size',
|
|
191
|
+
data: {
|
|
192
|
+
width: preset.width,
|
|
193
|
+
height: preset.height
|
|
194
|
+
}
|
|
195
|
+
},
|
|
196
|
+
returnUrl
|
|
197
|
+
});
|
|
198
|
+
} catch (error) {
|
|
199
|
+
fail(error, 'SMART.MEDIA_STORAGE.CANVA.EDIT_ERROR');
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
return {
|
|
203
|
+
edit,
|
|
204
|
+
create,
|
|
205
|
+
isSaving
|
|
206
|
+
};
|
|
87
207
|
}
|
|
@@ -69,5 +69,15 @@ export const messages = {
|
|
|
69
69
|
'SMART.MEDIA_STORAGE.CANVA.SUCCESS': 'تم الاستيراد من Canva',
|
|
70
70
|
'SMART.MEDIA_STORAGE.CANVA.POPUP_BLOCKED': 'اسمح بالنوافذ المنبثقة لهذا الموقع لربط Canva',
|
|
71
71
|
'SMART.MEDIA_STORAGE.CANVA.CONNECT_FAILED': 'تعذّر ربط Canva',
|
|
72
|
-
'SMART.MEDIA_STORAGE.CANVA.ERROR': 'تعذّر الاستيراد من Canva'
|
|
72
|
+
'SMART.MEDIA_STORAGE.CANVA.ERROR': 'تعذّر الاستيراد من Canva',
|
|
73
|
+
'SMART.MEDIA_STORAGE.CANVA.EDIT': 'التحرير في Canva',
|
|
74
|
+
'SMART.MEDIA_STORAGE.CANVA.CREATE': 'الإنشاء في Canva',
|
|
75
|
+
'SMART.MEDIA_STORAGE.CANVA.PRESET_PUSH': 'صورة الإشعار الكبيرة · {{width}}×{{height}}',
|
|
76
|
+
'SMART.MEDIA_STORAGE.CANVA.PRESET_INAPP': 'داخل التطبيق / Rich Media · {{width}}×{{height}}',
|
|
77
|
+
'SMART.MEDIA_STORAGE.CANVA.PRESET_EMAIL': 'رأس البريد الإلكتروني · {{width}}×{{height}}',
|
|
78
|
+
'SMART.MEDIA_STORAGE.CANVA.SAVING': 'جارٍ حفظ تصميمك من Canva…',
|
|
79
|
+
'SMART.MEDIA_STORAGE.CANVA.SAVED': 'تم الحفظ من Canva',
|
|
80
|
+
'SMART.MEDIA_STORAGE.CANVA.EDIT_COPY': 'تصميم Canva لهذه الصورة يخص مستخدمًا آخر — أنت تحرر نسخة',
|
|
81
|
+
'SMART.MEDIA_STORAGE.CANVA.EDIT_ERROR': 'تعذّر فتح Canva',
|
|
82
|
+
'SMART.MEDIA_STORAGE.CANVA.SAVE_ERROR': 'تعذّر حفظ التصميم من Canva'
|
|
73
83
|
};
|
|
@@ -69,5 +69,15 @@ export const messages = {
|
|
|
69
69
|
'SMART.MEDIA_STORAGE.CANVA.SUCCESS': 'Canva থেকে ইমপোর্ট হয়েছে',
|
|
70
70
|
'SMART.MEDIA_STORAGE.CANVA.POPUP_BLOCKED': 'Canva সংযুক্ত করতে এই সাইটের জন্য পপ-আপ অনুমতি দিন',
|
|
71
71
|
'SMART.MEDIA_STORAGE.CANVA.CONNECT_FAILED': 'Canva সংযুক্ত করা যায়নি',
|
|
72
|
-
'SMART.MEDIA_STORAGE.CANVA.ERROR': 'Canva থেকে ইমপোর্ট ব্যর্থ হয়েছে'
|
|
72
|
+
'SMART.MEDIA_STORAGE.CANVA.ERROR': 'Canva থেকে ইমপোর্ট ব্যর্থ হয়েছে',
|
|
73
|
+
'SMART.MEDIA_STORAGE.CANVA.EDIT': 'Canva-তে এডিট করুন',
|
|
74
|
+
'SMART.MEDIA_STORAGE.CANVA.CREATE': 'Canva-তে তৈরি করুন',
|
|
75
|
+
'SMART.MEDIA_STORAGE.CANVA.PRESET_PUSH': 'পুশের বড় ছবি · {{width}}×{{height}}',
|
|
76
|
+
'SMART.MEDIA_STORAGE.CANVA.PRESET_INAPP': 'ইন-অ্যাপ / রিচ মিডিয়া · {{width}}×{{height}}',
|
|
77
|
+
'SMART.MEDIA_STORAGE.CANVA.PRESET_EMAIL': 'ইমেল হেডার · {{width}}×{{height}}',
|
|
78
|
+
'SMART.MEDIA_STORAGE.CANVA.SAVING': 'Canva থেকে আপনার ডিজাইন সংরক্ষণ করা হচ্ছে…',
|
|
79
|
+
'SMART.MEDIA_STORAGE.CANVA.SAVED': 'Canva থেকে সংরক্ষিত হয়েছে',
|
|
80
|
+
'SMART.MEDIA_STORAGE.CANVA.EDIT_COPY': 'এই ছবির Canva ডিজাইনটি অন্য কারও — আপনি একটি কপি এডিট করছেন',
|
|
81
|
+
'SMART.MEDIA_STORAGE.CANVA.EDIT_ERROR': 'Canva খোলা যায়নি',
|
|
82
|
+
'SMART.MEDIA_STORAGE.CANVA.SAVE_ERROR': 'Canva থেকে ডিজাইন সংরক্ষণ করা যায়নি'
|
|
73
83
|
};
|
|
@@ -69,5 +69,15 @@ export const messages = {
|
|
|
69
69
|
'SMART.MEDIA_STORAGE.CANVA.SUCCESS': 'Aus Canva importiert',
|
|
70
70
|
'SMART.MEDIA_STORAGE.CANVA.POPUP_BLOCKED': 'Erlauben Sie Pop-ups für diese Website, um Canva zu verbinden',
|
|
71
71
|
'SMART.MEDIA_STORAGE.CANVA.CONNECT_FAILED': 'Canva konnte nicht verbunden werden',
|
|
72
|
-
'SMART.MEDIA_STORAGE.CANVA.ERROR': 'Canva-Import fehlgeschlagen'
|
|
72
|
+
'SMART.MEDIA_STORAGE.CANVA.ERROR': 'Canva-Import fehlgeschlagen',
|
|
73
|
+
'SMART.MEDIA_STORAGE.CANVA.EDIT': 'In Canva bearbeiten',
|
|
74
|
+
'SMART.MEDIA_STORAGE.CANVA.CREATE': 'In Canva erstellen',
|
|
75
|
+
'SMART.MEDIA_STORAGE.CANVA.PRESET_PUSH': 'Großes Push-Bild · {{width}}×{{height}}',
|
|
76
|
+
'SMART.MEDIA_STORAGE.CANVA.PRESET_INAPP': 'In-App / Rich Media · {{width}}×{{height}}',
|
|
77
|
+
'SMART.MEDIA_STORAGE.CANVA.PRESET_EMAIL': 'E-Mail-Header · {{width}}×{{height}}',
|
|
78
|
+
'SMART.MEDIA_STORAGE.CANVA.SAVING': 'Design aus Canva wird gespeichert…',
|
|
79
|
+
'SMART.MEDIA_STORAGE.CANVA.SAVED': 'Aus Canva gespeichert',
|
|
80
|
+
'SMART.MEDIA_STORAGE.CANVA.EDIT_COPY': 'Das Canva-Design dieses Bildes gehört jemand anderem — Sie bearbeiten eine Kopie',
|
|
81
|
+
'SMART.MEDIA_STORAGE.CANVA.EDIT_ERROR': 'Canva konnte nicht geöffnet werden',
|
|
82
|
+
'SMART.MEDIA_STORAGE.CANVA.SAVE_ERROR': 'Design aus Canva konnte nicht gespeichert werden'
|
|
73
83
|
};
|
|
@@ -69,5 +69,15 @@ export const messages = {
|
|
|
69
69
|
'SMART.MEDIA_STORAGE.CANVA.SUCCESS': 'Imported from Canva',
|
|
70
70
|
'SMART.MEDIA_STORAGE.CANVA.POPUP_BLOCKED': 'Allow pop-ups for this site to connect Canva',
|
|
71
71
|
'SMART.MEDIA_STORAGE.CANVA.CONNECT_FAILED': 'Could not connect Canva',
|
|
72
|
-
'SMART.MEDIA_STORAGE.CANVA.ERROR': 'Canva import failed'
|
|
72
|
+
'SMART.MEDIA_STORAGE.CANVA.ERROR': 'Canva import failed',
|
|
73
|
+
'SMART.MEDIA_STORAGE.CANVA.EDIT': 'Edit in Canva',
|
|
74
|
+
'SMART.MEDIA_STORAGE.CANVA.CREATE': 'Create in Canva',
|
|
75
|
+
'SMART.MEDIA_STORAGE.CANVA.PRESET_PUSH': 'Push big picture · {{width}}×{{height}}',
|
|
76
|
+
'SMART.MEDIA_STORAGE.CANVA.PRESET_INAPP': 'In-app / Rich Media · {{width}}×{{height}}',
|
|
77
|
+
'SMART.MEDIA_STORAGE.CANVA.PRESET_EMAIL': 'Email header · {{width}}×{{height}}',
|
|
78
|
+
'SMART.MEDIA_STORAGE.CANVA.SAVING': 'Saving your design from Canva…',
|
|
79
|
+
'SMART.MEDIA_STORAGE.CANVA.SAVED': 'Saved from Canva',
|
|
80
|
+
'SMART.MEDIA_STORAGE.CANVA.EDIT_COPY': 'This image’s Canva design belongs to someone else — you are editing a copy',
|
|
81
|
+
'SMART.MEDIA_STORAGE.CANVA.EDIT_ERROR': 'Could not open Canva',
|
|
82
|
+
'SMART.MEDIA_STORAGE.CANVA.SAVE_ERROR': 'Could not save the design from Canva'
|
|
73
83
|
};
|
|
@@ -69,5 +69,15 @@ export const messages = {
|
|
|
69
69
|
'SMART.MEDIA_STORAGE.CANVA.SUCCESS': 'Importado desde Canva',
|
|
70
70
|
'SMART.MEDIA_STORAGE.CANVA.POPUP_BLOCKED': 'Permite las ventanas emergentes de este sitio para conectar Canva',
|
|
71
71
|
'SMART.MEDIA_STORAGE.CANVA.CONNECT_FAILED': 'No se pudo conectar Canva',
|
|
72
|
-
'SMART.MEDIA_STORAGE.CANVA.ERROR': 'No se pudo importar desde Canva'
|
|
72
|
+
'SMART.MEDIA_STORAGE.CANVA.ERROR': 'No se pudo importar desde Canva',
|
|
73
|
+
'SMART.MEDIA_STORAGE.CANVA.EDIT': 'Editar en Canva',
|
|
74
|
+
'SMART.MEDIA_STORAGE.CANVA.CREATE': 'Crear en Canva',
|
|
75
|
+
'SMART.MEDIA_STORAGE.CANVA.PRESET_PUSH': 'Imagen grande de push · {{width}}×{{height}}',
|
|
76
|
+
'SMART.MEDIA_STORAGE.CANVA.PRESET_INAPP': 'In-app / Rich Media · {{width}}×{{height}}',
|
|
77
|
+
'SMART.MEDIA_STORAGE.CANVA.PRESET_EMAIL': 'Cabecera de email · {{width}}×{{height}}',
|
|
78
|
+
'SMART.MEDIA_STORAGE.CANVA.SAVING': 'Guardando tu diseño de Canva…',
|
|
79
|
+
'SMART.MEDIA_STORAGE.CANVA.SAVED': 'Guardado desde Canva',
|
|
80
|
+
'SMART.MEDIA_STORAGE.CANVA.EDIT_COPY': 'El diseño de Canva de esta imagen pertenece a otra persona: estás editando una copia',
|
|
81
|
+
'SMART.MEDIA_STORAGE.CANVA.EDIT_ERROR': 'No se pudo abrir Canva',
|
|
82
|
+
'SMART.MEDIA_STORAGE.CANVA.SAVE_ERROR': 'No se pudo guardar el diseño de Canva'
|
|
73
83
|
};
|
|
@@ -69,5 +69,15 @@ export const messages = {
|
|
|
69
69
|
'SMART.MEDIA_STORAGE.CANVA.SUCCESS': 'Importé depuis Canva',
|
|
70
70
|
'SMART.MEDIA_STORAGE.CANVA.POPUP_BLOCKED': 'Autorisez les fenêtres pop-up pour ce site afin de connecter Canva',
|
|
71
71
|
'SMART.MEDIA_STORAGE.CANVA.CONNECT_FAILED': 'Impossible de connecter Canva',
|
|
72
|
-
'SMART.MEDIA_STORAGE.CANVA.ERROR': 'Échec de l’importation depuis Canva'
|
|
72
|
+
'SMART.MEDIA_STORAGE.CANVA.ERROR': 'Échec de l’importation depuis Canva',
|
|
73
|
+
'SMART.MEDIA_STORAGE.CANVA.EDIT': 'Modifier dans Canva',
|
|
74
|
+
'SMART.MEDIA_STORAGE.CANVA.CREATE': 'Créer dans Canva',
|
|
75
|
+
'SMART.MEDIA_STORAGE.CANVA.PRESET_PUSH': 'Grande image push · {{width}}×{{height}}',
|
|
76
|
+
'SMART.MEDIA_STORAGE.CANVA.PRESET_INAPP': 'In-app / Rich Media · {{width}}×{{height}}',
|
|
77
|
+
'SMART.MEDIA_STORAGE.CANVA.PRESET_EMAIL': 'En-tête d’e-mail · {{width}}×{{height}}',
|
|
78
|
+
'SMART.MEDIA_STORAGE.CANVA.SAVING': 'Enregistrement du design depuis Canva…',
|
|
79
|
+
'SMART.MEDIA_STORAGE.CANVA.SAVED': 'Enregistré depuis Canva',
|
|
80
|
+
'SMART.MEDIA_STORAGE.CANVA.EDIT_COPY': 'Le design Canva de cette image appartient à quelqu’un d’autre : vous modifiez une copie',
|
|
81
|
+
'SMART.MEDIA_STORAGE.CANVA.EDIT_ERROR': 'Impossible d’ouvrir Canva',
|
|
82
|
+
'SMART.MEDIA_STORAGE.CANVA.SAVE_ERROR': 'Impossible d’enregistrer le design depuis Canva'
|
|
73
83
|
};
|
|
@@ -69,5 +69,15 @@ export const messages = {
|
|
|
69
69
|
'SMART.MEDIA_STORAGE.CANVA.SUCCESS': 'יובא מ-Canva',
|
|
70
70
|
'SMART.MEDIA_STORAGE.CANVA.POPUP_BLOCKED': 'אפשרו חלונות קופצים לאתר הזה כדי לחבר את Canva',
|
|
71
71
|
'SMART.MEDIA_STORAGE.CANVA.CONNECT_FAILED': 'לא ניתן לחבר את Canva',
|
|
72
|
-
'SMART.MEDIA_STORAGE.CANVA.ERROR': 'הייבוא מ-Canva נכשל'
|
|
72
|
+
'SMART.MEDIA_STORAGE.CANVA.ERROR': 'הייבוא מ-Canva נכשל',
|
|
73
|
+
'SMART.MEDIA_STORAGE.CANVA.EDIT': 'עריכה ב-Canva',
|
|
74
|
+
'SMART.MEDIA_STORAGE.CANVA.CREATE': 'יצירה ב-Canva',
|
|
75
|
+
'SMART.MEDIA_STORAGE.CANVA.PRESET_PUSH': 'תמונת פוש גדולה · {{width}}×{{height}}',
|
|
76
|
+
'SMART.MEDIA_STORAGE.CANVA.PRESET_INAPP': 'In-app / Rich Media · {{width}}×{{height}}',
|
|
77
|
+
'SMART.MEDIA_STORAGE.CANVA.PRESET_EMAIL': 'כותרת אימייל · {{width}}×{{height}}',
|
|
78
|
+
'SMART.MEDIA_STORAGE.CANVA.SAVING': 'שומרים את העיצוב מ-Canva…',
|
|
79
|
+
'SMART.MEDIA_STORAGE.CANVA.SAVED': 'נשמר מ-Canva',
|
|
80
|
+
'SMART.MEDIA_STORAGE.CANVA.EDIT_COPY': 'עיצוב ה-Canva של התמונה שייך למשתמש אחר — אתם עורכים עותק',
|
|
81
|
+
'SMART.MEDIA_STORAGE.CANVA.EDIT_ERROR': 'לא ניתן לפתוח את Canva',
|
|
82
|
+
'SMART.MEDIA_STORAGE.CANVA.SAVE_ERROR': 'לא ניתן לשמור את העיצוב מ-Canva'
|
|
73
83
|
};
|
|
@@ -69,5 +69,15 @@ export const messages = {
|
|
|
69
69
|
'SMART.MEDIA_STORAGE.CANVA.SUCCESS': 'Canva से इम्पोर्ट हो गया',
|
|
70
70
|
'SMART.MEDIA_STORAGE.CANVA.POPUP_BLOCKED': 'Canva कनेक्ट करने के लिए इस साइट के पॉप-अप की अनुमति दें',
|
|
71
71
|
'SMART.MEDIA_STORAGE.CANVA.CONNECT_FAILED': 'Canva कनेक्ट नहीं हो सका',
|
|
72
|
-
'SMART.MEDIA_STORAGE.CANVA.ERROR': 'Canva से इम्पोर्ट विफल रहा'
|
|
72
|
+
'SMART.MEDIA_STORAGE.CANVA.ERROR': 'Canva से इम्पोर्ट विफल रहा',
|
|
73
|
+
'SMART.MEDIA_STORAGE.CANVA.EDIT': 'Canva में संपादित करें',
|
|
74
|
+
'SMART.MEDIA_STORAGE.CANVA.CREATE': 'Canva में बनाएं',
|
|
75
|
+
'SMART.MEDIA_STORAGE.CANVA.PRESET_PUSH': 'पुश बड़ी तस्वीर · {{width}}×{{height}}',
|
|
76
|
+
'SMART.MEDIA_STORAGE.CANVA.PRESET_INAPP': 'इन-ऐप / रिच मीडिया · {{width}}×{{height}}',
|
|
77
|
+
'SMART.MEDIA_STORAGE.CANVA.PRESET_EMAIL': 'ईमेल हेडर · {{width}}×{{height}}',
|
|
78
|
+
'SMART.MEDIA_STORAGE.CANVA.SAVING': 'Canva से आपका डिज़ाइन सहेजा जा रहा है…',
|
|
79
|
+
'SMART.MEDIA_STORAGE.CANVA.SAVED': 'Canva से सहेजा गया',
|
|
80
|
+
'SMART.MEDIA_STORAGE.CANVA.EDIT_COPY': 'इस इमेज का Canva डिज़ाइन किसी और का है — आप एक कॉपी संपादित कर रहे हैं',
|
|
81
|
+
'SMART.MEDIA_STORAGE.CANVA.EDIT_ERROR': 'Canva नहीं खुल सका',
|
|
82
|
+
'SMART.MEDIA_STORAGE.CANVA.SAVE_ERROR': 'Canva से डिज़ाइन सहेजा नहीं जा सका'
|
|
73
83
|
};
|
|
@@ -69,5 +69,15 @@ export const messages = {
|
|
|
69
69
|
'SMART.MEDIA_STORAGE.CANVA.SUCCESS': 'Canvaからインポートしました',
|
|
70
70
|
'SMART.MEDIA_STORAGE.CANVA.POPUP_BLOCKED': 'Canvaを接続するには、このサイトのポップアップを許可してください',
|
|
71
71
|
'SMART.MEDIA_STORAGE.CANVA.CONNECT_FAILED': 'Canvaを接続できませんでした',
|
|
72
|
-
'SMART.MEDIA_STORAGE.CANVA.ERROR': 'Canvaからのインポートに失敗しました'
|
|
72
|
+
'SMART.MEDIA_STORAGE.CANVA.ERROR': 'Canvaからのインポートに失敗しました',
|
|
73
|
+
'SMART.MEDIA_STORAGE.CANVA.EDIT': 'Canvaで編集',
|
|
74
|
+
'SMART.MEDIA_STORAGE.CANVA.CREATE': 'Canvaで作成',
|
|
75
|
+
'SMART.MEDIA_STORAGE.CANVA.PRESET_PUSH': 'プッシュの大きな画像 · {{width}}×{{height}}',
|
|
76
|
+
'SMART.MEDIA_STORAGE.CANVA.PRESET_INAPP': 'アプリ内 / リッチメディア · {{width}}×{{height}}',
|
|
77
|
+
'SMART.MEDIA_STORAGE.CANVA.PRESET_EMAIL': 'メールヘッダー · {{width}}×{{height}}',
|
|
78
|
+
'SMART.MEDIA_STORAGE.CANVA.SAVING': 'Canvaのデザインを保存しています…',
|
|
79
|
+
'SMART.MEDIA_STORAGE.CANVA.SAVED': 'Canvaから保存しました',
|
|
80
|
+
'SMART.MEDIA_STORAGE.CANVA.EDIT_COPY': 'この画像のCanvaデザインは別のユーザーのものです。コピーを編集しています',
|
|
81
|
+
'SMART.MEDIA_STORAGE.CANVA.EDIT_ERROR': 'Canvaを開けませんでした',
|
|
82
|
+
'SMART.MEDIA_STORAGE.CANVA.SAVE_ERROR': 'Canvaのデザインを保存できませんでした'
|
|
73
83
|
};
|
|
@@ -69,5 +69,15 @@ export const messages = {
|
|
|
69
69
|
'SMART.MEDIA_STORAGE.CANVA.SUCCESS': 'Canva에서 가져왔습니다',
|
|
70
70
|
'SMART.MEDIA_STORAGE.CANVA.POPUP_BLOCKED': 'Canva를 연결하려면 이 사이트의 팝업을 허용하세요',
|
|
71
71
|
'SMART.MEDIA_STORAGE.CANVA.CONNECT_FAILED': 'Canva를 연결할 수 없습니다',
|
|
72
|
-
'SMART.MEDIA_STORAGE.CANVA.ERROR': 'Canva에서 가져오지 못했습니다'
|
|
72
|
+
'SMART.MEDIA_STORAGE.CANVA.ERROR': 'Canva에서 가져오지 못했습니다',
|
|
73
|
+
'SMART.MEDIA_STORAGE.CANVA.EDIT': 'Canva에서 편집',
|
|
74
|
+
'SMART.MEDIA_STORAGE.CANVA.CREATE': 'Canva에서 만들기',
|
|
75
|
+
'SMART.MEDIA_STORAGE.CANVA.PRESET_PUSH': '푸시 큰 이미지 · {{width}}×{{height}}',
|
|
76
|
+
'SMART.MEDIA_STORAGE.CANVA.PRESET_INAPP': '인앱 / 리치 미디어 · {{width}}×{{height}}',
|
|
77
|
+
'SMART.MEDIA_STORAGE.CANVA.PRESET_EMAIL': '이메일 헤더 · {{width}}×{{height}}',
|
|
78
|
+
'SMART.MEDIA_STORAGE.CANVA.SAVING': 'Canva에서 디자인을 저장하는 중…',
|
|
79
|
+
'SMART.MEDIA_STORAGE.CANVA.SAVED': 'Canva에서 저장했습니다',
|
|
80
|
+
'SMART.MEDIA_STORAGE.CANVA.EDIT_COPY': '이 이미지의 Canva 디자인은 다른 사용자의 것이므로 사본을 편집합니다',
|
|
81
|
+
'SMART.MEDIA_STORAGE.CANVA.EDIT_ERROR': 'Canva를 열 수 없습니다',
|
|
82
|
+
'SMART.MEDIA_STORAGE.CANVA.SAVE_ERROR': 'Canva에서 디자인을 저장하지 못했습니다'
|
|
73
83
|
};
|
|
@@ -69,5 +69,15 @@ export const messages = {
|
|
|
69
69
|
'SMART.MEDIA_STORAGE.CANVA.SUCCESS': 'Importado do Canva',
|
|
70
70
|
'SMART.MEDIA_STORAGE.CANVA.POPUP_BLOCKED': 'Permita pop-ups neste site para conectar o Canva',
|
|
71
71
|
'SMART.MEDIA_STORAGE.CANVA.CONNECT_FAILED': 'Não foi possível conectar o Canva',
|
|
72
|
-
'SMART.MEDIA_STORAGE.CANVA.ERROR': 'Falha ao importar do Canva'
|
|
72
|
+
'SMART.MEDIA_STORAGE.CANVA.ERROR': 'Falha ao importar do Canva',
|
|
73
|
+
'SMART.MEDIA_STORAGE.CANVA.EDIT': 'Editar no Canva',
|
|
74
|
+
'SMART.MEDIA_STORAGE.CANVA.CREATE': 'Criar no Canva',
|
|
75
|
+
'SMART.MEDIA_STORAGE.CANVA.PRESET_PUSH': 'Imagem grande de push · {{width}}×{{height}}',
|
|
76
|
+
'SMART.MEDIA_STORAGE.CANVA.PRESET_INAPP': 'In-app / Rich Media · {{width}}×{{height}}',
|
|
77
|
+
'SMART.MEDIA_STORAGE.CANVA.PRESET_EMAIL': 'Cabeçalho de e-mail · {{width}}×{{height}}',
|
|
78
|
+
'SMART.MEDIA_STORAGE.CANVA.SAVING': 'Salvando seu design do Canva…',
|
|
79
|
+
'SMART.MEDIA_STORAGE.CANVA.SAVED': 'Salvo do Canva',
|
|
80
|
+
'SMART.MEDIA_STORAGE.CANVA.EDIT_COPY': 'O design do Canva desta imagem pertence a outra pessoa — você está editando uma cópia',
|
|
81
|
+
'SMART.MEDIA_STORAGE.CANVA.EDIT_ERROR': 'Não foi possível abrir o Canva',
|
|
82
|
+
'SMART.MEDIA_STORAGE.CANVA.SAVE_ERROR': 'Não foi possível salvar o design do Canva'
|
|
73
83
|
};
|
|
@@ -69,5 +69,15 @@ export const messages = {
|
|
|
69
69
|
'SMART.MEDIA_STORAGE.CANVA.SUCCESS': 'Импортировано из Canva',
|
|
70
70
|
'SMART.MEDIA_STORAGE.CANVA.POPUP_BLOCKED': 'Разрешите всплывающие окна для этого сайта, чтобы подключить Canva',
|
|
71
71
|
'SMART.MEDIA_STORAGE.CANVA.CONNECT_FAILED': 'Не удалось подключить Canva',
|
|
72
|
-
'SMART.MEDIA_STORAGE.CANVA.ERROR': 'Не удалось импортировать из Canva'
|
|
72
|
+
'SMART.MEDIA_STORAGE.CANVA.ERROR': 'Не удалось импортировать из Canva',
|
|
73
|
+
'SMART.MEDIA_STORAGE.CANVA.EDIT': 'Редактировать в Canva',
|
|
74
|
+
'SMART.MEDIA_STORAGE.CANVA.CREATE': 'Создать в Canva',
|
|
75
|
+
'SMART.MEDIA_STORAGE.CANVA.PRESET_PUSH': 'Большая картинка пуша · {{width}}×{{height}}',
|
|
76
|
+
'SMART.MEDIA_STORAGE.CANVA.PRESET_INAPP': 'In-app / Rich Media · {{width}}×{{height}}',
|
|
77
|
+
'SMART.MEDIA_STORAGE.CANVA.PRESET_EMAIL': 'Шапка письма · {{width}}×{{height}}',
|
|
78
|
+
'SMART.MEDIA_STORAGE.CANVA.SAVING': 'Сохраняем дизайн из Canva…',
|
|
79
|
+
'SMART.MEDIA_STORAGE.CANVA.SAVED': 'Сохранено из Canva',
|
|
80
|
+
'SMART.MEDIA_STORAGE.CANVA.EDIT_COPY': 'Дизайн этой картинки в Canva принадлежит другому пользователю — вы правите копию',
|
|
81
|
+
'SMART.MEDIA_STORAGE.CANVA.EDIT_ERROR': 'Не удалось открыть Canva',
|
|
82
|
+
'SMART.MEDIA_STORAGE.CANVA.SAVE_ERROR': 'Не удалось сохранить дизайн из Canva'
|
|
73
83
|
};
|
|
@@ -69,5 +69,15 @@ export const messages = {
|
|
|
69
69
|
'SMART.MEDIA_STORAGE.CANVA.SUCCESS': 'นำเข้าจาก Canva แล้ว',
|
|
70
70
|
'SMART.MEDIA_STORAGE.CANVA.POPUP_BLOCKED': 'อนุญาตป๊อปอัปสำหรับเว็บไซต์นี้เพื่อเชื่อมต่อ Canva',
|
|
71
71
|
'SMART.MEDIA_STORAGE.CANVA.CONNECT_FAILED': 'ไม่สามารถเชื่อมต่อ Canva ได้',
|
|
72
|
-
'SMART.MEDIA_STORAGE.CANVA.ERROR': 'นำเข้าจาก Canva ไม่สำเร็จ'
|
|
72
|
+
'SMART.MEDIA_STORAGE.CANVA.ERROR': 'นำเข้าจาก Canva ไม่สำเร็จ',
|
|
73
|
+
'SMART.MEDIA_STORAGE.CANVA.EDIT': 'แก้ไขใน Canva',
|
|
74
|
+
'SMART.MEDIA_STORAGE.CANVA.CREATE': 'สร้างใน Canva',
|
|
75
|
+
'SMART.MEDIA_STORAGE.CANVA.PRESET_PUSH': 'รูปใหญ่ของพุช · {{width}}×{{height}}',
|
|
76
|
+
'SMART.MEDIA_STORAGE.CANVA.PRESET_INAPP': 'In-app / Rich Media · {{width}}×{{height}}',
|
|
77
|
+
'SMART.MEDIA_STORAGE.CANVA.PRESET_EMAIL': 'ส่วนหัวอีเมล · {{width}}×{{height}}',
|
|
78
|
+
'SMART.MEDIA_STORAGE.CANVA.SAVING': 'กำลังบันทึกงานออกแบบจาก Canva…',
|
|
79
|
+
'SMART.MEDIA_STORAGE.CANVA.SAVED': 'บันทึกจาก Canva แล้ว',
|
|
80
|
+
'SMART.MEDIA_STORAGE.CANVA.EDIT_COPY': 'งานออกแบบ Canva ของรูปนี้เป็นของผู้อื่น คุณกำลังแก้ไขสำเนา',
|
|
81
|
+
'SMART.MEDIA_STORAGE.CANVA.EDIT_ERROR': 'เปิด Canva ไม่ได้',
|
|
82
|
+
'SMART.MEDIA_STORAGE.CANVA.SAVE_ERROR': 'บันทึกงานออกแบบจาก Canva ไม่ได้'
|
|
73
83
|
};
|
|
@@ -69,5 +69,15 @@ export const messages = {
|
|
|
69
69
|
'SMART.MEDIA_STORAGE.CANVA.SUCCESS': '已从 Canva 导入',
|
|
70
70
|
'SMART.MEDIA_STORAGE.CANVA.POPUP_BLOCKED': '请允许此网站的弹出窗口以连接 Canva',
|
|
71
71
|
'SMART.MEDIA_STORAGE.CANVA.CONNECT_FAILED': '无法连接 Canva',
|
|
72
|
-
'SMART.MEDIA_STORAGE.CANVA.ERROR': '从 Canva 导入失败'
|
|
72
|
+
'SMART.MEDIA_STORAGE.CANVA.ERROR': '从 Canva 导入失败',
|
|
73
|
+
'SMART.MEDIA_STORAGE.CANVA.EDIT': '在 Canva 中编辑',
|
|
74
|
+
'SMART.MEDIA_STORAGE.CANVA.CREATE': '在 Canva 中创建',
|
|
75
|
+
'SMART.MEDIA_STORAGE.CANVA.PRESET_PUSH': '推送大图 · {{width}}×{{height}}',
|
|
76
|
+
'SMART.MEDIA_STORAGE.CANVA.PRESET_INAPP': '应用内 / 富媒体 · {{width}}×{{height}}',
|
|
77
|
+
'SMART.MEDIA_STORAGE.CANVA.PRESET_EMAIL': '邮件页眉 · {{width}}×{{height}}',
|
|
78
|
+
'SMART.MEDIA_STORAGE.CANVA.SAVING': '正在保存 Canva 中的设计…',
|
|
79
|
+
'SMART.MEDIA_STORAGE.CANVA.SAVED': '已从 Canva 保存',
|
|
80
|
+
'SMART.MEDIA_STORAGE.CANVA.EDIT_COPY': '此图片的 Canva 设计属于其他用户,你正在编辑副本',
|
|
81
|
+
'SMART.MEDIA_STORAGE.CANVA.EDIT_ERROR': '无法打开 Canva',
|
|
82
|
+
'SMART.MEDIA_STORAGE.CANVA.SAVE_ERROR': '无法保存 Canva 中的设计'
|
|
73
83
|
};
|
|
@@ -95,4 +95,23 @@ export type MediaStorageMessages = {
|
|
|
95
95
|
'SMART.MEDIA_STORAGE.CANVA.POPUP_BLOCKED': NoParams;
|
|
96
96
|
'SMART.MEDIA_STORAGE.CANVA.CONNECT_FAILED': NoParams;
|
|
97
97
|
'SMART.MEDIA_STORAGE.CANVA.ERROR': NoParams;
|
|
98
|
+
'SMART.MEDIA_STORAGE.CANVA.EDIT': NoParams;
|
|
99
|
+
'SMART.MEDIA_STORAGE.CANVA.CREATE': NoParams;
|
|
100
|
+
'SMART.MEDIA_STORAGE.CANVA.PRESET_PUSH': {
|
|
101
|
+
width: number;
|
|
102
|
+
height: number;
|
|
103
|
+
};
|
|
104
|
+
'SMART.MEDIA_STORAGE.CANVA.PRESET_INAPP': {
|
|
105
|
+
width: number;
|
|
106
|
+
height: number;
|
|
107
|
+
};
|
|
108
|
+
'SMART.MEDIA_STORAGE.CANVA.PRESET_EMAIL': {
|
|
109
|
+
width: number;
|
|
110
|
+
height: number;
|
|
111
|
+
};
|
|
112
|
+
'SMART.MEDIA_STORAGE.CANVA.SAVING': NoParams;
|
|
113
|
+
'SMART.MEDIA_STORAGE.CANVA.SAVED': NoParams;
|
|
114
|
+
'SMART.MEDIA_STORAGE.CANVA.EDIT_COPY': NoParams;
|
|
115
|
+
'SMART.MEDIA_STORAGE.CANVA.EDIT_ERROR': NoParams;
|
|
116
|
+
'SMART.MEDIA_STORAGE.CANVA.SAVE_ERROR': NoParams;
|
|
98
117
|
};
|
package/MediaStorage/styles.d.ts
CHANGED
|
@@ -38,3 +38,4 @@ export declare const DesignTile: import("styled-components").StyledComponent<"bu
|
|
|
38
38
|
}, never>;
|
|
39
39
|
export declare const DesignCaption: import("styled-components").StyledComponent<"span", any, {}, never>;
|
|
40
40
|
export declare const DropzoneRow: import("styled-components").StyledComponent<"div", any, {}, never>;
|
|
41
|
+
export declare const CanvaActions: import("styled-components").StyledComponent<"div", any, {}, never>;
|
package/MediaStorage/styles.js
CHANGED
|
@@ -139,4 +139,8 @@ export const DesignCaption = styled.span.withConfig({
|
|
|
139
139
|
export const DropzoneRow = styled.div.withConfig({
|
|
140
140
|
displayName: "DropzoneRow",
|
|
141
141
|
componentId: "sc-uu3cbo-29"
|
|
142
|
-
})(["display:flex;align-items:stretch;gap:12px;& > :first-child{flex:1;}"]);
|
|
142
|
+
})(["display:flex;align-items:stretch;gap:12px;& > :first-child{flex:1;}"]);
|
|
143
|
+
export const CanvaActions = styled.div.withConfig({
|
|
144
|
+
displayName: "CanvaActions",
|
|
145
|
+
componentId: "sc-uu3cbo-30"
|
|
146
|
+
})(["display:flex;flex-direction:column;justify-content:center;gap:8px;& > *{width:100%;}"]);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pushwoosh/smart-components-kit",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0",
|
|
4
4
|
"description": "Stateful, data-connected React components shared by Pushwoosh micro-frontends",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -17,12 +17,12 @@
|
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
19
|
"@floating-ui/react-dom": "^2.1.2",
|
|
20
|
-
"@pushwoosh/dumb-components": "^2.9.
|
|
20
|
+
"@pushwoosh/dumb-components": "^2.9.19",
|
|
21
21
|
"@pushwoosh/kit-constants": "^2.1.0",
|
|
22
22
|
"@pushwoosh/kit-helpers": "^4.12.7",
|
|
23
|
-
"@pushwoosh/kit-icons": "^2.3.
|
|
23
|
+
"@pushwoosh/kit-icons": "^2.3.7",
|
|
24
24
|
"@pushwoosh/kit-typography": "^1.8.7",
|
|
25
|
-
"@pushwoosh/rpc-v2-http-api-data": "^0.2.
|
|
25
|
+
"@pushwoosh/rpc-v2-http-api-data": "^0.2.389",
|
|
26
26
|
"@pushwoosh/spa-context": "^1.8.1",
|
|
27
27
|
"idb-keyval": "^6.2.2",
|
|
28
28
|
"jwt-decode": "^4.0.0",
|