import { useStableCallback } from "@prismicio/editor-support/React"; import { useRouter } from "next/router"; import { createContext, ReactNode, useCallback, useContext, useMemo, useState, } from "react"; import { readSliceMocks, updateSlice } from "@/apiClient"; import { useAutoSync } from "@/features/sync/AutoSyncProvider"; import { ActionQueueStatus, useActionQueue } from "@/hooks/useActionQueue"; import { ComponentUI } from "@/legacy/lib/models/common/ComponentUI"; import { VariationSM } from "@/legacy/lib/models/common/Slice"; import useSliceMachineActions from "@/modules/useSliceMachineActions"; type SliceContext = { slice: ComponentUI; actionQueueStatus: ActionQueueStatus; setSlice: (slice: ComponentUI, onSaveCallback?: () => void) => void; variation: VariationSM; }; type SliceBuilderProviderProps = { children: ReactNode | ((value: SliceContext) => ReactNode); initialSlice: ComponentUI; }; const SliceContextValue = createContext(undefined); export function SliceBuilderProvider(props: SliceBuilderProviderProps) { const { children, initialSlice } = props; const router = useRouter(); const [slice, setSliceState] = useState(initialSlice); const { actionQueueStatus, setNextAction } = useActionQueue({ errorMessage: "Failed to save slice. Check your browser's console for more information.", }); const { saveSliceSuccess } = useSliceMachineActions(); const stableSaveSliceSuccess = useStableCallback(saveSliceSuccess); const { syncChanges } = useAutoSync(); const variation = useMemo(() => { const variationName = router.query.variation; const v = slice.model.variations.find( (variation) => variation.id === variationName, ); if (v) { return v; } throw new Error("Variation not found"); }, [slice, router]); const setSlice = useCallback( (slice: ComponentUI, onSaveCallback?: () => void) => { setSliceState(slice); setNextAction(async () => { const { errors: updateSliceErrors } = await updateSlice(slice); if (updateSliceErrors.length > 0) { throw updateSliceErrors; } const { errors: readSliceMockErrors, mocks } = await readSliceMocks({ libraryID: slice.from, sliceID: slice.model.id, }); if (readSliceMockErrors.length > 0) { throw readSliceMockErrors; } // Update slices store with new slice stableSaveSliceSuccess({ ...slice, mocks }); syncChanges(); onSaveCallback?.(); }); }, [setNextAction, stableSaveSliceSuccess, syncChanges], ); const contextValue: SliceContext = useMemo( () => ({ actionQueueStatus, slice, setSlice, variation, }), [actionQueueStatus, slice, setSlice, variation], ); return ( {typeof children === "function" ? children(contextValue) : children} ); } export function useSliceState() { const sliceState = useContext(SliceContextValue); if (!sliceState) { throw new Error("SliceBuilderProvider not found"); } return sliceState; }