PluginProbe
Extendify / 3.1.4
Extendify v3.1.4
3.2.1 3.2.0 3.1.6 3.1.5 3.1.4 3.1.3 3.1.2 3.1.1 3.1.0 3.0.6 3.0.5 3.0.4 trunk 0.1.0 0.10.0 0.10.1 0.10.2 0.11.0 0.11.1 0.2.0 0.3.0 0.3.1 0.4.0 0.5.0 0.6.0 All 127 releases
extendify / src / AutoLaunch / state / launch-data.js

launch-data.js in Extendify 3.1.4, at src/AutoLaunch/state/launch-data.js

196 lines 5.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import {
2 getDesignBuildShape,
3 getHomeShape,
4 getImagesShape,
5 getLaunchDecisionsShape,
6 getLogoShape,
7 getPagesShape,
8 getPluginsShape,
9 getProfileShape,
10 getStringsShape,
11 getStyleShape,
12 } from '@auto-launch/fetchers/shape';
13 import { clearSiteImages } from '@auto-launch/functions/wp';
14 import { safeLocalStorage } from '@shared/state/safe-local-storage';
15 import { __ } from '@wordpress/i18n';
16 import { create } from 'zustand';
17 import { createJSONStorage, devtools, persist } from 'zustand/middleware';
18 import { overrideWithUrlParams, urlParams, urlParamsShape } from './url-params';
19
20 const shapeToKeyValue = (shape) => {
21 return Object.fromEntries(
22 Object.keys(shape.shape).map((key) => [key, undefined]),
23 );
24 };
25
26 const initialState = {
27 go: false,
28 showExtendifyCodeScreen: false,
29 // translators: this is for a action log UI. Keep it short
30 statusMessages: [__('Booting things up', 'extendify-local')],
31 errorMessage: null,
32 errorCount: 0,
33 title: null,
34 description: null,
35 descriptionBackup: undefined,
36 descriptionRaw: null,
37 urlParams: {},
38 siteProfile: {
39 ...shapeToKeyValue(getProfileShape),
40 },
41 launchDecisions: {
42 ...shapeToKeyValue(getLaunchDecisionsShape),
43 },
44 ...shapeToKeyValue(getLogoShape),
45 ...shapeToKeyValue(getPluginsShape),
46 ...shapeToKeyValue(getStyleShape),
47 ...shapeToKeyValue(getStringsShape),
48 ...shapeToKeyValue(getImagesShape),
49 ...shapeToKeyValue(getHomeShape),
50 ...shapeToKeyValue(getPagesShape),
51 ...shapeToKeyValue(getDesignBuildShape),
52 designBuild: undefined,
53 attempt: 1,
54 };
55
56 const state = (set, get) => ({
57 ...initialState,
58 urlParams: {
59 ...initialState.urlParams,
60 ...urlParams,
61 },
62 title: undefined,
63 description: undefined,
64 descriptionBackup: undefined,
65 descriptionRaw: undefined,
66 pulse: false,
67 setPulse: (value) => set({ pulse: value }),
68 setData: (key, value) => {
69 if (!isValidKey(key)) return;
70 if (get()[key] === value) return; // avoid unnecessary updates
71 set({ [key]: value });
72 },
73 addStatusMessage: (message) => {
74 const currentMessages = get().statusMessages;
75 // remove any previous duplicates
76 const prev = currentMessages.filter((msg) => msg !== message);
77 set({ statusMessages: [...prev, message] });
78 },
79 setErrorMessage: (message) => {
80 set((state) => ({
81 errorMessage: message,
82 errorCount: state.errorCount + 1,
83 }));
84 },
85 needToStall: () => get().errorCount > 6,
86 resetErrorCount: () => {
87 set({ errorCount: 0 });
88 },
89 reset: ({ exclude }) => {
90 const newState = { ...initialState, attempt: get().attempt + 1 };
91 if (exclude && Array.isArray(exclude)) {
92 exclude.forEach((key) => {
93 if (!isValidKey(key)) return;
94 newState[key] = get()[key];
95 });
96 }
97 clearSiteImages().catch(() => null);
98 set(newState);
99 },
100 });
101
102 // Checks that a key being set is actually something we expect
103 const isValidKey = (key) => Object.keys(initialState).includes(key);
104
105 const keySchemas = {
106 urlParams: urlParamsShape,
107 siteProfile: getProfileShape,
108 launchDecisions: getLaunchDecisionsShape,
109 ...Object.fromEntries(
110 [
111 getLogoShape,
112 getPluginsShape,
113 getStyleShape,
114 getStringsShape,
115 getImagesShape,
116 getHomeShape,
117 getPagesShape,
118 getDesignBuildShape,
119 ].flatMap((s) => Object.entries(s.shape)),
120 ),
121 };
122
123 export const useLaunchDataStore = create(
124 persist(devtools(state, { name: 'Extendify Launch Data' }), {
125 name: `extendify-launch-data-${window.extSharedData.siteId}`,
126 storage: createJSONStorage(() => safeLocalStorage),
127 merge: (p, current) => {
128 // Make sure the persisted state is valid and not corrupted.
129 const persisted = p && typeof p === 'object' ? p : {};
130
131 // This gives us some recovery on page reload
132 const validated = Object.fromEntries(
133 Object.entries(persisted)
134 .filter(([key]) => key in keySchemas)
135 .map(([key, value]) => {
136 const result = keySchemas[key].safeParse(value);
137 return [key, result.success ? result.data : undefined];
138 }),
139 );
140 // Merge in the url params
141 const { title, description, go, ...urlParamsMapped } =
142 overrideWithUrlParams(urlParams);
143
144 return {
145 ...current,
146 ...persisted,
147 ...validated,
148 // If there's a URL param here it should override these values
149 title: title || persisted.title,
150 description: description || persisted.description,
151 descriptionRaw: description || persisted.descriptionRaw,
152 descriptionBackup:
153 persisted.descriptionBackup ||
154 description ||
155 (window.extLaunchData?.showLaunchTitle ? undefined : title),
156 go: go || persisted.go,
157 urlParams: {
158 title,
159 description,
160 go,
161 ...urlParamsMapped,
162 },
163 };
164 },
165 onRehydrateStorage: () => (state) => {
166 if (!state) return;
167 queueMicrotask(() => {
168 useLaunchDataStore.setState(state);
169 });
170 },
171 partialize: (state) => {
172 const {
173 statusMessages,
174 errorMessage,
175 errorCount,
176 pulse,
177 description,
178 descriptionRaw,
179 title,
180 showExtendifyCodeScreen,
181 ...rest
182 } = state;
183 return Object.fromEntries(
184 Object.entries(rest).filter(([, v]) =>
185 Array.isArray(v) ? v.length > 0 : Boolean(v),
186 ),
187 );
188 },
189 }),
190 state,
191 );
192
193 export const clearPersistedLaunchData = () => {
194 useLaunchDataStore.persist.clearStorage();
195 };
196