slice-machine-ui 1.22.3-beta.1 → 1.22.3-beta.3

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 (154) hide show
  1. package/components/DeleteVariationModal/index.tsx +12 -11
  2. package/components/Forms/CreateSliceModal/CreateSliceModal.tsx +2 -5
  3. package/components/Forms/RenameCustomTypeModal/RenameCustomTypeModal.tsx +9 -5
  4. package/components/Forms/RenameVariationModal/RenameVariationModal.tsx +12 -11
  5. package/components/ItemHeader/index.tsx +1 -0
  6. package/components/ListItem/index.tsx +5 -2
  7. package/components/ScreenshotChangesModal/VariationDropZone.tsx +31 -9
  8. package/components/ScreenshotChangesModal/index.tsx +3 -0
  9. package/components/ScreenshotChangesModal/useCustomScreenshot.tsx +5 -5
  10. package/components/Simulator/index.tsx +9 -3
  11. package/lib/builders/CustomTypeBuilder/SliceZone/SlicesTemplatesModal.tsx +2 -2
  12. package/lib/builders/CustomTypeBuilder/SliceZone/UpdateSliceZoneModal.tsx +2 -2
  13. package/lib/builders/CustomTypeBuilder/SliceZone/index.tsx +12 -20
  14. package/lib/builders/CustomTypeBuilder/TabModal/update.tsx +3 -1
  15. package/lib/builders/CustomTypeBuilder/TabZone/index.tsx +119 -52
  16. package/lib/builders/CustomTypeBuilder/index.tsx +39 -42
  17. package/lib/builders/SliceBuilder/FieldZones/index.tsx +81 -56
  18. package/lib/builders/SliceBuilder/Sidebar/AddVariationModal.tsx +24 -16
  19. package/lib/builders/SliceBuilder/Sidebar/index.tsx +44 -46
  20. package/lib/builders/SliceBuilder/SimulatorButton/index.tsx +4 -28
  21. package/lib/builders/SliceBuilder/index.tsx +10 -96
  22. package/lib/builders/common/Zone/Card/components/Hints/CodeBlock.tsx +5 -1
  23. package/lib/builders/common/Zone/Card/components/NewField.tsx +16 -15
  24. package/lib/builders/common/Zone/Card/index.jsx +2 -0
  25. package/lib/builders/common/Zone/index.jsx +3 -1
  26. package/lib/models/common/ComponentUI.ts +0 -14
  27. package/lib/models/common/CustomType/sliceZone.ts +0 -29
  28. package/lib/models/common/CustomType/tab.ts +10 -142
  29. package/lib/models/common/widgets/Group/ListItem/index.jsx +61 -23
  30. package/out/404.html +1 -1
  31. package/out/_next/static/chunks/065a3ddb-9a38ca0d60f0bf2f.js +1 -0
  32. package/out/_next/static/chunks/183-4feb6bb3eddbc768.js +1 -0
  33. package/out/_next/static/chunks/18539003-7b2711e6c51d6fac.js +97 -0
  34. package/out/_next/static/chunks/1cc2734a-2c5b6c0367fcde86.js +1 -0
  35. package/out/_next/static/chunks/25-8fedd33ad9b6de5b.js +1 -0
  36. package/out/_next/static/chunks/318-541db69860d31138.js +1 -0
  37. package/out/_next/static/chunks/{505-3f1cf09a086dcba8.js → 376-0ed5822f8afcaa7c.js} +3 -3
  38. package/out/_next/static/chunks/4c744e84-e3161d754618373f.js +1 -0
  39. package/out/_next/static/chunks/50-cfc2514205b86001.js +1 -0
  40. package/out/_next/static/chunks/543-f8766685f7f451e2.js +1 -0
  41. package/out/_next/static/chunks/59b4e022-7a3b5554b806349f.js +1 -0
  42. package/out/_next/static/chunks/696-b12edad30a3617e5.js +31 -0
  43. package/out/_next/static/chunks/727-15cf3f2fea9a37e5.js +1 -0
  44. package/out/_next/static/chunks/731-501990ebe6a71b32.js +1 -0
  45. package/out/_next/static/chunks/787-727e3aef5d2a10a8.js +1 -0
  46. package/out/_next/static/chunks/904-ccd8ca3368ce29fc.js +1 -0
  47. package/out/_next/static/chunks/{918-38d08f1e885b222d.js → 918-5bb55fb464e34768.js} +1 -1
  48. package/out/_next/static/chunks/f36c6662-03bb5e9d9aa0b0aa.js +1 -0
  49. package/out/_next/static/chunks/pages/_app-20876abeebe0fda7.js +430 -0
  50. package/out/_next/static/chunks/pages/changelog-68d115a14f1423d7.js +1 -0
  51. package/out/_next/static/chunks/pages/changes-6f62ae7b6243a1c7.js +1 -0
  52. package/out/_next/static/chunks/pages/custom-types/{[customTypeId]-3a37eb3373bb8823.js → [customTypeId]-3f862ad6111a1fc0.js} +1 -1
  53. package/out/_next/static/chunks/pages/{custom-types-2f5664d9492b13fb.js → custom-types-94b8f8dbf7727412.js} +1 -1
  54. package/out/_next/static/chunks/pages/{index-d8e3a2c0d712904f.js → index-64cfb8b0948ba8ef.js} +1 -1
  55. package/out/_next/static/chunks/pages/page-types/{[pageTypeId]-733f3890c0466a05.js → [pageTypeId]-d1ffca11c42f2603.js} +1 -1
  56. package/out/_next/static/chunks/pages/slices/[lib]/[sliceName]/[variation]/simulator-897ca93c114a1435.js +1 -0
  57. package/out/_next/static/chunks/pages/slices/[lib]/[sliceName]/[variation]-e89e2e6f772a3454.js +1 -0
  58. package/out/_next/static/chunks/pages/slices-9628f8aa54968d6a.js +1 -0
  59. package/out/_next/static/css/{1bbf650dfd37ce69.css → 1aa04669758c24f4.css} +1 -1
  60. package/out/_next/static/j_voPTrYzsuLCERqtl3Hn/_buildManifest.js +1 -0
  61. package/out/changelog.html +1 -1
  62. package/out/changes.html +1 -1
  63. package/out/custom-types/[customTypeId].html +1 -1
  64. package/out/custom-types.html +1 -1
  65. package/out/index.html +1 -1
  66. package/out/labs.html +1 -1
  67. package/out/page-types/[pageTypeId].html +1 -1
  68. package/out/slices/[lib]/[sliceName]/[variation]/simulator.html +1 -1
  69. package/out/slices/[lib]/[sliceName]/[variation].html +1 -1
  70. package/out/slices.html +1 -1
  71. package/package.json +6 -6
  72. package/pages/slices/[lib]/[sliceName]/[variation]/index.tsx +25 -11
  73. package/pages/slices/[lib]/[sliceName]/[variation]/simulator.tsx +12 -9
  74. package/src/apiClient.ts +7 -6
  75. package/src/components/CodeBlock/CodeBlock.tsx +1 -0
  76. package/src/components/Window/Window.tsx +7 -1
  77. package/src/domain/__tests__/customType.test.ts +785 -0
  78. package/src/domain/customType.ts +519 -6
  79. package/src/domain/slice.ts +166 -1
  80. package/src/features/autoSave/AutoSaveStatusIndicator.tsx +43 -0
  81. package/src/features/autoSave/useAutoSave.tsx +177 -0
  82. package/src/features/customTypes/EditDropdown.tsx +3 -0
  83. package/src/features/customTypes/actions/convertCustomToPageType.ts +2 -4
  84. package/src/features/customTypes/customTypesBuilder/CustomTypeProvider.tsx +90 -0
  85. package/src/features/customTypes/customTypesBuilder/CustomTypesBuilderPage.tsx +46 -79
  86. package/src/features/customTypes/customTypesMessages.ts +4 -0
  87. package/src/features/slices/actions/addSlicesToSliceZone.ts +2 -7
  88. package/src/features/slices/actions/uploadSliceScreenshot.ts +45 -0
  89. package/src/features/slices/convertLegacySlice/ConvertLegacySliceAsNewVariationDialog.tsx +5 -5
  90. package/src/features/slices/convertLegacySlice/ConvertLegacySliceButton.tsx +4 -10
  91. package/src/features/slices/sliceBuilder/SliceBuilderProvider.tsx +110 -0
  92. package/src/features/slices/sliceBuilder/actions/deleteVariation.ts +8 -24
  93. package/src/features/slices/sliceBuilder/actions/renameVariation.ts +8 -24
  94. package/src/features/slices/sliceCards/SharedSliceCard.tsx +1 -0
  95. package/src/hooks/useCurrentSlice.tsx +4 -16
  96. package/src/hooks/useScreenshotChangesModal.ts +1 -0
  97. package/src/hooks/useServerState.ts +1 -58
  98. package/src/modules/availableCustomTypes/index.ts +8 -3
  99. package/src/modules/simulator/index.ts +0 -2
  100. package/src/modules/slices/index.ts +32 -25
  101. package/src/modules/slices/selector.ts +30 -0
  102. package/src/modules/useSliceMachineActions.ts +20 -270
  103. package/src/redux/reducer.ts +0 -4
  104. package/src/redux/saga.ts +0 -6
  105. package/src/redux/type.ts +0 -4
  106. package/test/src/modules/availableCustomTypes/index.test.ts +8 -10
  107. package/test/src/modules/simulator.test.ts +0 -2
  108. package/lib/models/common/CustomType/group.ts +0 -80
  109. package/lib/models/common/Variation.ts +0 -100
  110. package/out/_next/static/ZrWICkLApT4ZATA_akn-2/_buildManifest.js +0 -1
  111. package/out/_next/static/chunks/18539003-4460ccbfe3109578.js +0 -97
  112. package/out/_next/static/chunks/482-34cee2a2071c235f.js +0 -1
  113. package/out/_next/static/chunks/550-c80fd46fb64d1eef.js +0 -1
  114. package/out/_next/static/chunks/80-7b8a97d0122ff74a.js +0 -1
  115. package/out/_next/static/chunks/840-163f8a1040e6820d.js +0 -1
  116. package/out/_next/static/chunks/904-519dbf0f7e8c6243.js +0 -1
  117. package/out/_next/static/chunks/958-8aca174b80cb0c35.js +0 -1
  118. package/out/_next/static/chunks/pages/_app-132564608e9a9502.js +0 -458
  119. package/out/_next/static/chunks/pages/changelog-4d0f2f1222e403fe.js +0 -1
  120. package/out/_next/static/chunks/pages/changes-52c9d917808d1461.js +0 -1
  121. package/out/_next/static/chunks/pages/slices/[lib]/[sliceName]/[variation]/simulator-7b17cb59d0db03b5.js +0 -1
  122. package/out/_next/static/chunks/pages/slices/[lib]/[sliceName]/[variation]-ef11594ce026b650.js +0 -1
  123. package/out/_next/static/chunks/pages/slices-884a936a9a062a65.js +0 -1
  124. package/src/domain/__tests__/CustomTypeModel.test.ts +0 -247
  125. package/src/layouts/WithSlice.tsx +0 -26
  126. package/src/modules/screenshots/actions.ts +0 -21
  127. package/src/modules/screenshots/sagas.ts +0 -70
  128. package/src/modules/selectedCustomType/actions.ts +0 -147
  129. package/src/modules/selectedCustomType/index.ts +0 -11
  130. package/src/modules/selectedCustomType/reducer.ts +0 -287
  131. package/src/modules/selectedCustomType/sagas.ts +0 -72
  132. package/src/modules/selectedCustomType/selectors.ts +0 -33
  133. package/src/modules/selectedCustomType/stateHelpers.ts +0 -42
  134. package/src/modules/selectedCustomType/types.ts +0 -9
  135. package/src/modules/selectedSlice/actions.ts +0 -106
  136. package/src/modules/selectedSlice/reducer.ts +0 -175
  137. package/src/modules/selectedSlice/sagas.ts +0 -72
  138. package/src/modules/selectedSlice/selectors.ts +0 -55
  139. package/src/modules/selectedSlice/types.ts +0 -3
  140. package/src/modules/toaster/utils.tsx +0 -23
  141. package/test/lib/models/common/CustomType/sliceZone.test.ts +0 -49
  142. package/test/pages/custom-types.test.tsx +0 -625
  143. package/test/src/modules/selectedCustomType/__fixtures__/model.json +0 -119
  144. package/test/src/modules/selectedCustomType/reducer.test.ts +0 -322
  145. package/test/src/modules/selectedCustomType/sagas.test.ts +0 -89
  146. package/test/src/modules/selectedCustomType/selectors.test.ts +0 -54
  147. package/test/src/modules/selectedSlice/__fixtures__/mocks.json +0 -171
  148. package/test/src/modules/selectedSlice/__fixtures__/model.json +0 -35
  149. package/test/src/modules/selectedSlice/__testutils__/getRefreshStateCreatorPayloadData.ts +0 -72
  150. package/test/src/modules/selectedSlice/__testutils__/getSelectedSliceDummyData.ts +0 -30
  151. package/test/src/modules/selectedSlice/reducer.test.ts +0 -170
  152. package/test/src/modules/selectedSlice/sagas.test.ts +0 -82
  153. package/test/src/modules/toaster/utils.test.ts +0 -50
  154. /package/out/_next/static/{ZrWICkLApT4ZATA_akn-2 → j_voPTrYzsuLCERqtl3Hn}/_ssgManifest.js +0 -0
