@designcrowd/library.brand-page 6.2.4 → 6.2.5-ast-seo

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. package/lib/src/{CreatedOnBrandCrowd-de-de-ystrO2LW.js → CreatedOnBrandCrowd-de-de-CqVXsL0_.js} +1 -1
  2. package/lib/src/{CreatedOnBrandCrowd-en-us-BU7hNzTZ.js → CreatedOnBrandCrowd-en-us-DvvlNNB4.js} +1 -1
  3. package/lib/src/{CreatedOnBrandCrowd-es-es-CbuxneQ3.js → CreatedOnBrandCrowd-es-es-Cw9-MTwf.js} +1 -1
  4. package/lib/src/{CreatedOnBrandCrowd-fr-fr-BuNUGOFr.js → CreatedOnBrandCrowd-fr-ca-BLxkHd-s.js} +1 -1
  5. package/lib/src/{CreatedOnBrandCrowd-fr-ca-BuNUGOFr.js → CreatedOnBrandCrowd-fr-fr-BLxkHd-s.js} +1 -1
  6. package/lib/src/{CreatedOnBrandCrowd-pt-pt-BehL88mc.js → CreatedOnBrandCrowd-pt-br-B33ZEiQL.js} +1 -1
  7. package/lib/src/{CreatedOnBrandCrowd-pt-br-BehL88mc.js → CreatedOnBrandCrowd-pt-pt-B33ZEiQL.js} +1 -1
  8. package/lib/src/{CreatedOnDcom-de-de-CMxjFZt9.js → CreatedOnDcom-de-de-ZtRablI0.js} +1 -1
  9. package/lib/src/{CreatedOnDcom-en-us-2Cf6WBvx.js → CreatedOnDcom-en-us-CgVj4Now.js} +1 -1
  10. package/lib/src/{CreatedOnDcom-es-es-CATNnbTq.js → CreatedOnDcom-es-es-Dtmyg7qT.js} +1 -1
  11. package/lib/src/{CreatedOnDcom-fr-ca-DQtMfB-a.js → CreatedOnDcom-fr-ca-CN9RLbJw.js} +1 -1
  12. package/lib/src/{CreatedOnDcom-fr-fr-C1_FWOQf.js → CreatedOnDcom-fr-fr-CJ03rWsS.js} +1 -1
  13. package/lib/src/{CreatedOnDcom-pt-br-C0QOCW0L.js → CreatedOnDcom-pt-br-CmybfT--.js} +1 -1
  14. package/lib/src/{CreatedOnDcom-pt-pt-lHD-p6o4.js → CreatedOnDcom-pt-pt-DEzj870-.js} +1 -1
  15. package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.d.ts +31 -0
  16. package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.js +34 -0
  17. package/lib/src/brand-page-maker/components/brandpage-maker-page/BrandPageMakerPage.mixin.d.ts +30 -0
  18. package/lib/src/brand-page-maker/components/quick-link-bar/QuickLinkBar.mixin.d.ts +30 -0
  19. package/lib/src/brand-page-maker/components/seo-settings/SeoPageSettings.mixin.d.ts +32 -0
  20. package/lib/src/brand-page-maker/components/seo-settings/SeoPageSettings.mixin.js +2 -0
  21. package/lib/src/brand-page-maker/components/seo-settings/UrlSettings.mixin.d.ts +30 -0
  22. package/lib/src/brand-page-maker/components/seo-settings/UseExistingDomainModal.mixin.d.ts +30 -0
  23. package/lib/src/brand-page-maker/components/template-preview/TemplatePreview.mixin.d.ts +30 -0
  24. package/lib/src/brand-page-maker/components/upgrade-to-premium-button/UpgradeToPremiumButton.mixin.d.ts +30 -0
  25. package/lib/src/brand-page-maker/stores/brandpage-container/brand-page-container-store.d.ts +33 -0
  26. package/lib/src/brand-page-maker/stores/brandpage-container/brand-page-container-store.js +178 -11
  27. package/lib/src/brand-page-maker/utils/pending-settings-update.util.d.ts +10 -0
  28. package/lib/src/brand-page-maker/utils/pending-settings-update.util.js +63 -0
  29. package/lib/src/bundled-translations-BNA5h0Dx.js +179 -0
  30. package/lib/src/bundled-translations.de-DE-fyTHrRxT.js +179 -0
  31. package/lib/src/bundled-translations.es-ES-BMmvJGGC.js +179 -0
  32. package/lib/src/bundled-translations.fr-CA-Bo69L_BP.js +179 -0
  33. package/lib/src/bundled-translations.fr-FR-C4yTVFOW.js +179 -0
  34. package/lib/src/bundled-translations.pt-BR-CPMPfny0.js +179 -0
  35. package/lib/src/bundled-translations.pt-PT-C6ZwYs37.js +179 -0
  36. package/lib/src/bundles/bundled-translations.de-DE.json +5 -1
  37. package/lib/src/bundles/bundled-translations.es-ES.json +5 -1
  38. package/lib/src/bundles/bundled-translations.fr-CA.json +5 -1
  39. package/lib/src/bundles/bundled-translations.fr-FR.json +5 -1
  40. package/lib/src/bundles/bundled-translations.json +5 -1
  41. package/lib/src/bundles/bundled-translations.pt-BR.json +5 -1
  42. package/lib/src/bundles/bundled-translations.pt-PT.json +5 -1
  43. package/lib/src/constants/brand-page-maker.d.ts +1 -0
  44. package/lib/src/constants/brand-page-maker.js +3 -0
  45. package/lib/src/css/library.brand-page-brandCrowd.min.css +8 -8
  46. package/lib/src/css/library.brand-page-brandPage.min.css +8 -8
  47. package/lib/src/css/library.brand-page-designCom.min.css +8 -8
  48. package/lib/src/css/library.brand-page-preview.min.css +8 -8
  49. package/lib/src/index.mjs +1 -1
  50. package/lib/src/{lib-CqHUUPUW.js → lib-CNFoZlFr.js} +16317 -16111
  51. package/lib/src/shared/content-settings/components/payment-config-field/PaymentConfigField.mixin.d.ts +30 -0
  52. package/lib/src/shared/logo-settings/components/LogoSettings.mixin.d.ts +30 -0
  53. package/lib/src/shared/page-settings/components/page-settings/PageSettings.mixin.d.ts +30 -0
  54. package/lib/src/shared/page-settings/components/page-settings-section-styles/PageSettingsSectionStyles.mixin.d.ts +30 -0
  55. package/lib/src/shared/publish-brand-page-with-state/PublishBrandPageModalWithState.mixin.d.ts +30 -0
  56. package/lib/src/shared/side-bar/components/SideBar.mixin.d.ts +30 -0
  57. package/lib/src/shared/style-settings/components/StyleSettings.mixin.d.ts +30 -0
  58. package/package.json +1 -1
  59. package/src/brand-page/components/payment/RequestPaymentStripe.vue +15 -6
  60. package/src/brand-page/components/payment/RequestPaymentStripe.vue.test.ts +644 -0
  61. package/src/brand-page/components/payment/i18n/request-payment-stripe.de-DE.json +5 -1
  62. package/src/brand-page/components/payment/i18n/request-payment-stripe.es-ES.json +5 -1
  63. package/src/brand-page/components/payment/i18n/request-payment-stripe.fr-CA.json +5 -1
  64. package/src/brand-page/components/payment/i18n/request-payment-stripe.fr-FR.json +5 -1
  65. package/src/brand-page/components/payment/i18n/request-payment-stripe.json +5 -1
  66. package/src/brand-page/components/payment/i18n/request-payment-stripe.pt-BR.json +5 -1
  67. package/src/brand-page/components/payment/i18n/request-payment-stripe.pt-PT.json +5 -1
  68. package/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.ts +44 -0
  69. package/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.settings-save.test.ts +133 -0
  70. package/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.vue +1 -0
  71. package/src/brand-page-maker/components/brandpage-settings/BrandPageSettings.test.ts +197 -0
  72. package/src/brand-page-maker/components/brandpage-settings/BrandPageSettings.vue +8 -3
  73. package/src/brand-page-maker/components/sensitive-content/SensitiveContent.vue +16 -3
  74. package/src/brand-page-maker/components/seo-settings/SeoPageSettings.mixin.ts +4 -0
  75. package/src/brand-page-maker/stores/brandpage-container/brand-page-container-store.settings-first-save.test.ts +685 -0
  76. package/src/brand-page-maker/stores/brandpage-container/brand-page-container-store.ts +267 -20
  77. package/src/brand-page-maker/utils/pending-settings-update.util.test.ts +117 -0
  78. package/src/brand-page-maker/utils/pending-settings-update.util.ts +93 -0
  79. package/src/bundles/bundled-translations.de-DE.json +5 -1
  80. package/src/bundles/bundled-translations.es-ES.json +5 -1
  81. package/src/bundles/bundled-translations.fr-CA.json +5 -1
  82. package/src/bundles/bundled-translations.fr-FR.json +5 -1
  83. package/src/bundles/bundled-translations.json +5 -1
  84. package/src/bundles/bundled-translations.pt-BR.json +5 -1
  85. package/src/bundles/bundled-translations.pt-PT.json +5 -1
  86. package/src/constants/brand-page-maker.ts +3 -0
  87. package/lib/src/bundled-translations-BYUfWBT3.js +0 -179
  88. package/lib/src/bundled-translations.de-DE-MmzUu1tt.js +0 -179
  89. package/lib/src/bundled-translations.es-ES-D-tG33XL.js +0 -179
  90. package/lib/src/bundled-translations.fr-CA-CNc1H1h3.js +0 -179
  91. package/lib/src/bundled-translations.fr-FR-DX0-yepT.js +0 -179
  92. package/lib/src/bundled-translations.pt-BR-ih1-LRgy.js +0 -179
  93. package/lib/src/bundled-translations.pt-PT-Dq2CmD1p.js +0 -179
  94. package/lib/src/metadata-builder/builders/reorder-pages-builder.d.ts +0 -13
  95. package/lib/src/metadata-builder/builders/reorder-pages-builder.js +0 -49
  96. package/src/metadata-builder/builders/reorder-pages-builder.ts +0 -80
