@designcrowd/library.brand-page 6.0.6-undo-6 → 6.0.6-undo-8
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/lib/src/{CreatedOnBrandCrowd-de-de-BfSQG4or.js → CreatedOnBrandCrowd-de-de-DdT7VIEh.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-en-us-CO07UsMZ.js → CreatedOnBrandCrowd-en-us-YSkiGVKr.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-es-es-BElFyN72.js → CreatedOnBrandCrowd-es-es-1EPcCaOy.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-fr-fr-DnTxsYIb.js → CreatedOnBrandCrowd-fr-ca-C8fnEHlw.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-fr-ca-DnTxsYIb.js → CreatedOnBrandCrowd-fr-fr-C8fnEHlw.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-pt-pt-DSMhWz5Z.js → CreatedOnBrandCrowd-pt-br-Dl3Se_ur.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-pt-br-DSMhWz5Z.js → CreatedOnBrandCrowd-pt-pt-Dl3Se_ur.js} +1 -1
- package/lib/src/{CreatedOnDcom-de-de-C2469ycC.js → CreatedOnDcom-de-de-rXbL8YwY.js} +1 -1
- package/lib/src/{CreatedOnDcom-en-us-Cvz7kq6J.js → CreatedOnDcom-en-us-Bm9CAhKw.js} +1 -1
- package/lib/src/{CreatedOnDcom-es-es-BvDTs1Y_.js → CreatedOnDcom-es-es-B8diEgO8.js} +1 -1
- package/lib/src/{CreatedOnDcom-fr-ca-vJ9zwwPI.js → CreatedOnDcom-fr-ca-b6jqk1vU.js} +1 -1
- package/lib/src/{CreatedOnDcom-fr-fr-D90gm3ay.js → CreatedOnDcom-fr-fr-ECBv8SyF.js} +1 -1
- package/lib/src/{CreatedOnDcom-pt-br-C1VGGfTF.js → CreatedOnDcom-pt-br-C7THecsn.js} +1 -1
- package/lib/src/{CreatedOnDcom-pt-pt-DGL1py4g.js → CreatedOnDcom-pt-pt-C7f06hrr.js} +1 -1
- package/lib/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.js +65 -54
- package/lib/src/css/library.brand-page-brandCrowd.min.css +13 -13
- package/lib/src/css/library.brand-page-brandPage.min.css +13 -13
- package/lib/src/css/library.brand-page-designCom.min.css +13 -13
- package/lib/src/css/library.brand-page-preview.min.css +13 -13
- package/lib/src/index.mjs +1 -1
- package/lib/src/{lib-nGjOXase.js → lib-DQvE17ni.js} +612 -602
- package/package.json +1 -1
- package/src/brand-page/components/shop/Shop.vue +0 -1
- package/src/brand-page-maker/components/quick-link-bar/RedoButton.vue +9 -1
- package/src/brand-page-maker/components/quick-link-bar/UndoButton.vue +9 -1
- package/src/brand-page-maker/components/quick-link-bar/undo-redo-buttons.test.ts +29 -2
- package/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.test.ts +130 -0
- package/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.ts +71 -62
package/package.json
CHANGED
|
@@ -39,17 +39,25 @@ import { Icon, Tooltip } from '@designcrowd/fe-shared-lib';
|
|
|
39
39
|
import { useHistoryStore } from '@brand-page-maker/stores/history/history-store';
|
|
40
40
|
import { useAiWebsiteBuilderThreadStore } from '@brand-page-maker/stores/ai-thread/ai-website-builder-thread-store';
|
|
41
41
|
import { useBrandPageContainerStore } from '@brand-page-maker/stores/brandpage-container';
|
|
42
|
+
import { useUiTemplateSettingsStore } from '@shared/template-settings/store';
|
|
42
43
|
import { quickLinkBarTr } from '@src/composables/useTranslate';
|
|
43
44
|
|
|
44
45
|
const historyStore = useHistoryStore();
|
|
45
46
|
const aiThreadStore = useAiWebsiteBuilderThreadStore();
|
|
46
47
|
const containerStore = useBrandPageContainerStore();
|
|
48
|
+
const templateSettingsStore = useUiTemplateSettingsStore();
|
|
47
49
|
|
|
48
50
|
const isDisabled = computed(
|
|
49
51
|
() =>
|
|
50
52
|
!historyStore.canRedo ||
|
|
51
53
|
aiThreadStore.isProcessing ||
|
|
52
|
-
containerStore.isSaving
|
|
54
|
+
containerStore.isSaving ||
|
|
55
|
+
// Locked while a restore is applying (the apply awaits the designed-logo
|
|
56
|
+
// re-render) or the template previews are refetching: re-entering
|
|
57
|
+
// mid-regeneration overlapped two reloads and left the sidebar keyed to
|
|
58
|
+
// the wrong logo (fast undo→redo desync).
|
|
59
|
+
historyStore.isApplyingSnapshot ||
|
|
60
|
+
templateSettingsStore.isBusy,
|
|
53
61
|
);
|
|
54
62
|
|
|
55
63
|
const onClick = () => {
|
|
@@ -39,17 +39,25 @@ import { Icon, Tooltip } from '@designcrowd/fe-shared-lib';
|
|
|
39
39
|
import { useHistoryStore } from '@brand-page-maker/stores/history/history-store';
|
|
40
40
|
import { useAiWebsiteBuilderThreadStore } from '@brand-page-maker/stores/ai-thread/ai-website-builder-thread-store';
|
|
41
41
|
import { useBrandPageContainerStore } from '@brand-page-maker/stores/brandpage-container';
|
|
42
|
+
import { useUiTemplateSettingsStore } from '@shared/template-settings/store';
|
|
42
43
|
import { quickLinkBarTr } from '@src/composables/useTranslate';
|
|
43
44
|
|
|
44
45
|
const historyStore = useHistoryStore();
|
|
45
46
|
const aiThreadStore = useAiWebsiteBuilderThreadStore();
|
|
46
47
|
const containerStore = useBrandPageContainerStore();
|
|
48
|
+
const templateSettingsStore = useUiTemplateSettingsStore();
|
|
47
49
|
|
|
48
50
|
const isDisabled = computed(
|
|
49
51
|
() =>
|
|
50
52
|
!historyStore.canUndo ||
|
|
51
53
|
aiThreadStore.isProcessing ||
|
|
52
|
-
containerStore.isSaving
|
|
54
|
+
containerStore.isSaving ||
|
|
55
|
+
// Locked while a restore is applying (the apply awaits the designed-logo
|
|
56
|
+
// re-render) or the template previews are refetching: re-entering
|
|
57
|
+
// mid-regeneration overlapped two reloads and left the sidebar keyed to
|
|
58
|
+
// the wrong logo (fast undo→redo desync).
|
|
59
|
+
historyStore.isApplyingSnapshot ||
|
|
60
|
+
templateSettingsStore.isBusy,
|
|
53
61
|
);
|
|
54
62
|
|
|
55
63
|
const onClick = () => {
|
|
@@ -6,8 +6,10 @@ import RedoButton from './RedoButton.vue';
|
|
|
6
6
|
|
|
7
7
|
// These tests cover the click-dispatch contract for the undo/redo buttons:
|
|
8
8
|
// - Click → historyStore.undo()/redo() ONLY when enabled.
|
|
9
|
-
// - Disabled when any of
|
|
10
|
-
// aiThread.isProcessing, container.isSaving.
|
|
9
|
+
// - Disabled when any of five guards is true: canUndo/canRedo,
|
|
10
|
+
// aiThread.isProcessing, container.isSaving, history.isApplyingSnapshot
|
|
11
|
+
// (a restore is applying — spans the awaited logo re-render), or
|
|
12
|
+
// templateSettings.isBusy (template previews are refetching).
|
|
11
13
|
//
|
|
12
14
|
// Markup, class names, and i18n strings are intentionally not asserted —
|
|
13
15
|
// they're covered by e2e tests and the data-component / data-test-*
|
|
@@ -34,6 +36,7 @@ vi.mock('@designcrowd/fe-shared-lib', () => ({
|
|
|
34
36
|
const historyStoreMock = {
|
|
35
37
|
canUndo: true,
|
|
36
38
|
canRedo: true,
|
|
39
|
+
isApplyingSnapshot: false,
|
|
37
40
|
undo: vi.fn(),
|
|
38
41
|
redo: vi.fn(),
|
|
39
42
|
};
|
|
@@ -57,14 +60,22 @@ vi.mock('@brand-page-maker/stores/brandpage-container', () => ({
|
|
|
57
60
|
useBrandPageContainerStore: vi.fn(() => containerStoreMock),
|
|
58
61
|
}));
|
|
59
62
|
|
|
63
|
+
const templateSettingsStoreMock = { isBusy: false };
|
|
64
|
+
|
|
65
|
+
vi.mock('@shared/template-settings/store', () => ({
|
|
66
|
+
useUiTemplateSettingsStore: vi.fn(() => templateSettingsStoreMock),
|
|
67
|
+
}));
|
|
68
|
+
|
|
60
69
|
beforeEach(() => {
|
|
61
70
|
setActivePinia(createPinia());
|
|
62
71
|
historyStoreMock.canUndo = true;
|
|
63
72
|
historyStoreMock.canRedo = true;
|
|
73
|
+
historyStoreMock.isApplyingSnapshot = false;
|
|
64
74
|
historyStoreMock.undo = vi.fn();
|
|
65
75
|
historyStoreMock.redo = vi.fn();
|
|
66
76
|
aiStoreMock.isProcessing = false;
|
|
67
77
|
containerStoreMock.isSaving = false;
|
|
78
|
+
templateSettingsStoreMock.isBusy = false;
|
|
68
79
|
});
|
|
69
80
|
|
|
70
81
|
describe('UndoButton', () => {
|
|
@@ -80,6 +91,14 @@ describe('UndoButton', () => {
|
|
|
80
91
|
['canUndo is false', () => (historyStoreMock.canUndo = false)],
|
|
81
92
|
['AI is processing', () => (aiStoreMock.isProcessing = true)],
|
|
82
93
|
['save is in flight', () => (containerStoreMock.isSaving = true)],
|
|
94
|
+
[
|
|
95
|
+
'a restore is applying',
|
|
96
|
+
() => (historyStoreMock.isApplyingSnapshot = true),
|
|
97
|
+
],
|
|
98
|
+
[
|
|
99
|
+
'template previews are refetching',
|
|
100
|
+
() => (templateSettingsStoreMock.isBusy = true),
|
|
101
|
+
],
|
|
83
102
|
])('does not dispatch when %s', async (_label, applyGuard) => {
|
|
84
103
|
applyGuard();
|
|
85
104
|
|
|
@@ -104,6 +123,14 @@ describe('RedoButton', () => {
|
|
|
104
123
|
['canRedo is false', () => (historyStoreMock.canRedo = false)],
|
|
105
124
|
['AI is processing', () => (aiStoreMock.isProcessing = true)],
|
|
106
125
|
['save is in flight', () => (containerStoreMock.isSaving = true)],
|
|
126
|
+
[
|
|
127
|
+
'a restore is applying',
|
|
128
|
+
() => (historyStoreMock.isApplyingSnapshot = true),
|
|
129
|
+
],
|
|
130
|
+
[
|
|
131
|
+
'template previews are refetching',
|
|
132
|
+
() => (templateSettingsStoreMock.isBusy = true),
|
|
133
|
+
],
|
|
107
134
|
])('does not dispatch when %s', async (_label, applyGuard) => {
|
|
108
135
|
applyGuard();
|
|
109
136
|
|
|
@@ -50,6 +50,9 @@ import {
|
|
|
50
50
|
} from '@shared/content-settings/store';
|
|
51
51
|
import { useUiSideBarStore } from '@shared/side-bar/store';
|
|
52
52
|
import { useUiEditableLogoStore } from '@shared/logo-settings/store/editable-logo-store';
|
|
53
|
+
import { useUiLogoSettingsStore } from '@shared/logo-settings/store';
|
|
54
|
+
import { useLogoStore } from '@brand-page-maker/stores';
|
|
55
|
+
import { getLogoImageFromModel } from '@brand-page/utils/logo.util';
|
|
53
56
|
import { SIDE_BAR_TAB_NAMES } from '@brand-page-maker/constants';
|
|
54
57
|
import { PAGE_SECTIONS } from '@shared/page-settings/models';
|
|
55
58
|
import { FabricRenderClient } from '../../../clients/fabric-render-client';
|
|
@@ -988,4 +991,131 @@ describe('brand page maker store module', () => {
|
|
|
988
991
|
// Still 'Acme' — no restore attempted.
|
|
989
992
|
expect(editableLogoStore.logoEdits.textObjects[0].text).toBe('Acme');
|
|
990
993
|
});
|
|
994
|
+
|
|
995
|
+
// The template sidebar regenerates off the selectedLogoImage watcher, so
|
|
996
|
+
// the restore must hand it a READY preview key. For a designed logo
|
|
997
|
+
// (pre-purchase) that key is the s3 render token minted by the awaited
|
|
998
|
+
// fabric re-render — exposing selectedLogoImage BEFORE the render made the
|
|
999
|
+
// sidebar fetch a list keyed to the previous render, which repainted
|
|
1000
|
+
// seconds later (the undo "flash"). Same precondition that makes the BYO
|
|
1001
|
+
// upload flow work: the key exists before the watcher fires.
|
|
1002
|
+
test('_syncLogoSettingsFromSnapshot re-renders the designed logo BEFORE exposing selectedLogoImage', async () => {
|
|
1003
|
+
const makerStore = useBrandPageMakerStore();
|
|
1004
|
+
const containerStore = useBrandPageContainerStore();
|
|
1005
|
+
const editableLogoStore = useUiEditableLogoStore();
|
|
1006
|
+
const logoSettingsStore = useUiLogoSettingsStore();
|
|
1007
|
+
const logoStore = useLogoStore();
|
|
1008
|
+
|
|
1009
|
+
await makerStore.initialise(INITIALISE_PAYLOAD);
|
|
1010
|
+
|
|
1011
|
+
const originalStamp = editableLogoStore.stampLogoBase64IntoBrandPageData;
|
|
1012
|
+
const originalRender = editableLogoStore.updateEditableLogoImageUrlAsync;
|
|
1013
|
+
const originalSetSelected = logoSettingsStore.setSelectedLogoImage;
|
|
1014
|
+
|
|
1015
|
+
try {
|
|
1016
|
+
containerStore.isPrePurchase = true;
|
|
1017
|
+
logoStore.setLogoTemplateAsset({
|
|
1018
|
+
token: 'designed-template',
|
|
1019
|
+
isByo: false,
|
|
1020
|
+
} as never);
|
|
1021
|
+
logoStore.addLogoDraftAsset({
|
|
1022
|
+
logoDraftAsset: { token: 'designed-2', tick: 1, isByo: false },
|
|
1023
|
+
} as never);
|
|
1024
|
+
// Previous token differs from the snapshot's → not the
|
|
1025
|
+
// logoUnchanged short-circuit.
|
|
1026
|
+
editableLogoStore.setLogoDraftToken('designed-1');
|
|
1027
|
+
|
|
1028
|
+
const snapshot = JSON.parse(
|
|
1029
|
+
JSON.stringify(makerStore.brandPageData),
|
|
1030
|
+
) as BrandPageModel;
|
|
1031
|
+
const snapshotLogoImage = getLogoImageFromModel(snapshot);
|
|
1032
|
+
|
|
1033
|
+
expect(snapshotLogoImage).toBeTruthy();
|
|
1034
|
+
snapshotLogoImage!.logoDraftToken = 'designed-2';
|
|
1035
|
+
|
|
1036
|
+
const callOrder: string[] = [];
|
|
1037
|
+
|
|
1038
|
+
editableLogoStore.stampLogoBase64IntoBrandPageData = vi.fn();
|
|
1039
|
+
editableLogoStore.updateEditableLogoImageUrlAsync = vi.fn(async () => {
|
|
1040
|
+
// Async like the real fabric render — the order assertion below
|
|
1041
|
+
// fails if the sync doesn't await it before exposing the logo.
|
|
1042
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
1043
|
+
callOrder.push('render');
|
|
1044
|
+
});
|
|
1045
|
+
logoSettingsStore.setSelectedLogoImage = vi.fn(() => {
|
|
1046
|
+
callOrder.push('selectedLogoImage');
|
|
1047
|
+
});
|
|
1048
|
+
|
|
1049
|
+
await makerStore._syncLogoSettingsFromSnapshot(
|
|
1050
|
+
snapshot,
|
|
1051
|
+
'{"colors":["#123456"]}',
|
|
1052
|
+
);
|
|
1053
|
+
|
|
1054
|
+
expect(callOrder).toEqual(['render', 'selectedLogoImage']);
|
|
1055
|
+
expect(logoSettingsStore.setSelectedLogoImage).toHaveBeenCalledWith(
|
|
1056
|
+
expect.objectContaining({ logoDraftToken: 'designed-2' }),
|
|
1057
|
+
);
|
|
1058
|
+
} finally {
|
|
1059
|
+
containerStore.isPrePurchase = false;
|
|
1060
|
+
editableLogoStore.stampLogoBase64IntoBrandPageData = originalStamp;
|
|
1061
|
+
editableLogoStore.updateEditableLogoImageUrlAsync = originalRender;
|
|
1062
|
+
logoSettingsStore.setSelectedLogoImage = originalSetSelected;
|
|
1063
|
+
}
|
|
1064
|
+
});
|
|
1065
|
+
|
|
1066
|
+
test('_syncLogoSettingsFromSnapshot still exposes selectedLogoImage on the BYO and token-less paths', async () => {
|
|
1067
|
+
const makerStore = useBrandPageMakerStore();
|
|
1068
|
+
const editableLogoStore = useUiEditableLogoStore();
|
|
1069
|
+
const logoSettingsStore = useUiLogoSettingsStore();
|
|
1070
|
+
const logoStore = useLogoStore();
|
|
1071
|
+
|
|
1072
|
+
await makerStore.initialise(INITIALISE_PAYLOAD);
|
|
1073
|
+
|
|
1074
|
+
const originalStamp = editableLogoStore.stampLogoBase64IntoBrandPageData;
|
|
1075
|
+
const originalSetSelected = logoSettingsStore.setSelectedLogoImage;
|
|
1076
|
+
|
|
1077
|
+
try {
|
|
1078
|
+
editableLogoStore.stampLogoBase64IntoBrandPageData = vi.fn();
|
|
1079
|
+
|
|
1080
|
+
const setSelectedSpy = vi.fn();
|
|
1081
|
+
|
|
1082
|
+
logoSettingsStore.setSelectedLogoImage = setSelectedSpy;
|
|
1083
|
+
|
|
1084
|
+
// BYO path: registered byo draft, differing previous token.
|
|
1085
|
+
logoStore.addLogoDraftAsset({
|
|
1086
|
+
logoDraftAsset: { token: 'byo-1', tick: 2, isByo: true },
|
|
1087
|
+
} as never);
|
|
1088
|
+
editableLogoStore.setLogoDraftToken('designed-1');
|
|
1089
|
+
|
|
1090
|
+
const byoSnapshot = JSON.parse(
|
|
1091
|
+
JSON.stringify(makerStore.brandPageData),
|
|
1092
|
+
) as BrandPageModel;
|
|
1093
|
+
const byoLogoImage = getLogoImageFromModel(byoSnapshot);
|
|
1094
|
+
|
|
1095
|
+
byoLogoImage!.logoDraftToken = 'byo-1';
|
|
1096
|
+
|
|
1097
|
+
await makerStore._syncLogoSettingsFromSnapshot(byoSnapshot);
|
|
1098
|
+
|
|
1099
|
+
expect(setSelectedSpy).toHaveBeenCalledWith(
|
|
1100
|
+
expect.objectContaining({ logoDraftToken: 'byo-1' }),
|
|
1101
|
+
);
|
|
1102
|
+
|
|
1103
|
+
// Token-less path: the logoImage exists but has no draft token.
|
|
1104
|
+
setSelectedSpy.mockClear();
|
|
1105
|
+
|
|
1106
|
+
const tokenlessSnapshot = JSON.parse(
|
|
1107
|
+
JSON.stringify(makerStore.brandPageData),
|
|
1108
|
+
) as BrandPageModel;
|
|
1109
|
+
const tokenlessLogoImage = getLogoImageFromModel(tokenlessSnapshot);
|
|
1110
|
+
|
|
1111
|
+
tokenlessLogoImage!.logoDraftToken = '';
|
|
1112
|
+
|
|
1113
|
+
await makerStore._syncLogoSettingsFromSnapshot(tokenlessSnapshot);
|
|
1114
|
+
|
|
1115
|
+
expect(setSelectedSpy).toHaveBeenCalledTimes(1);
|
|
1116
|
+
} finally {
|
|
1117
|
+
editableLogoStore.stampLogoBase64IntoBrandPageData = originalStamp;
|
|
1118
|
+
logoSettingsStore.setSelectedLogoImage = originalSetSelected;
|
|
1119
|
+
}
|
|
1120
|
+
});
|
|
991
1121
|
});
|
|
@@ -960,83 +960,92 @@ export const useBrandPageMakerStore = defineStore('brandPageMaker', {
|
|
|
960
960
|
|
|
961
961
|
if (!logoImage) return;
|
|
962
962
|
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
// existing object, so the templates store's deep watcher receives
|
|
966
|
-
// old === new (same reference), sees no logoDraftToken change, and
|
|
967
|
-
// never refetches the template previews. Post-purchase that watcher
|
|
968
|
-
// is the ONLY refetch path (previews are keyed by logoDraftToken and
|
|
969
|
-
// the designed-logo re-render below is pre-purchase-only), which left
|
|
970
|
-
// the sidebar stuck on the undone logo (BP-5814).
|
|
971
|
-
logoSettingsStore.setSelectedLogoImage({ ...logoImage });
|
|
972
|
-
|
|
973
|
-
const draftToken: string | undefined = logoImage.logoDraftToken;
|
|
963
|
+
try {
|
|
964
|
+
const draftToken: string | undefined = logoImage.logoDraftToken;
|
|
974
965
|
|
|
975
|
-
|
|
966
|
+
if (!draftToken) return;
|
|
976
967
|
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
968
|
+
// Re-derive enableEditMode + templateAsset from the draft registry
|
|
969
|
+
// (append-only for the session) instead of stashing on every entry.
|
|
970
|
+
const draft = logoStore.getLogoDraftAssetByToken(draftToken);
|
|
980
971
|
|
|
981
|
-
|
|
982
|
-
|
|
972
|
+
if (draft) {
|
|
973
|
+
editableLogoStore.setEnableEditMode(!draft.isByo);
|
|
983
974
|
|
|
984
|
-
|
|
985
|
-
|
|
975
|
+
if (draft.templateAsset) {
|
|
976
|
+
logoStore.setLogoTemplateAsset(draft.templateAsset);
|
|
977
|
+
}
|
|
986
978
|
}
|
|
987
|
-
}
|
|
988
979
|
|
|
989
|
-
|
|
980
|
+
editableLogoStore.setLogoDraftToken(draftToken);
|
|
990
981
|
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
982
|
+
// No logo change → cache is still correct; just stamp base64 back
|
|
983
|
+
// (snapshot doesn't carry logoImageBase64Url).
|
|
984
|
+
const logoUnchanged =
|
|
985
|
+
prevDraftToken === draftToken &&
|
|
986
|
+
(logoEditsStr === undefined || logoEditsStr === prevLogoEditsStr);
|
|
996
987
|
|
|
997
|
-
|
|
998
|
-
|
|
988
|
+
if (logoUnchanged) {
|
|
989
|
+
editableLogoStore.stampLogoBase64IntoBrandPageData();
|
|
999
990
|
|
|
1000
|
-
|
|
1001
|
-
|
|
991
|
+
return;
|
|
992
|
+
}
|
|
1002
993
|
|
|
1003
|
-
|
|
994
|
+
const isByo = !!draft?.isByo;
|
|
1004
995
|
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
996
|
+
if (isByo) {
|
|
997
|
+
// BYO mints a fresh draftToken per upload so the per-token
|
|
998
|
+
// cache always matches; no re-render needed.
|
|
999
|
+
if (editableLogoStore.restoreVariationsForDraftToken(draftToken)) {
|
|
1000
|
+
editableLogoStore.stampLogoBase64IntoBrandPageData();
|
|
1001
|
+
}
|
|
1011
1002
|
|
|
1012
|
-
|
|
1013
|
-
|
|
1003
|
+
return;
|
|
1004
|
+
}
|
|
1014
1005
|
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1006
|
+
// Designed: draft token is reused across edits, so the cache
|
|
1007
|
+
// only holds the latest render. Re-issue fabric-render — same
|
|
1008
|
+
// call as the live edit path. Awaited so concurrent undos
|
|
1009
|
+
// serialize and the call sits inside the isApplyingSnapshot
|
|
1010
|
+
// window (watcher guard suppresses the writeback).
|
|
1011
|
+
if (
|
|
1012
|
+
containerStore.isPrePurchase &&
|
|
1013
|
+
logoEditsStr &&
|
|
1014
|
+
logoStore.logoTemplateAsset
|
|
1015
|
+
) {
|
|
1016
|
+
// Stamp the cached (pre-undo) base64 onto brandPageData first
|
|
1017
|
+
// so the canvas keeps showing the previous logo while the
|
|
1018
|
+
// re-render is in flight. Without this the logoImageBase64Url
|
|
1019
|
+
// fields are undefined (snapshot is stripped pre-purchase) and
|
|
1020
|
+
// the canvas flickers blank for ~500-1500ms.
|
|
1021
|
+
editableLogoStore.stampLogoBase64IntoBrandPageData();
|
|
1031
1022
|
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1023
|
+
try {
|
|
1024
|
+
await editableLogoStore.updateEditableLogoImageUrlAsync();
|
|
1025
|
+
} catch (error) {
|
|
1026
|
+
console.error(
|
|
1027
|
+
'brandpage-maker-store: failed to re-render logo on history apply',
|
|
1028
|
+
error,
|
|
1029
|
+
);
|
|
1030
|
+
}
|
|
1039
1031
|
}
|
|
1032
|
+
} finally {
|
|
1033
|
+
// Assign a FRESH object — the same way the upload/selection flows
|
|
1034
|
+
// write selectedLogoImage. A setState/$patch here deep-merges into
|
|
1035
|
+
// the existing object, so the templates store's deep watcher would
|
|
1036
|
+
// receive old === new (same reference), see no logoDraftToken
|
|
1037
|
+
// change, and never refetch the template previews (BP-5814).
|
|
1038
|
+
//
|
|
1039
|
+
// Set LAST — after the branch above has prepared the preview key
|
|
1040
|
+
// (BYO cache restore, or the awaited designed re-render that mints
|
|
1041
|
+
// the s3 token) — so the watcher always fires with a fetchable key,
|
|
1042
|
+
// the same precondition that makes the upload flow work. Firing it
|
|
1043
|
+
// before the re-render fetched the template list with the previous
|
|
1044
|
+
// render's s3 token: an obsolete list that repainted seconds later
|
|
1045
|
+
// (the undo "flash"). The sidebar instead holds the previous
|
|
1046
|
+
// previews while the render is in flight, matching the canvas
|
|
1047
|
+
// policy above.
|
|
1048
|
+
logoSettingsStore.setSelectedLogoImage({ ...logoImage });
|
|
1040
1049
|
}
|
|
1041
1050
|
},
|
|
1042
1051
|
|