@@ -2,9 +2,49 @@ import type {
2
2
  CompositeSlice,
3
3
  LegacySlice,
4
4
  } from "@prismicio/types-internal/lib/customtypes/widgets/slices";
5
+ import { NestableWidget } from "@prismicio/types-internal/lib/customtypes";
5
6
 
6
7
  import type { ComponentUI } from "@lib/models/common/ComponentUI";
7
- import type { VariationSM } from "@lib/models/common/Slice";
8
+ import type { VariationSM, WidgetsArea } from "@lib/models/common/Slice";
9
+
10
+ type CopySliceVariationArgs = {
11
+ copiedVariation: VariationSM;
12
+ id: string;
13
+ name: string;
14
+ slice: ComponentUI;
15
+ };
16
+
17
+ type DeleteFieldArgs = {
18
+ slice: ComponentUI;
19
+ variationId: string;
20
+ widgetArea: WidgetsArea;
21
+ fieldId: string;
22
+ };
23
+
24
+ type UpdateFieldArgs = {
25
+ slice: ComponentUI;
26
+ variationId: string;
27
+ widgetArea: WidgetsArea;
28
+ previousFieldId: string;
29
+ newFieldId: string;
30
+ newField: NestableWidget;
31
+ };
32
+
33
+ type AddFieldArgs = {
34
+ slice: ComponentUI;
35
+ variationId: string;
36
+ widgetArea: WidgetsArea;
37
+ newFieldId: string;
38
+ newField: NestableWidget;
39
+ };
40
+
41
+ type ReorderFieldArgs = {
42
+ slice: ComponentUI;
43
+ variationId: string;
44
+ widgetArea: WidgetsArea;
45
+ sourceIndex: number;
46
+ destinationIndex: number;
47
+ };
8
48
 
