Update everything to handle null values in content and description fields

This commit is contained in:
Magdalena Markusik 2021-02-18 13:38:41 +01:00
parent 25f8e29801
commit 9730e44abe
21 changed files with 140 additions and 134 deletions

View file

@ -1,6 +1,7 @@
import { WindowTitle } from "@saleor/components/WindowTitle";
import useNavigator from "@saleor/hooks/useNavigator";
import useNotifier from "@saleor/hooks/useNotifier";
import { getParsedDataForJsonStringField } from "@saleor/translations/utils";
import createMetadataCreateHandler from "@saleor/utils/handlers/metadataCreateHandler";
import {
useMetadataUpdate,
@ -48,7 +49,7 @@ export const CategoryCreateView: React.FC<CategoryCreateViewProps> = ({
const result = await createCategory({
variables: {
input: {
description: JSON.stringify(formData.description),
description: getParsedDataForJsonStringField(formData.description),
name: formData.name,
seo: {
description: formData.seoDescription,

View file

@ -13,6 +13,7 @@ import usePaginator, {
createPaginationState
} from "@saleor/hooks/usePaginator";
import { commonMessages } from "@saleor/intl";
import { getParsedDataForJsonStringField } from "@saleor/translations/utils";
import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers";
import createMetadataUpdateHandler from "@saleor/utils/handlers/metadataUpdateHandler";
import { mapNodeToChoice } from "@saleor/utils/maps";
@ -188,7 +189,7 @@ export const CategoryDetails: React.FC<CategoryDetailsProps> = ({
id,
input: {
backgroundImageAlt: formData.backgroundImageAlt,
description: JSON.stringify(formData.description),
description: getParsedDataForJsonStringField(formData.description),
name: formData.name,
seo: {
description: formData.seoDescription,

View file

@ -7,6 +7,7 @@ import useChannels from "@saleor/hooks/useChannels";
import useNavigator from "@saleor/hooks/useNavigator";
import useNotifier from "@saleor/hooks/useNotifier";
import { commonMessages } from "@saleor/intl";
import { getParsedDataForJsonStringField } from "@saleor/translations/utils";
import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers";
import createMetadataCreateHandler from "@saleor/utils/handlers/metadataCreateHandler";
import {
@ -102,7 +103,7 @@ export const CollectionCreate: React.FC<CollectionCreateProps> = ({
input: {
backgroundImage: formData.backgroundImage.value,
backgroundImageAlt: formData.backgroundImageAlt,
description: JSON.stringify(formData.description),
description: getParsedDataForJsonStringField(formData.description),
name: formData.name,
seo: {
description: formData.seoDescription,

View file

@ -21,6 +21,7 @@ import usePaginator, {
} from "@saleor/hooks/usePaginator";
import { commonMessages } from "@saleor/intl";
import useProductSearch from "@saleor/searches/useProductSearch";
import { getParsedDataForJsonStringField } from "@saleor/translations/utils";
import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers";
import createMetadataUpdateHandler from "@saleor/utils/handlers/metadataUpdateHandler";
import {
@ -198,7 +199,7 @@ export const CollectionDetails: React.FC<CollectionDetailsProps> = ({
const handleUpdate = async (formData: CollectionUpdateData) => {
const input: CollectionInput = {
backgroundImageAlt: formData.backgroundImageAlt,
description: JSON.stringify(formData.description),
description: getParsedDataForJsonStringField(formData.description),
name: formData.name,
seo: {
description: formData.seoDescription,

View file

@ -122,7 +122,7 @@ function usePageForm(
title: page?.title || ""
});
const [content, changeContent] = useRichText({
initial: pageExists ? page?.content : null,
initial: page?.content,
triggerChange
});

View file

@ -12,6 +12,7 @@ import useNotifier from "@saleor/hooks/useNotifier";
import usePageSearch from "@saleor/searches/usePageSearch";
import usePageTypeSearch from "@saleor/searches/usePageTypeSearch";
import useProductSearch from "@saleor/searches/useProductSearch";
import { getParsedDataForJsonStringField } from "@saleor/translations/utils";
import createMetadataCreateHandler from "@saleor/utils/handlers/metadataCreateHandler";
import {
useMetadataUpdate,
@ -128,7 +129,7 @@ export const PageCreate: React.FC<PageCreateProps> = ({ params }) => {
attributes: formData.attributes,
updatedFileAttributes
}),
content: JSON.stringify(formData.content),
content: getParsedDataForJsonStringField(formData.content),
isPublished: formData.isPublished,
pageType: formData.pageType,
publicationDate: formData.publicationDate,

View file

@ -53,7 +53,7 @@ const createPageInput = (
attributes: data.attributes,
updatedFileAttributes
}),
content: JSON.stringify(data.content),
content: !!data.content?.blocks.length ? JSON.stringify(data.content) : null,
isPublished: data.isPublished,
publicationDate: data.publicationDate,
seo: {

View file

@ -37,6 +37,7 @@ import {
} from "@saleor/products/types/VariantCreate";
import { getAvailabilityVariables } from "@saleor/products/utils/handlers";
import { SearchProductTypes_search_edges_node } from "@saleor/searches/types/SearchProductTypes";
import { getParsedDataForJsonStringField } from "@saleor/translations/utils";
import { MutationFetchResult } from "react-apollo";
const getChannelsVariables = (productId: string, channels: ChannelData[]) => ({
@ -108,7 +109,7 @@ export function createHandler(
category: formData.category,
chargeTaxes: formData.chargeTaxes,
collections: formData.collections,
description: JSON.stringify(formData.description),
description: getParsedDataForJsonStringField(formData.description),
name: formData.name,
productType: formData.productType?.id,
rating: formData.rating,

View file

@ -185,7 +185,9 @@ export function createUpdateHandler(
category: data.category,
chargeTaxes: data.chargeTaxes,
collections: data.collections,
description: JSON.stringify(data.description),
description: !!data.description?.blocks?.length
? JSON.stringify(data.description)
: null,
name: data.name,
rating: data.rating,
seo: {

View file

@ -5,7 +5,10 @@ import LanguageSwitch from "@saleor/components/LanguageSwitch";
import PageHeader from "@saleor/components/PageHeader";
import { CategoryTranslationFragment } from "@saleor/fragments/types/CategoryTranslationFragment";
import { commonMessages, sectionNames } from "@saleor/intl";
import { TranslationsEntitiesPageProps } from "@saleor/translations/types";
import {
TranslationInputFieldName,
TranslationsEntitiesPageProps
} from "@saleor/translations/types";
import React from "react";
import { useIntl } from "react-intl";
@ -17,13 +20,6 @@ export interface TranslationsCategoriesPageProps
data: CategoryTranslationFragment;
}
export const fieldNames = {
description: "description",
name: "name",
seoDescription: "seoDescription",
seoTitle: "seoTitle"
};
const TranslationsCategoriesPage: React.FC<TranslationsCategoriesPageProps> = ({
activeField,
disabled,
@ -72,14 +68,14 @@ const TranslationsCategoriesPage: React.FC<TranslationsCategoriesPageProps> = ({
displayName: intl.formatMessage({
defaultMessage: "Category Name"
}),
name: fieldNames.name,
name: TranslationInputFieldName.name,
translation: data?.translation?.name || null,
type: "short" as "short",
value: data?.category?.name
},
{
displayName: intl.formatMessage(commonMessages.description),
name: fieldNames.description,
name: TranslationInputFieldName.description,
translation: data?.translation?.description || null,
type: "rich" as "rich",
value: data?.category?.description
@ -103,7 +99,7 @@ const TranslationsCategoriesPage: React.FC<TranslationsCategoriesPageProps> = ({
displayName: intl.formatMessage({
defaultMessage: "Search Engine Title"
}),
name: fieldNames.seoTitle,
name: TranslationInputFieldName.seoTitle,
translation: data?.translation?.seoTitle || null,
type: "short" as "short",
value: data?.category?.seoTitle
@ -112,7 +108,7 @@ const TranslationsCategoriesPage: React.FC<TranslationsCategoriesPageProps> = ({
displayName: intl.formatMessage({
defaultMessage: "Search Engine Description"
}),
name: fieldNames.seoDescription,
name: TranslationInputFieldName.seoDescription,
translation: data?.translation?.seoDescription || null,
type: "long" as "long",
value: data?.category?.seoDescription

View file

@ -5,7 +5,10 @@ import LanguageSwitch from "@saleor/components/LanguageSwitch";
import PageHeader from "@saleor/components/PageHeader";
import { CollectionTranslationFragment } from "@saleor/fragments/types/CollectionTranslationFragment";
import { commonMessages, sectionNames } from "@saleor/intl";
import { TranslationsEntitiesPageProps } from "@saleor/translations/types";
import {
TranslationInputFieldName,
TranslationsEntitiesPageProps
} from "@saleor/translations/types";
import React from "react";
import { useIntl } from "react-intl";
@ -17,13 +20,6 @@ export interface TranslationsCollectionsPageProps
data: CollectionTranslationFragment;
}
export const fieldNames = {
description: "description",
name: "name",
seoDescription: "seoDescription",
seoTitle: "seoTitle"
};
const TranslationsCollectionsPage: React.FC<TranslationsCollectionsPageProps> = ({
activeField,
disabled,
@ -73,14 +69,14 @@ const TranslationsCollectionsPage: React.FC<TranslationsCollectionsPageProps> =
displayName: intl.formatMessage({
defaultMessage: "Collection Name"
}),
name: fieldNames.name,
name: TranslationInputFieldName.name,
translation: data?.translation?.name || null,
type: "short" as "short",
value: data?.collection?.name
},
{
displayName: intl.formatMessage(commonMessages.description),
name: fieldNames.description,
name: TranslationInputFieldName.description,
translation: data?.translation?.description || null,
type: "rich" as "rich",
value: data?.collection?.description
@ -104,7 +100,7 @@ const TranslationsCollectionsPage: React.FC<TranslationsCollectionsPageProps> =
displayName: intl.formatMessage({
defaultMessage: "Search Engine Title"
}),
name: fieldNames.seoTitle,
name: TranslationInputFieldName.seoTitle,
translation: data?.translation?.seoTitle || null,
type: "short" as "short",
value: data?.collection?.seoTitle
@ -113,7 +109,7 @@ const TranslationsCollectionsPage: React.FC<TranslationsCollectionsPageProps> =
displayName: intl.formatMessage({
defaultMessage: "Search Engine Description"
}),
name: fieldNames.seoDescription,
name: TranslationInputFieldName.seoDescription,
translation: data?.translation?.seoDescription || null,
type: "long" as "long",
value: data?.collection?.seoDescription

View file

@ -5,7 +5,10 @@ import LanguageSwitch from "@saleor/components/LanguageSwitch";
import PageHeader from "@saleor/components/PageHeader";
import { PageTranslationFragment } from "@saleor/fragments/types/PageTranslationFragment";
import { commonMessages, sectionNames } from "@saleor/intl";
import { TranslationsEntitiesPageProps } from "@saleor/translations/types";
import {
PageTranslationInputFieldName,
TranslationsEntitiesPageProps
} from "@saleor/translations/types";
import React from "react";
import { useIntl } from "react-intl";
@ -17,13 +20,6 @@ export interface TranslationsPagesPageProps
data: PageTranslationFragment;
}
export const fieldNames = {
content: "content",
seoDescription: "seoDescription",
seoTitle: "seoTitle",
title: "title"
};
const TranslationsPagesPage: React.FC<TranslationsPagesPageProps> = ({
activeField,
disabled,
@ -72,7 +68,7 @@ const TranslationsPagesPage: React.FC<TranslationsPagesPageProps> = ({
displayName: intl.formatMessage({
defaultMessage: "Page Title"
}),
name: fieldNames.title,
name: PageTranslationInputFieldName.title,
translation: data?.translation?.title || null,
type: "short" as "short",
value: data?.page?.title
@ -82,7 +78,7 @@ const TranslationsPagesPage: React.FC<TranslationsPagesPageProps> = ({
defaultMessage: "Content",
description: "page content"
}),
name: fieldNames.content,
name: PageTranslationInputFieldName.content,
translation: data?.translation?.content || null,
type: "rich" as "rich",
value: data?.page?.content
@ -106,7 +102,7 @@ const TranslationsPagesPage: React.FC<TranslationsPagesPageProps> = ({
displayName: intl.formatMessage({
defaultMessage: "Search Engine Title"
}),
name: fieldNames.seoTitle,
name: PageTranslationInputFieldName.seoTitle,
translation: data?.translation?.seoTitle || null,
type: "short" as "short",
value: data?.page?.seoTitle
@ -115,7 +111,7 @@ const TranslationsPagesPage: React.FC<TranslationsPagesPageProps> = ({
displayName: intl.formatMessage({
defaultMessage: "Search Engine Description"
}),
name: fieldNames.seoDescription,
name: PageTranslationInputFieldName.seoDescription,
translation: data?.translation?.seoDescription || null,
type: "long" as "long",
value: data?.page?.seoDescription

View file

@ -5,7 +5,10 @@ import LanguageSwitch from "@saleor/components/LanguageSwitch";
import PageHeader from "@saleor/components/PageHeader";
import { ProductTranslationFragment } from "@saleor/fragments/types/ProductTranslationFragment";
import { commonMessages, sectionNames } from "@saleor/intl";
import { TranslationsEntitiesPageProps } from "@saleor/translations/types";
import {
TranslationInputFieldName,
TranslationsEntitiesPageProps
} from "@saleor/translations/types";
import React from "react";
import { useIntl } from "react-intl";
@ -17,13 +20,6 @@ export interface TranslationsProductsPageProps
data: ProductTranslationFragment;
}
export const fieldNames = {
description: "description",
name: "name",
seoDescription: "seoDescription",
seoTitle: "seoTitle"
};
const TranslationsProductsPage: React.FC<TranslationsProductsPageProps> = ({
activeField,
disabled,
@ -73,7 +69,7 @@ const TranslationsProductsPage: React.FC<TranslationsProductsPageProps> = ({
displayName: intl.formatMessage({
defaultMessage: "Product Name"
}),
name: fieldNames.name,
name: TranslationInputFieldName.name,
translation: data?.translation?.name || null,
type: "short" as "short",
value: data?.product?.name
@ -82,7 +78,7 @@ const TranslationsProductsPage: React.FC<TranslationsProductsPageProps> = ({
displayName: intl.formatMessage({
defaultMessage: "Description"
}),
name: fieldNames.description,
name: TranslationInputFieldName.description,
translation: data?.translation?.description || null,
type: "rich" as "rich",
value: data?.product?.description
@ -106,7 +102,7 @@ const TranslationsProductsPage: React.FC<TranslationsProductsPageProps> = ({
displayName: intl.formatMessage({
defaultMessage: "Search Engine Title"
}),
name: fieldNames.seoTitle,
name: TranslationInputFieldName.seoTitle,
translation: data?.translation?.seoTitle || null,
type: "short" as "short",
value: data?.product?.seoTitle
@ -115,7 +111,7 @@ const TranslationsProductsPage: React.FC<TranslationsProductsPageProps> = ({
displayName: intl.formatMessage({
defaultMessage: "Search Engine Description"
}),
name: fieldNames.seoDescription,
name: TranslationInputFieldName.seoDescription,
translation: data?.translation?.seoDescription || null,
type: "long" as "long",
value: data?.product?.seoDescription

View file

@ -107,6 +107,7 @@ const updateCategoryTranslations = gql`
}
}
`;
export const TypedUpdateCategoryTranslations = TypedMutation<
UpdateCategoryTranslations,
UpdateCategoryTranslationsVariables
@ -143,6 +144,7 @@ const updateCollectionTranslations = gql`
}
}
`;
export const TypedUpdateCollectionTranslations = TypedMutation<
UpdateCollectionTranslations,
UpdateCollectionTranslationsVariables

View file

@ -14,3 +14,17 @@ export interface TranslationsEntitiesPageProps {
onLanguageChange: (lang: string) => void;
onSubmit: (field: string, data: string | OutputData) => void;
}
export enum TranslationInputFieldName {
description = "description",
name = "name",
seoDescription = "seoDescription",
seoTitle = "seoTitle"
}
export enum PageTranslationInputFieldName {
content = "content",
title = "title",
seoDescription = "seoDescription",
seoTitle = "seoTitle"
}

24
src/translations/utils.ts Normal file
View file

@ -0,0 +1,24 @@
import { OutputData } from "@editorjs/editorjs";
import { TranslationInput } from "@saleor/types/globalTypes";
import { TranslationInputFieldName } from "./types";
export const getParsedTranslationInputData = ({
fieldName,
data
}: {
fieldName: keyof TranslationInput;
data: string | OutputData;
}): Record<string, string | null> => {
if (fieldName === TranslationInputFieldName.description) {
return {
description: getParsedDataForJsonStringField(data as OutputData)
};
}
return { [fieldName]: data as string };
};
export const getParsedDataForJsonStringField = (
data: OutputData
): string | null => (!!data.blocks?.length ? JSON.stringify(data) : null);

View file

@ -1,3 +1,4 @@
import { OutputData } from "@editorjs/editorjs";
import useNavigator from "@saleor/hooks/useNavigator";
import useNotifier from "@saleor/hooks/useNotifier";
import useShop from "@saleor/hooks/useShop";
@ -6,18 +7,18 @@ import { stringify as stringifyQs } from "qs";
import React from "react";
import { useIntl } from "react-intl";
import { LanguageCodeEnum, TranslationInput } from "../../types/globalTypes";
import TranslationsCategoriesPage, {
fieldNames
} from "../components/TranslationsCategoriesPage";
import { LanguageCodeEnum } from "../../types/globalTypes";
import TranslationsCategoriesPage from "../components/TranslationsCategoriesPage";
import { TypedUpdateCategoryTranslations } from "../mutations";
import { useCategoryTranslationDetails } from "../queries";
import { TranslationInputFieldName } from "../types";
import { UpdateCategoryTranslations } from "../types/UpdateCategoryTranslations";
import {
languageEntitiesUrl,
languageEntityUrl,
TranslatableEntities
} from "../urls";
import { getParsedTranslationInputData } from "../utils";
export interface TranslationsCategoriesQueryParams {
activeField: string;
@ -67,25 +68,19 @@ const TranslationsCategories: React.FC<TranslationsCategoriesProps> = ({
return (
<TypedUpdateCategoryTranslations onCompleted={onUpdate}>
{(updateTranslations, updateTranslationsOpts) => {
const handleSubmit = (field: string, data: string) => {
const input: TranslationInput = {};
if (field === fieldNames.description) {
input.description = JSON.stringify(data);
} else if (field === fieldNames.name) {
input.name = data;
} else if (field === fieldNames.seoDescription) {
input.seoDescription = data;
} else if (field === fieldNames.seoTitle) {
input.seoTitle = data;
}
const handleSubmit = (
fieldName: TranslationInputFieldName,
data: string | OutputData
) => {
updateTranslations({
variables: {
id,
input,
input: getParsedTranslationInputData({ data, fieldName }),
language: languageCode
}
});
};
const translation = categoryTranslations?.data?.translation;
return (

View file

@ -7,18 +7,18 @@ import React from "react";
import { useIntl } from "react-intl";
import { maybe } from "../../misc";
import { LanguageCodeEnum, TranslationInput } from "../../types/globalTypes";
import TranslationsCollectionsPage, {
fieldNames
} from "../components/TranslationsCollectionsPage";
import { LanguageCodeEnum } from "../../types/globalTypes";
import TranslationsCollectionsPage from "../components/TranslationsCollectionsPage";
import { TypedUpdateCollectionTranslations } from "../mutations";
import { useCollectionTranslationDetails } from "../queries";
import { TranslationInputFieldName } from "../types";
import { UpdateCollectionTranslations } from "../types/UpdateCollectionTranslations";
import {
languageEntitiesUrl,
languageEntityUrl,
TranslatableEntities
} from "../urls";
import { getParsedTranslationInputData } from "../utils";
export interface TranslationsCollectionsQueryParams {
activeField: string;
@ -69,21 +69,14 @@ const TranslationsCollections: React.FC<TranslationsCollectionsProps> = ({
return (
<TypedUpdateCollectionTranslations onCompleted={onUpdate}>
{(updateTranslations, updateTranslationsOpts) => {
const handleSubmit = (field: string, data: string) => {
const input: TranslationInput = {};
if (field === fieldNames.description) {
input.description = JSON.stringify(data);
} else if (field === fieldNames.name) {
input.name = data;
} else if (field === fieldNames.seoDescription) {
input.seoDescription = data;
} else if (field === fieldNames.seoTitle) {
input.seoTitle = data;
}
const handleSubmit = (
fieldName: TranslationInputFieldName,
data: string
) => {
updateTranslations({
variables: {
id,
input,
input: getParsedTranslationInputData({ data, fieldName }),
language: languageCode
}
});

View file

@ -6,21 +6,18 @@ import { stringify as stringifyQs } from "qs";
import React from "react";
import { useIntl } from "react-intl";
import {
LanguageCodeEnum,
PageTranslationInput
} from "../../types/globalTypes";
import TranslationsPagesPage, {
fieldNames
} from "../components/TranslationsPagesPage";
import { LanguageCodeEnum } from "../../types/globalTypes";
import TranslationsPagesPage from "../components/TranslationsPagesPage";
import { TypedUpdatePageTranslations } from "../mutations";
import { usePageTranslationDetails } from "../queries";
import { TranslationInputFieldName } from "../types";
import { UpdatePageTranslations } from "../types/UpdatePageTranslations";
import {
languageEntitiesUrl,
languageEntityUrl,
TranslatableEntities
} from "../urls";
import { getParsedTranslationInputData } from "../utils";
export interface TranslationsPagesQueryParams {
activeField: string;
@ -70,21 +67,14 @@ const TranslationsPages: React.FC<TranslationsPagesProps> = ({
return (
<TypedUpdatePageTranslations onCompleted={onUpdate}>
{(updateTranslations, updateTranslationsOpts) => {
const handleSubmit = (field: string, data: string) => {
const input: PageTranslationInput = {};
if (field === fieldNames.content) {
input.content = JSON.stringify(data);
} else if (field === fieldNames.title) {
input.title = data;
} else if (field === fieldNames.seoDescription) {
input.seoDescription = data;
} else if (field === fieldNames.seoTitle) {
input.seoTitle = data;
}
const handleSubmit = (
fieldName: TranslationInputFieldName,
data: string
) => {
updateTranslations({
variables: {
id,
input,
input: getParsedTranslationInputData({ data, fieldName }),
language: languageCode
}
});

View file

@ -7,18 +7,18 @@ import React from "react";
import { useIntl } from "react-intl";
import { maybe } from "../../misc";
import { LanguageCodeEnum, TranslationInput } from "../../types/globalTypes";
import TranslationsProductsPage, {
fieldNames
} from "../components/TranslationsProductsPage";
import { LanguageCodeEnum } from "../../types/globalTypes";
import TranslationsProductsPage from "../components/TranslationsProductsPage";
import { TypedUpdateProductTranslations } from "../mutations";
import { useProductTranslationDetails } from "../queries";
import { TranslationInputFieldName } from "../types";
import { UpdateProductTranslations } from "../types/UpdateProductTranslations";
import {
languageEntitiesUrl,
languageEntityUrl,
TranslatableEntities
} from "../urls";
import { getParsedTranslationInputData } from "../utils";
export interface TranslationsProductsQueryParams {
activeField: string;
@ -68,21 +68,14 @@ const TranslationsProducts: React.FC<TranslationsProductsProps> = ({
return (
<TypedUpdateProductTranslations onCompleted={onUpdate}>
{(updateTranslations, updateTranslationsOpts) => {
const handleSubmit = (field: string, data: string) => {
const input: TranslationInput = {};
if (field === fieldNames.description) {
input.description = JSON.stringify(data);
} else if (field === fieldNames.name) {
input.name = data;
} else if (field === fieldNames.seoDescription) {
input.seoDescription = data;
} else if (field === fieldNames.seoTitle) {
input.seoTitle = data;
}
const handleSubmit = (
fieldName: TranslationInputFieldName,
data: string
) => {
updateTranslations({
variables: {
id,
input,
input: getParsedTranslationInputData({ data, fieldName }),
language: languageCode
}
});

View file

@ -6,18 +6,21 @@ function useRichText(opts: {
initial: string | null;
triggerChange: () => void;
}): [MutableRefObject<OutputData>, RichTextEditorChange] {
const data = useRef<OutputData>(
opts.initial === null ? { blocks: [] } : undefined
);
const data = useRef<OutputData>();
const [, setLoaded] = useState(false);
useEffect(() => {
if (opts.initial !== null) {
try {
data.current = JSON.parse(opts.initial);
setLoaded(true);
} catch {
data.current = undefined;
}
if (opts.initial === null) {
data.current = { blocks: [] };
setLoaded(true);
return;
}
try {
data.current = JSON.parse(opts.initial);
setLoaded(true);
} catch {
data.current = undefined;
}
}, [opts.initial]);