@@ -89,6 +89,14 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
89
89
  requestVerificationToken?: string | undefined;
90
90
  isHostModalVisible?: boolean | undefined;
91
91
  livePreviewUrl?: string | undefined;
92
+ pendingSettingsUpdate?: {
93
+ meta?: {
94
+ title?: string | undefined;
95
+ description?: string | undefined;
96
+ } | undefined;
97
+ sensitiveContent?: number | undefined;
98
+ } | null | undefined;
99
+ hostSettingsSaveRequest?: number | undefined;
92
100
  } & import("pinia").PiniaCustomStateProperties<import("@brand-page-maker/stores").BrandPageContainerState>) => boolean;
93
101
  isUserDraft: (state: {
94
102
  availableTaxes: any[];
@@ -171,6 +179,14 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
171
179
  requestVerificationToken?: string | undefined;
172
180
  isHostModalVisible?: boolean | undefined;
173
181
  livePreviewUrl?: string | undefined;
182
+ pendingSettingsUpdate?: {
183
+ meta?: {
184
+ title?: string | undefined;
185
+ description?: string | undefined;
186
+ } | undefined;
187
+ sensitiveContent?: number | undefined;
188
+ } | null | undefined;
189
+ hostSettingsSaveRequest?: number | undefined;
174
190
  } & import("pinia").PiniaCustomStateProperties<import("@brand-page-maker/stores").BrandPageContainerState>) => boolean;