9
49
  export function countMissingScreenshots(slice: ComponentUI): number {
10
50
  return slice.model.variations.length - Object.keys(slice.screenshots).length;
@@ -78,3 +118,128 @@ export function getFieldMappingFingerprint(
78
118
  ),
79
119
  };
80
120
  }
121
+
122
+ export function copySliceVariation(args: CopySliceVariationArgs) {
123
+ const { slice, id, name, copiedVariation } = args;
124
+ const newVariation = { ...copiedVariation, id, name };
125
+
126
+ return {
127
+ slice: {
128
+ ...slice,
129
+ model: {
130
+ ...slice.model,
131
+ variations: slice.model.variations.concat([newVariation]),
132
+ },
133
+ },
134
+ variation: newVariation,
135
+ };
136
+ }
137
+
138
+ export function deleteField(args: DeleteFieldArgs): ComponentUI {
139
+ const { slice, variationId, widgetArea, fieldId } = args;
140
+
141
+ return {
142
+ ...slice,
143
+ model: {
144
+ ...slice.model,
145
+ variations: slice.model.variations.map((v) => {
146
+ if (v.id === variationId) {
147
+ return {
148
+ ...v,
149
+ [widgetArea]: v[widgetArea]?.filter((w) => w.key !== fieldId),
150
+ };
151
+ }
152
+ return v;
153
+ }),
154
+ },
155
+ };
156
+ }
157
+
158
+ export function updateField(args: UpdateFieldArgs): ComponentUI {
159
+ const {
160
+ slice,
161
+ variationId,
162
+ widgetArea,
163
+ previousFieldId,
164
+ newFieldId,
165
+ newField,
166
+ } = args;
167
+
168
+ return {
169
+ ...slice,
170
+ model: {
171
+ ...slice.model,
172
+ variations: slice.model.variations.map((v) => {
173
+ if (v.id === variationId) {
174
+ return {
175
+ ...v,
176
+ [widgetArea]: v[widgetArea]?.map((w) => {
177
+ if (w.key === previousFieldId) {
178
+ return {
179
+ key: newFieldId,
180
+ value: newField,
181
+ };
182
+ }
183
+ return w;
184
+ }),
185
+ };
186
+ }
187
+ return v;
188
+ }),
189
+ },
190
+ };
191
+ }
192
+
193
+ export function addField(args: AddFieldArgs): ComponentUI {
194
+ const { slice, variationId, widgetArea, newFieldId, newField } = args;
195
+
196
+ return {
197
+ ...slice,
198
+ model: {
199
+ ...slice.model,
200
+ variations: slice.model.variations.map((v) => {
201
+ if (v.id === variationId) {
202
+ return {
203
+ ...v,
204
+ [widgetArea]: v[widgetArea]?.concat([
205
+ {
206
+ key: newFieldId,
207
+ value: newField,
208
+ },
209
+ ]),
210
+ };
211
+ }
212
+ return v;
213
+ }),
214
+ },
215
+ };
216
+ }
217
+
218
+ export function reorderField(args: ReorderFieldArgs): ComponentUI {
219
+ const { slice, variationId, widgetArea, sourceIndex, destinationIndex } =
220
+ args;
221
+
222
+ const fields =
223
+ slice.model.variations.find((v) => v.id === variationId)?.[widgetArea] ??
224
+ [];
225
+
226
+ const reorderedFields = [...fields];
227
+ const [removedField] = reorderedFields.splice(sourceIndex, 1);
228
+ reorderedFields.splice(destinationIndex, 0, removedField);
229
+
230
+ return {
231
+ ...slice,
232
+ model: {
233
+ ...slice.model,
234
+ variations: slice.model.variations.map((v) => {
235
+ if (v.id === variationId) {
236
+ return {
237
+ ...v,
238
+ [widgetArea]: reorderedFields,
239
+ };
240
+ }
241
+ return v;
242
+ }),
243
+ },
244
+ };
245
+ }
@@ -0,0 +1,43 @@
1
+ import { FC } from "react";
2
+ import { Box, Icon, ProgressCircle, Text } from "@prismicio/editor-ui";
3
+
4
+ import { AutoSaveStatus } from "./useAutoSave";
5
+
6
+ type AutoSaveStatusIndicatorProps = {
7
+ status: AutoSaveStatus;
8
+ };
9
+
10
+ export const AutoSaveStatusIndicator: FC<AutoSaveStatusIndicatorProps> = (
11
+ props,
12
+ ) => {
13
+ const { status } = props;
14
+ let autoSaveStatusInfo;
15
+
16
+ switch (status) {
17
+ case "saving":
18
+ autoSaveStatusInfo = {
19
+ icon: <ProgressCircle color="grey11" />,
20
+ text: "Saving...",
21
+ };
22
+ break;
23
+ case "failed":
24
+ autoSaveStatusInfo = {
25
+ icon: <Icon name="close" color="tomato11" size="medium" />,
26
+ text: "Failed to save",
27
+ };
28
+ break;
29
+ case "saved":
30
+ autoSaveStatusInfo = {
31
+ icon: <Icon name="check" color="green11" size="medium" />,
32
+ text: "Auto-saved",
33
+ };
34
+ break;
35
+ }
36
+
37
+ return (
38
+ <Box gap={8} alignItems="center">
39
+ {autoSaveStatusInfo.icon}
40
+ <Text color="grey11">{autoSaveStatusInfo.text}</Text>
41
+ </Box>
42
+ );
43
+ };
@@ -0,0 +1,177 @@
1
+ import {
2
+ useCallback,
3
+ useState,
4
+ useEffect,
5
+ SetStateAction,
6
+ Dispatch,
7
+ useMemo,
8
+ } from "react";
9
+ import { uniqueId } from "lodash";
10
+ import { toast } from "react-toastify";
11
+ import { Box, Button, Text } from "@prismicio/editor-ui";
12
+
13
+ export type AutoSaveStatus = "saving" | "saved" | "failed";
14
+
15
+ type UseAutoSaveArgs = {
16
+ autoSaveStatusDelay?: number;
17
+ errorMessage?: string;
18
+ retryDelay?: number;
19
+ retryMessage?: string;
20
+ };
21
+
22
+ type UseAutoSaveReturnType = {
23
+ autoSaveStatus: AutoSaveStatus;
24
+ setNextSave: (nextSave: NextSave) => void;
25
+ };
26
+
27
+ type AutoSaveStack = {
28
+ pendingSave: NextSave | undefined;
29
+ nextSave: NextSave | undefined;
30
+ };
31
+
32
+ type NextSave = () => Promise<unknown>;
33
+
34
+ export const useAutoSave = (
35
+ args: UseAutoSaveArgs = {},
36
+ ): UseAutoSaveReturnType => {
37
+ const {
38
+ autoSaveStatusDelay = 300,
39
+ errorMessage = "An error happened while saving",
40
+ retryDelay = 1000,
41
+ retryMessage = "Retry",
42
+ } = args;
43
+
44
+ const [autoSaveStack, setAutoSaveStack] = useState<AutoSaveStack>({
45
+ pendingSave: undefined,
46
+ nextSave: undefined,
47
+ });
48
+ const [autoSaveStatusActual, setAutoSaveStatusActual] =
49
+ useState<AutoSaveStatus>("saved");
50
+ const [autoSaveStatusDelayed, setAutoSaveStatusDelayed] =
51
+ useState<AutoSaveStatus>(autoSaveStatusActual);
52
+
53
+ const setNextSave = useCallback((nextSave: NextSave) => {
54
+ setAutoSaveStack((prevState) => ({
55
+ ...prevState,
56
+ nextSave,
57
+ }));
58
+ }, []);
59
+
60
+ const executeSave = useCallback(
61
+ async (nextSave?: NextSave) => {
62
+ if (nextSave) {
63
+ setAutoSaveStatusActual("saving");
64
+
65
+ try {
66
+ await nextSave();
67
+
68
+ setAutoSaveStatusActual("saved");
69
+ } catch (error) {
70
+ setAutoSaveStatusActual("failed");
71
+ console.error(errorMessage, error);
72
+
73
+ toastError({
74
+ errorMessage,
75
+ retryDelay,
76
+ retryMessage,
77
+ setAutoSaveStatusActual,
78
+ setAutoSaveStack,
79
+ });
80
+ }
81
+ }
82
+ },
83
+ [errorMessage, retryDelay, retryMessage],
84
+ );
85
+
86
+ useEffect(() => {
87
+ if (autoSaveStatusActual === "saved" && autoSaveStack.nextSave) {
88
+ void executeSave(autoSaveStack.nextSave);
89
+
90
+ setAutoSaveStack({
91
+ pendingSave: autoSaveStack.nextSave,
92
+ nextSave: undefined,
93
+ });
94
+ }
95
+ }, [autoSaveStatusActual, autoSaveStack, executeSave]);
96
+
97
+ useEffect(() => {
98
+ if (autoSaveStatusActual === "saving") {
99
+ setAutoSaveStatusDelayed("saving");
100
+ } else {
101
+ const debounceTimeout = setTimeout(() => {
102
+ setAutoSaveStatusDelayed(autoSaveStatusActual);
103
+ }, autoSaveStatusDelay);
104
+
105
+ return () => {
106
+ clearTimeout(debounceTimeout);
107
+ };
108
+ }
109
+
110
+ return;
111
+ }, [autoSaveStatusActual, autoSaveStatusDelay]);
112
+
113
+ return useMemo(
114
+ () => ({
115
+ autoSaveStatus: autoSaveStatusDelayed,
116
+ setNextSave,
117
+ }),
118
+ [autoSaveStatusDelayed, setNextSave],
119
+ );
120
+ };
121
+
122
+ type ToastErrorArgs = {
123
+ errorMessage: string;
124
+ retryDelay: number;
125
+ retryMessage: string;
126
+ setAutoSaveStatusActual: Dispatch<SetStateAction<AutoSaveStatus>>;
127
+ setAutoSaveStack: Dispatch<SetStateAction<AutoSaveStack>>;
128
+ };
129
+
130
+ function toastError(args: ToastErrorArgs) {
131
+ const {
132
+ errorMessage,
133
+ retryDelay,
134
+ retryMessage,
135
+ setAutoSaveStatusActual,
136
+ setAutoSaveStack,
137
+ } = args;
138
+ const toastId = uniqueId();
139
+
140
+ toast.error(
141
+ () => (
142
+ <Box gap={8} alignItems="center">
143
+ <Text color="grey1" variant="small">
144
+ {errorMessage}
145
+ </Text>
146
+ <Button
147
+ size="small"
148
+ color="grey"
149
+ onClick={() => {
150
+ toast.dismiss(toastId);
151
+
152
+ // Ensure saving is directly propagated before waiting for the retry
153
+ setAutoSaveStatusActual("saving");
154
+
155
+ setTimeout(() => {
156
+ // By setting the status to saved, the save effect will be triggered
157
+ // with the latest data to save.
158
+ setAutoSaveStatusActual("saved");
159
+ setAutoSaveStack((prevState) => ({
160
+ nextSave: prevState.nextSave ?? prevState.pendingSave,
161
+ pendingSave: undefined,
162
+ }));
163
+ }, retryDelay);
164
+ }}
165
+ >
166
+ {retryMessage}
167
+ </Button>
168
+ </Box>
169
+ ),
170
+ {
171
+ autoClose: false,
172
+ closeOnClick: false,
173
+ draggable: false,
174
+ toastId,
175
+ },
176
+ );
177
+ }
@@ -25,12 +25,14 @@ type EditDropdownProps = {
25
25
  isChangesLocal: boolean;
26
26
  format: CustomTypeFormat;
27
27
  customType: CustomType;
28
+ setLocalCustomType?: (customType: CustomType) => void;
28
29
  };
29
30
 
30
31
  export const EditDropdown: FC<EditDropdownProps> = ({
31
32
  format,
32
33
  customType,
33
34
  isChangesLocal,
35
+ setLocalCustomType,
34
36
  }) => {
35
37
  const router = useRouter();
36
38
  const { saveCustomTypeSuccess } = useSliceMachineActions();
@@ -123,6 +125,7 @@ export const EditDropdown: FC<EditDropdownProps> = ({
123
125
  customType={customType}
124
126
  isChangesLocal={isChangesLocal}
125
127
  onClose={() => setIsRenameCustomTypeModalOpen(false)}
128
+ setLocalCustomType={setLocalCustomType}
126
129
  />
127
130
  ) : null}
128
131
  </>
@@ -3,7 +3,7 @@ import { CustomType } from "@prismicio/types-internal/lib/customtypes";
3
3
 
4
4
  import { CustomTypeFormat } from "@slicemachine/manager";
5
5
  import { convertToPageType } from "@src/domain/customType";
6
- import { managerClient } from "@src/managerClient";
6
+ import { updateCustomType } from "@src/apiClient";
7
7
 
8
8
  import { CUSTOM_TYPES_MESSAGES } from "../customTypesMessages";
9
9
 
@@ -16,9 +16,7 @@ export async function convertCustomToPageType(
16
16
 
17
17
  try {
18
18
  const newCustomType = convertToPageType(customType);
19
- await managerClient.customTypes.updateCustomType({
20
- model: newCustomType,
21
- });
19
+ await updateCustomType(newCustomType);
22
20
 
23
21
  // Update the custom type in the redux store
24
22
  saveCustomType(newCustomType);
@@ -0,0 +1,90 @@
1
+ import {
2
+ ReactNode,
3
+ createContext,
4
+ useCallback,
5
+ useContext,
6
+ useMemo,
7
+ useState,
8
+ } from "react";
9
+ import { CustomType } from "@prismicio/types-internal/lib/customtypes";
10
+ import { useStableCallback } from "@prismicio/editor-support/React";
11
+
12
+ import useSliceMachineActions from "@src/modules/useSliceMachineActions";
13
+ import {
14
+ AutoSaveStatus,
15
+ useAutoSave,
16
+ } from "@src/features/autoSave/useAutoSave";
17
+ import { getFormat } from "@src/domain/customType";
18
+ import { updateCustomType } from "@src/apiClient";
19
+
20
+ import { CUSTOM_TYPES_MESSAGES } from "../customTypesMessages";
21
+
22
+ type CustomTypeContext = {
23
+ customType: CustomType;
24
+ autoSaveStatus: AutoSaveStatus;
25
+ setCustomType: (customType: CustomType) => void;
26
+ };
27
+
28
+ type CustomTypeProviderProps = {
29
+ children: ReactNode | ((value: CustomTypeContext) => ReactNode);
30
+ initialCustomType: CustomType;
31
+ };
32
+
33
+ const CustomTypeContextValue = createContext<CustomTypeContext | undefined>(
34
+ undefined,
35
+ );
36
+
37
+ export function CustomTypeProvider(props: CustomTypeProviderProps) {
38
+ const { children, initialCustomType } = props;
39
+
40
+ const [customType, setCustomTypeState] = useState(initialCustomType);
41
+ const format = getFormat(customType);
42
+ const customTypeMessages = CUSTOM_TYPES_MESSAGES[format];
43
+ const { autoSaveStatus, setNextSave } = useAutoSave({
44
+ errorMessage: customTypeMessages.autoSaveFailed,
45
+ });
46
+ const { saveCustomTypeSuccess } = useSliceMachineActions();
47
+ const stableSaveCustomTypeSuccess = useStableCallback(saveCustomTypeSuccess);
48
+
49
+ const setCustomType = useCallback(
50
+ (customType: CustomType) => {
51
+ setCustomTypeState(customType);
52
+ setNextSave(async () => {
53
+ const { errors } = await updateCustomType(customType);
54
+
55
+ if (errors.length > 0) {
56
+ throw errors;
57
+ }
58
+
59
+ // Update available custom types store with new custom type
60
+ stableSaveCustomTypeSuccess(customType);
61
+ });
62
+ },
63
+ [setNextSave, stableSaveCustomTypeSuccess],
64
+ );
65
+
66
+ const contextValue: CustomTypeContext = useMemo(
67
+ () => ({
68
+ autoSaveStatus,
69
+ customType,
70
+ setCustomType,
71
+ }),
72
+ [autoSaveStatus, customType, setCustomType],
73
+ );
74
+
75
+ return (
76
+ <CustomTypeContextValue.Provider value={contextValue}>
77
+ {typeof children === "function" ? children(contextValue) : children}
78
+ </CustomTypeContextValue.Provider>
79
+ );
80
+ }
81
+
82
+ export function useCustomTypeState() {
83
+ const customTypeState = useContext(CustomTypeContextValue);
84
+
85
+ if (!customTypeState) {
86
+ throw new Error("CustomTypeProvider not found");
87
+ }
88
+
89
+ return customTypeState;
90
+ }