175
191
  isAnyModalVisible: (state: {
176
192
  availableTaxes: any[];
@@ -253,6 +269,14 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
253
269
  requestVerificationToken?: string | undefined;
254
270
  isHostModalVisible?: boolean | undefined;
255
271
  livePreviewUrl?: string | undefined;
272
+ pendingSettingsUpdate?: {
273
+ meta?: {
274
+ title?: string | undefined;
275
+ description?: string | undefined;
276
+ } | undefined;
277
+ sensitiveContent?: number | undefined;
278
+ } | null | undefined;
279
+ hostSettingsSaveRequest?: number | undefined;
256
280
  } & import("pinia").PiniaCustomStateProperties<import("@brand-page-maker/stores").BrandPageContainerState>) => boolean;
257
281
  }, {
258
282
  initialise(payload: import("../../stores/brandpage-container").InitialisePayload): void;
@@ -342,6 +366,12 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
342
366
  updateSensitiveContent({ sensitiveContent }: {
343
367
  sensitiveContent: any;
344
368
  }): Promise<void>;
369
+ routeNeverSavedSettingsUpdate(update: import("../../utils/pending-settings-update.util").PendingSettingsUpdateValue): Promise<void>;
370
+ mergePendingSettingsUpdate(update: import("../../utils/pending-settings-update.util").PendingSettingsUpdateValue): void;
371
+ saveSiteThenUpdateSettings(update: import("../../utils/pending-settings-update.util").PendingSettingsUpdateValue): Promise<void>;
372
+ applyPendingSettingsUpdate(): Promise<void>;
373
+ cancelPendingSettingsUpdate(): void;
374
+ writeSettingsUpdate(update: import("../../utils/pending-settings-update.util").PendingSettingsUpdateValue): Promise<boolean>;
345
375
  createBrandPageCustomDomain({ domainName }: {
346
376
  domainName: any;
347
377
  }): Promise<false | undefined>;
@@ -5,6 +5,7 @@ import { type AbTest } from '@brand-page';
5
5
  import type { WebsiteSlugCheckResponse } from '@brand-page-maker/models/api.model';
6
6
  import { WEBSITE_UPGRADE_CONTEXT_TYPES } from '@designcrowd/fe-shared-lib';
7
7
  import { type OnSearchTermChangedCallback } from '@shared/template-settings/store';
8
+ import { type PendingSettingsUpdateValue } from '../../utils/pending-settings-update.util';
8
9
  export type WebsiteContextUpgradeType = keyof typeof WEBSITE_UPGRADE_CONTEXT_TYPES;
9
10
  export interface BrandPageContainerState {
10
11
  availableTaxes: any[];
@@ -59,6 +60,8 @@ export interface BrandPageContainerState {
59
60
  requestVerificationToken?: string;
60
61
  isHostModalVisible?: boolean;
61
62
  livePreviewUrl?: string;
63
+ pendingSettingsUpdate?: PendingSettingsUpdateValue | null;
64
+ hostSettingsSaveRequest?: number;
62
65
  }
63
66
  export type GettyVideoEditorViewModelResponse = {
64
67
  assetId: string;
@@ -172,6 +175,14 @@ export declare const useBrandPageContainerStore: import("pinia").StoreDefinition
172
175
  requestVerificationToken?: string | undefined;
173
176
  isHostModalVisible?: boolean | undefined;
174
177
  livePreviewUrl?: string | undefined;
178
+ pendingSettingsUpdate?: {
179
+ meta?: {
180
+ title?: string | undefined;
181
+ description?: string | undefined;
182
+ } | undefined;
183
+ sensitiveContent?: number | undefined;
184
+ } | null | undefined;
185
+ hostSettingsSaveRequest?: number | undefined;
175
186
  } & import("pinia").PiniaCustomStateProperties<BrandPageContainerState>) => boolean;
176
187
  isUserDraft: (state: {
177
188
  availableTaxes: any[];
@@ -254,6 +265,14 @@ export declare const useBrandPageContainerStore: import("pinia").StoreDefinition
254
265
  requestVerificationToken?: string | undefined;
255
266
  isHostModalVisible?: boolean | undefined;
256
267
  livePreviewUrl?: string | undefined;
268
+ pendingSettingsUpdate?: {
269
+ meta?: {
270
+ title?: string | undefined;
271
+ description?: string | undefined;
272
+ } | undefined;
273
+ sensitiveContent?: number | undefined;
274
+ } | null | undefined;
275
+ hostSettingsSaveRequest?: number | undefined;
257
276
  } & import("pinia").PiniaCustomStateProperties<BrandPageContainerState>) => boolean;
258
277
  isAnyModalVisible: (state: {
259
278
  availableTaxes: any[];
@@ -336,6 +355,14 @@ export declare const useBrandPageContainerStore: import("pinia").StoreDefinition
336
355
  requestVerificationToken?: string | undefined;
337
356
  isHostModalVisible?: boolean | undefined;
338
357
  livePreviewUrl?: string | undefined;
358
+ pendingSettingsUpdate?: {
359
+ meta?: {
360
+ title?: string | undefined;
361
+ description?: string | undefined;
362
+ } | undefined;
363
+ sensitiveContent?: number | undefined;
364
+ } | null | undefined;
365
+ hostSettingsSaveRequest?: number | undefined;
339
366
  } & import("pinia").PiniaCustomStateProperties<BrandPageContainerState>) => boolean;
340
367
  }, {
341
368
  initialise(payload: InitialisePayload): void;
@@ -425,6 +452,12 @@ export declare const useBrandPageContainerStore: import("pinia").StoreDefinition
425
452
  updateSensitiveContent({ sensitiveContent }: {
426
453
  sensitiveContent: any;
427
454
  }): Promise<void>;
455
+ routeNeverSavedSettingsUpdate(update: PendingSettingsUpdateValue): Promise<void>;
456
+ mergePendingSettingsUpdate(update: PendingSettingsUpdateValue): void;
457
+ saveSiteThenUpdateSettings(update: PendingSettingsUpdateValue): Promise<void>;
458
+ applyPendingSettingsUpdate(): Promise<void>;
459
+ cancelPendingSettingsUpdate(): void;
460
+ writeSettingsUpdate(update: PendingSettingsUpdateValue): Promise<boolean>;
428
461
  createBrandPageCustomDomain({ domainName }: {
429
462
  domainName: any;
430
463
  }): Promise<false | undefined>;
@@ -14,6 +14,7 @@ import { errorTr, constantsTr } from '@src/composables/useTranslate';
14
14
  import { findValuesByKey } from '../../../helpers/ts.helper';
15
15
  import { WEBSITE_UPGRADE_CONTEXT_TYPES } from '@designcrowd/fe-shared-lib';
16
16
  import { useUiTemplateSettingsStore, } from '@shared/template-settings/store';
17
+ import { clearPendingSettingsUpdate, readPendingSettingsUpdate, writePendingSettingsUpdate, } from '../../utils/pending-settings-update.util';
17
18
  export const BRANDPAGE_STATUS = Object.freeze({
18
19
  Published: 'Published',
19
20
  Unpublished: 'Unpublished',
@@ -73,6 +74,8 @@ export const useBrandPageContainerStore = defineStore('brandPageContainer', {
73
74
  isHostModalVisible: false,
74
75
  requestVerificationToken: undefined,
75
76
  livePreviewUrl: undefined,
77
+ pendingSettingsUpdate: null,
78
+ hostSettingsSaveRequest: 0,
76
79
  };
77
80
  },
78
81
  actions: {
@@ -864,19 +867,21 @@ export const useBrandPageContainerStore = defineStore('brandPageContainer', {
864
867
  }
865
868
  },
866
869
  async updateBrandPageSettings({ description, title }) {
870
+ const update = {
871
+ meta: { title, description },
872
+ };
873
+ if (!this.designDraftToken) {
874
+ await this.routeNeverSavedSettingsUpdate(update);
875
+ return;
876
+ }
867
877
  const brandPageMakerStore = useBrandPageMakerStore();
868
878
  try {
869
879
  this.setIsPublishing({ isPublishing: true });
870
- const result = await brandPageClient.updateBrandPageMetaAsync(brandPageMakerStore.brandPageType, this.designDraftToken, {
871
- pageDescription: description,
872
- pageTitle: title,
873
- metaKeywords: [],
874
- });
875
- if (!result) {
880
+ const ok = await this.writeSettingsUpdate(update);
881
+ if (!ok) {
876
882
  await brandPageMakerStore.enqueueErrorMessage();
877
883
  return;
878
884
  }
879
- this.updateBrandPageMeta(result);
880
885
  await brandPageMakerStore.enqueueSaveSuccessMessage({
881
886
  description: constantsTr('settingsSaveSuccessMessage'),
882
887
  isPublished: this.isPublished,
@@ -894,17 +899,111 @@ export const useBrandPageContainerStore = defineStore('brandPageContainer', {
894
899
  }
895
900
  },
896
901
  async updateSensitiveContent({ sensitiveContent }) {
902
+ const update = { sensitiveContent };
903
+ if (!this.designDraftToken) {
904
+ await this.routeNeverSavedSettingsUpdate(update);
905
+ return;
906
+ }
897
907
  const brandPageMakerStore = useBrandPageMakerStore();
898
908
  try {
899
909
  this.setIsPublishing({ isPublishing: true });
900
- const result = await brandPageClient.updateSensitiveContentAsync(brandPageMakerStore.brandPageType, this.designDraftToken, {
901
- sensitiveContentType: sensitiveContent,
910
+ const ok = await this.writeSettingsUpdate(update);
911
+ if (!ok) {
912
+ await brandPageMakerStore.enqueueErrorMessage();
913
+ return;
914
+ }
915
+ await brandPageMakerStore.enqueueSaveSuccessMessage({
916
+ description: constantsTr('settingsSaveSuccessMessage'),
917
+ isPublished: this.isPublished,
902
918
  });
903
- if (!result) {
919
+ }
920
+ catch (err) {
921
+ await brandPageMakerStore.enqueueErrorMessage();
922
+ if (process.env.NODE_ENV !== 'production') {
923
+ console.error(err);
924
+ }
925
+ }
926
+ finally {
927
+ this.setIsPublishing({ isPublishing: false });
928
+ await brandPageMakerStore.showNextNotificationMessage();
929
+ }
930
+ },
931
+ // The no-token branch shared by both settings writes: a never-saved site has
932
+ // nowhere to write yet, so the site is saved first (post-purchase, via the maker
933
+ // itself) or the write waits on the host's save (pre-purchase). Admin templates
934
+ // have no draft token and never gain one, so they never save (T6.2).
935
+ async routeNeverSavedSettingsUpdate(update) {
936
+ if (this.isAdminMaker) {
937
+ return;
938
+ }
939
+ if (!this.isPrePurchase) {
940
+ await this.saveSiteThenUpdateSettings(update);
941
+ return;
942
+ }
943
+ this.mergePendingSettingsUpdate(update);
944
+ },
945
+ // Merges into the in-memory pending update AND sessionStorage (so it survives
946
+ // the pre-purchase email-capture reload) every time, so a second write is never
947
+ // lost. Only asks BrandPageMaker's watcher to ask the host to save when no host
948
+ // save is already running: while one is in flight, this write rides along with
949
+ // it (the apply once it lands writes the merged value) instead of re-asking,
950
+ // which would run a second host save concurrently and risk a second draft.
951
+ mergePendingSettingsUpdate(update) {
952
+ const brandPageMakerStore = useBrandPageMakerStore();
953
+ const mergedMeta = update.meta || this.pendingSettingsUpdate?.meta
954
+ ? { ...this.pendingSettingsUpdate?.meta, ...update.meta }
955
+ : undefined;
956
+ this.pendingSettingsUpdate = {
957
+ ...this.pendingSettingsUpdate,
958
+ ...update,
959
+ meta: mergedMeta,
960
+ };
961
+ writePendingSettingsUpdate(brandPageMakerStore.brandPageType, this.designTemplateToken, this.pendingSettingsUpdate);
962
+ if (!this.isSaving) {
963
+ this.hostSettingsSaveRequest = (this.hostSettingsSaveRequest ?? 0) + 1;
964
+ }
965
+ },
966
+ // Post-purchase first save: saves the whole site (Save Progress's own path,
967
+ // `saveOnly` so a published site isn't republished), then writes the setting
968
+ // against the fresh token. Reused by `applyPendingSettingsUpdate` for the
969
+ // pre-purchase counterpart once the host's save has produced a token.
970
+ async saveSiteThenUpdateSettings(update) {
971
+ const brandPageMakerStore = useBrandPageMakerStore();
972
+ if (this.isAdminMaker) {
973
+ return;
974
+ }
975
+ if (this.isSaving) {
976
+ await brandPageMakerStore.enqueueErrorMessage();
977
+ await brandPageMakerStore.showNextNotificationMessage();
978
+ return;
979
+ }
980
+ this.setIsPublishing({ isPublishing: true });
981
+ try {
982
+ // saveBrandPage's inferred return type doesn't narrow to the `saved` shape
983
+ // at this call site, so this reads the one field it needs.
984
+ const result = await this.saveBrandPage({ saveOnly: true });
985
+ if (!result || !result.saved) {
986
+ // A thrown save error already enqueued its own message (saveBrandPage's
987
+ // own catch); a silent `false`/empty response didn't, so cover that case
988
+ // here rather than leave the customer with no feedback. Checked by type,
989
+ // not just presence, so an unrelated message already queued (e.g. from a
990
+ // previous action) can't be mistaken for this save's own error.
991
+ const hasErrorQueued = brandPageMakerStore.notificationMessageQueue.some((message) => message.type === 'error');
992
+ if (!hasErrorQueued) {
993
+ await brandPageMakerStore.enqueueErrorMessage();
994
+ }
995
+ return;
996
+ }
997
+ // The save's own banner is disarmed — the setting write's banner below is
998
+ // the only notification for this sequence.
999
+ this.setTriggerSaveSuccessMessage({
1000
+ triggerSaveSuccessMessage: false,
1001
+ });
1002
+ const ok = await this.writeSettingsUpdate(update);
1003
+ if (!ok) {
904
1004
  await brandPageMakerStore.enqueueErrorMessage();
905
1005
  return;
906
1006
  }
907
- this.updateBrandPageSensitiveContent(result);
908
1007
  await brandPageMakerStore.enqueueSaveSuccessMessage({
909
1008
  description: constantsTr('settingsSaveSuccessMessage'),
910
1009
  isPublished: this.isPublished,
@@ -921,6 +1020,74 @@ export const useBrandPageContainerStore = defineStore('brandPageContainer', {
921
1020
  await brandPageMakerStore.showNextNotificationMessage();
922
1021
  }
923
1022
  },
1023
+ // Applies whatever settings update is pending once a draft token exists:
1024
+ // in-session pre-purchase (memory) or after the email-capture reload
1025
+ // (sessionStorage, scoped to the current brand page type). Clears both before
1026
+ // writing so it runs exactly once even if the write itself fails.
1027
+ async applyPendingSettingsUpdate() {
1028
+ const brandPageMakerStore = useBrandPageMakerStore();
1029
+ const pending = this.pendingSettingsUpdate ||
1030
+ readPendingSettingsUpdate(brandPageMakerStore.brandPageType, this.designTemplateToken);
1031
+ if (!pending || !this.designDraftToken) {
1032
+ return;
1033
+ }
1034
+ this.cancelPendingSettingsUpdate();
1035
+ try {
1036
+ this.setIsPublishing({ isPublishing: true });
1037
+ const ok = await this.writeSettingsUpdate(pending);
1038
+ if (!ok) {
1039
+ await brandPageMakerStore.enqueueErrorMessage();
1040
+ return;
1041
+ }
1042
+ await brandPageMakerStore.enqueueSaveSuccessMessage({
1043
+ description: constantsTr('settingsSaveSuccessMessage'),
1044
+ isPublished: this.isPublished,
1045
+ });
1046
+ }
1047
+ catch (err) {
1048
+ await brandPageMakerStore.enqueueErrorMessage();
1049
+ if (process.env.NODE_ENV !== 'production') {
1050
+ console.error(err);
1051
+ }
1052
+ }
1053
+ finally {
1054
+ this.setIsPublishing({ isPublishing: false });
1055
+ await brandPageMakerStore.showNextNotificationMessage();
1056
+ }
1057
+ },
1058
+ // The visitor abandoned the host's save prompt (or it threw): drop the pending
1059
+ // update from memory and storage without writing anything.
1060
+ cancelPendingSettingsUpdate() {
1061
+ this.pendingSettingsUpdate = null;
1062
+ clearPendingSettingsUpdate();
1063
+ },
1064
+ // The actual endpoint write(s) shared by the saved-site path, the post-purchase
1065
+ // first save and the pre-purchase apply-on-reload path. Callers own
1066
+ // isPublishing/notification sequencing; this only reports success or failure.
1067
+ async writeSettingsUpdate(update) {
1068
+ const brandPageMakerStore = useBrandPageMakerStore();
1069
+ if (update.meta) {
1070
+ const result = await brandPageClient.updateBrandPageMetaAsync(brandPageMakerStore.brandPageType, this.designDraftToken, {
1071
+ pageDescription: update.meta.description,
1072
+ pageTitle: update.meta.title,
1073
+ metaKeywords: [],
1074
+ });
1075
+ if (!result) {
1076
+ return false;
1077
+ }
1078
+ this.updateBrandPageMeta(result);
1079
+ }
1080
+ if (update.sensitiveContent !== undefined) {
1081
+ const result = await brandPageClient.updateSensitiveContentAsync(brandPageMakerStore.brandPageType, this.designDraftToken, {
1082
+ sensitiveContentType: update.sensitiveContent,
1083
+ });
1084
+ if (!result) {
1085
+ return false;
1086
+ }
1087
+ this.updateBrandPageSensitiveContent(result);
1088
+ }
1089
+ return true;
1090
+ },
924
1091
  async createBrandPageCustomDomain({ domainName }) {
925
1092
  const brandPageMakerStore = useBrandPageMakerStore();
926
1093
  const customDomainResponse = await brandPageClient.createBrandPageCustomDomainAsync(brandPageMakerStore.brandPageType, this.designDraftToken, domainName, false);
@@ -0,0 +1,10 @@
1
+ export interface PendingSettingsUpdateValue {
2
+ meta?: {
3
+ title?: string;
4
+ description?: string;
5
+ };
6
+ sensitiveContent?: number;
7
+ }
8
+ export declare const clearPendingSettingsUpdate: () => void;
9
+ export declare const writePendingSettingsUpdate: (brandPageType: string, designTemplateToken: string, update: PendingSettingsUpdateValue) => void;
10
+ export declare const readPendingSettingsUpdate: (brandPageType: string, designTemplateToken: string) => PendingSettingsUpdateValue | undefined;
@@ -0,0 +1,63 @@
1
+ // Carries a settings write across the pre-purchase email-capture reload (a full page
2
+ // load), which a store or an in-memory-only flag can't survive.
3
+ const STORAGE_KEY = 'bc-pending-settings-update';
4
+ const EXPIRY_MS = 30 * 60 * 1000;
5
+ // Private mode / blocked storage can throw on property access, not just on the
6
+ // calls below, so this is wrapped too.
7
+ const getSessionStorage = () => {
8
+ try {
9
+ return typeof window !== 'undefined' ? window.sessionStorage : undefined;
10
+ }
11
+ catch {
12
+ return undefined;
13
+ }
14
+ };
15
+ export const clearPendingSettingsUpdate = () => {
16
+ try {
17
+ getSessionStorage()?.removeItem(STORAGE_KEY);
18
+ }
19
+ catch {
20
+ // Storage unavailable or blocked — nothing to clear.
21
+ }
22
+ };
23
+ export const writePendingSettingsUpdate = (brandPageType, designTemplateToken, update) => {
24
+ try {
25
+ const entry = {
26
+ brandPageType,
27
+ designTemplateToken,
28
+ update,
29
+ savedAt: Date.now(),
30
+ };
31
+ getSessionStorage()?.setItem(STORAGE_KEY, JSON.stringify(entry));
32
+ }
33
+ catch {
34
+ // Storage unavailable or blocked — the in-memory pending state (the store's
35
+ // own `pendingSettingsUpdate`) still carries the update through this session.
36
+ }
37
+ };
38
+ // Returns undefined, and drops the stored entry, when it's missing, unreadable,
39
+ // expired, or belongs to a different brand page or a different site — the reload
40
+ // always passes the brand page type and design template token it's carrying the
41
+ // update for, so a mismatch means a stale entry from another pre-purchase draft
42
+ // (possibly of the same type) rather than the one this reload continues.
43
+ export const readPendingSettingsUpdate = (brandPageType, designTemplateToken) => {
44
+ try {
45
+ const raw = getSessionStorage()?.getItem(STORAGE_KEY);
46
+ if (!raw) {
47
+ return undefined;
48
+ }
49
+ const entry = JSON.parse(raw);
50
+ const isExpired = Date.now() - entry.savedAt > EXPIRY_MS;
51
+ const isOtherBrandPage = entry.brandPageType !== brandPageType;
52
+ const isOtherSite = entry.designTemplateToken !== designTemplateToken;
53
+ if (isExpired || isOtherBrandPage || isOtherSite) {
54
+ clearPendingSettingsUpdate();
55
+ return undefined;
56
+ }
57
+ return entry.update;
58
+ }
59
+ catch {
60
+ clearPendingSettingsUpdate();
61
+ return undefined;
62
+ }
63
+ };