From ba4edd98056d2adc844ed6200422b8ee783b5327 Mon Sep 17 00:00:00 2001 From: Nar Cuenca Date: Mon, 23 Sep 2024 11:29:18 +0800 Subject: [PATCH 01/15] task: update widths --- .../src/app/views/ItemCreate/ItemCreate.tsx | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/apps/content-editor/src/app/views/ItemCreate/ItemCreate.tsx b/src/apps/content-editor/src/app/views/ItemCreate/ItemCreate.tsx index 2f1e47da01..0fa2b801d1 100644 --- a/src/apps/content-editor/src/app/views/ItemCreate/ItemCreate.tsx +++ b/src/apps/content-editor/src/app/views/ItemCreate/ItemCreate.tsx @@ -382,7 +382,7 @@ export const ItemCreate = () => { direction="row" gap={4} > - + {saveClicked && (hasErrors || hasSEOErrors) && ( { /> - + From eaaf5b8a88ae8a45b51e6028877d4f386f4d240a Mon Sep 17 00:00:00 2001 From: Nar Cuenca Date: Mon, 23 Sep 2024 11:40:26 +0800 Subject: [PATCH 02/15] task: update widths --- .../src/app/views/ItemEdit/Meta/index.tsx | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/apps/content-editor/src/app/views/ItemEdit/Meta/index.tsx b/src/apps/content-editor/src/app/views/ItemEdit/Meta/index.tsx index ab591f91dd..8ee5e8dfe8 100644 --- a/src/apps/content-editor/src/app/views/ItemEdit/Meta/index.tsx +++ b/src/apps/content-editor/src/app/views/ItemEdit/Meta/index.tsx @@ -249,8 +249,9 @@ export const Meta = forwardRef( scrollbarWidth: "none", overflowY: "auto", }} + height="100%" > - + {!!errorComponent && errorComponent} @@ -374,6 +375,7 @@ export const Meta = forwardRef( {model?.type !== "dataset" && !isCreateItemPage && ( - - - + + + + + )} From 30893e16d25b856429661d83c96ee8a58554b7a3 Mon Sep 17 00:00:00 2001 From: Nar Cuenca Date: Mon, 23 Sep 2024 12:25:43 +0800 Subject: [PATCH 03/15] fix: only show asterisk when field is required --- .../src/app/views/ItemEdit/Meta/settings/OGTitle.tsx | 2 +- .../src/app/views/ItemEdit/Meta/settings/TCTitle.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/apps/content-editor/src/app/views/ItemEdit/Meta/settings/OGTitle.tsx b/src/apps/content-editor/src/app/views/ItemEdit/Meta/settings/OGTitle.tsx index a5935a0024..fb28d0323f 100644 --- a/src/apps/content-editor/src/app/views/ItemEdit/Meta/settings/OGTitle.tsx +++ b/src/apps/content-editor/src/app/views/ItemEdit/Meta/settings/OGTitle.tsx @@ -18,7 +18,7 @@ export const OGTitle = ({ value, onChange, error, field }: OGTitleProps) => { { Date: Tue, 24 Sep 2024 09:32:52 +0800 Subject: [PATCH 04/15] task: prevent changing tabs when click save in the pending edit modal when save fails --- .../src/app/views/ItemEdit/ItemEdit.js | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/apps/content-editor/src/app/views/ItemEdit/ItemEdit.js b/src/apps/content-editor/src/app/views/ItemEdit/ItemEdit.js index af848509d6..ff3d6293f5 100644 --- a/src/apps/content-editor/src/app/views/ItemEdit/ItemEdit.js +++ b/src/apps/content-editor/src/app/views/ItemEdit/ItemEdit.js @@ -292,11 +292,17 @@ export default function ItemEdit() { async function save() { setSaveClicked(true); - if (hasErrors || hasSEOErrors || metaRef.current?.validateMetaFields?.()) - return; - - setSaving(true); try { + if ( + hasErrors || + hasSEOErrors || + metaRef.current?.validateMetaFields?.() + ) { + throw new Error(`Cannot Save: ${item.web.metaTitle}`); + } + + setSaving(true); + // Skip content item fields validation when in the meta tab since this // means that the user only wants to update the meta fields const res = await dispatch( @@ -412,6 +418,7 @@ export default function ItemEdit() { } function discard() { + console.log("discard changes"); dispatch({ type: "UNMARK_ITEMS_DIRTY", items: [itemZUID], From cccf207df0ee960ed2d3bce91608cfb24c8c5bd9 Mon Sep 17 00:00:00 2001 From: Nar Cuenca Date: Tue, 24 Sep 2024 09:38:14 +0800 Subject: [PATCH 05/15] task: do not show social media preview when creating a dataset item --- src/apps/content-editor/src/app/views/ItemCreate/ItemCreate.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/apps/content-editor/src/app/views/ItemCreate/ItemCreate.tsx b/src/apps/content-editor/src/app/views/ItemCreate/ItemCreate.tsx index 0fa2b801d1..2bba258423 100644 --- a/src/apps/content-editor/src/app/views/ItemCreate/ItemCreate.tsx +++ b/src/apps/content-editor/src/app/views/ItemCreate/ItemCreate.tsx @@ -432,7 +432,7 @@ export const ItemCreate = () => { width="40%" maxWidth={620} > - + {model?.type !== "dataset" && } From b05af26609882e3a0b37071b90e1968de93e3ce8 Mon Sep 17 00:00:00 2001 From: Nar Cuenca Date: Tue, 24 Sep 2024 09:49:33 +0800 Subject: [PATCH 06/15] task: show the content analytics for dataset items --- .../src/app/views/ItemEdit/Meta/index.tsx | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/apps/content-editor/src/app/views/ItemEdit/Meta/index.tsx b/src/apps/content-editor/src/app/views/ItemEdit/Meta/index.tsx index 8ee5e8dfe8..679c186ceb 100644 --- a/src/apps/content-editor/src/app/views/ItemEdit/Meta/index.tsx +++ b/src/apps/content-editor/src/app/views/ItemEdit/Meta/index.tsx @@ -373,7 +373,7 @@ export const Meta = forwardRef( /> - {model?.type !== "dataset" && !isCreateItemPage && ( + {!isCreateItemPage && ( - - + {model?.type !== "dataset" && ( + <> + + + + )} From 619ee4f26f24b6b236bdd7666da1b2cba4dafd28 Mon Sep 17 00:00:00 2001 From: Nar Cuenca Date: Tue, 24 Sep 2024 10:03:15 +0800 Subject: [PATCH 07/15] fix: remove set height --- .../src/app/views/ItemEdit/Meta/ContentInsights/WordCount.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/apps/content-editor/src/app/views/ItemEdit/Meta/ContentInsights/WordCount.tsx b/src/apps/content-editor/src/app/views/ItemEdit/Meta/ContentInsights/WordCount.tsx index 4478d5b120..509527f0f3 100644 --- a/src/apps/content-editor/src/app/views/ItemEdit/Meta/ContentInsights/WordCount.tsx +++ b/src/apps/content-editor/src/app/views/ItemEdit/Meta/ContentInsights/WordCount.tsx @@ -13,7 +13,6 @@ export const WordCount = ({ return ( Date: Tue, 24 Sep 2024 10:03:31 +0800 Subject: [PATCH 08/15] task: bump zesty/material version --- package-lock.json | 14 +++++++------- package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4435c8d046..e54452f580 100644 --- a/package-lock.json +++ b/package-lock.json @@ -30,7 +30,7 @@ "@tinymce/tinymce-react": "^4.3.0", "@welldone-software/why-did-you-render": "^6.1.1", "@zesty-io/core": "1.10.0", - "@zesty-io/material": "^0.15.3", + "@zesty-io/material": "^0.15.4", "chart.js": "^3.8.0", "chartjs-adapter-moment": "^1.0.1", "chartjs-plugin-datalabels": "^2.0.0", @@ -3911,9 +3911,9 @@ } }, "node_modules/@zesty-io/material": { - "version": "0.15.3", - "resolved": "https://registry.npmjs.org/@zesty-io/material/-/material-0.15.3.tgz", - "integrity": "sha512-zJOagsYexWOq1Bw+L0X1nSKTL+aZkB7MZPCqW53uqAwnKMZ3mejpsOjJwvzoYtm+6oJ6RHQJu0xmNbPXCcjLKA==", + "version": "0.15.4", + "resolved": "https://registry.npmjs.org/@zesty-io/material/-/material-0.15.4.tgz", + "integrity": "sha512-+0QOEmd4B/JIEz1YSk0fE0v0Fl+Siyc2kwUYQJCz1ZATqBHG/INyUxz/kOXdStQFFOeGlElJQDvRYDc1IcDdmw==", "dependencies": { "@emotion/react": "^11.9.0", "@emotion/styled": "^11.8.1", @@ -18396,9 +18396,9 @@ } }, "@zesty-io/material": { - "version": "0.15.3", - "resolved": "https://registry.npmjs.org/@zesty-io/material/-/material-0.15.3.tgz", - "integrity": "sha512-zJOagsYexWOq1Bw+L0X1nSKTL+aZkB7MZPCqW53uqAwnKMZ3mejpsOjJwvzoYtm+6oJ6RHQJu0xmNbPXCcjLKA==", + "version": "0.15.4", + "resolved": "https://registry.npmjs.org/@zesty-io/material/-/material-0.15.4.tgz", + "integrity": "sha512-+0QOEmd4B/JIEz1YSk0fE0v0Fl+Siyc2kwUYQJCz1ZATqBHG/INyUxz/kOXdStQFFOeGlElJQDvRYDc1IcDdmw==", "requires": { "@emotion/react": "^11.9.0", "@emotion/styled": "^11.8.1", diff --git a/package.json b/package.json index 0a1397272c..3188010ab3 100644 --- a/package.json +++ b/package.json @@ -59,7 +59,7 @@ "@tinymce/tinymce-react": "^4.3.0", "@welldone-software/why-did-you-render": "^6.1.1", "@zesty-io/core": "1.10.0", - "@zesty-io/material": "^0.15.3", + "@zesty-io/material": "^0.15.4", "chart.js": "^3.8.0", "chartjs-adapter-moment": "^1.0.1", "chartjs-plugin-datalabels": "^2.0.0", From 30696eb8abc024caafdb2ec5250c1f75171e9f8b Mon Sep 17 00:00:00 2001 From: Nar Cuenca Date: Tue, 24 Sep 2024 11:46:59 +0800 Subject: [PATCH 09/15] fix: always scroll to error blurb on save error --- .../src/app/components/Editor/FieldError.tsx | 212 ++++++++++-------- .../PendingEditsModal/PendingEditsModal.tsx | 1 + .../src/app/views/ItemCreate/ItemCreate.tsx | 8 +- .../src/app/views/ItemEdit/Content/Content.js | 1 + .../src/app/views/ItemEdit/ItemEdit.js | 10 +- 5 files changed, 133 insertions(+), 99 deletions(-) diff --git a/src/apps/content-editor/src/app/components/Editor/FieldError.tsx b/src/apps/content-editor/src/app/components/Editor/FieldError.tsx index dd57ebd61a..dfb8a3b700 100644 --- a/src/apps/content-editor/src/app/components/Editor/FieldError.tsx +++ b/src/apps/content-editor/src/app/components/Editor/FieldError.tsx @@ -1,4 +1,10 @@ -import { useMemo, useRef, useEffect } from "react"; +import { + useMemo, + useRef, + useEffect, + forwardRef, + useImperativeHandle, +} from "react"; import { Stack, Typography, Box, ThemeProvider } from "@mui/material"; import DangerousRoundedIcon from "@mui/icons-material/DangerousRounded"; import { theme } from "@zesty-io/material"; @@ -64,97 +70,115 @@ const getErrorMessage = (errors: Error) => { return errorMessages; }; -export const FieldError = ({ errors, fields }: FieldErrorProps) => { - const errorContainerEl = useRef(null); - - // Scroll to the errors on mount - useEffect(() => { - errorContainerEl?.current?.scrollIntoView({ - behavior: "smooth", - block: "center", - inline: "center", - }); - }, []); - - const fieldErrors = useMemo(() => { - const errorMap = Object.entries(errors)?.map(([name, errorDetails]) => { - const errorMessages = getErrorMessage(errorDetails); - - const fieldData = fields?.find((field) => field.name === name); - - return { - label: - fieldData?.label || - SEO_FIELD_LABELS[name as keyof typeof SEO_FIELD_LABELS], - errorMessages, - sort: fieldData?.sort, - ZUID: fieldData?.ZUID || name, - }; - }); - - return errorMap.sort((a, b) => a.sort - b.sort); - }, [errors, fields]); - - const fieldsWithErrors = fieldErrors?.filter( - (error) => error.errorMessages.length > 0 - ); - - const handleErrorClick = (fieldZUID: string) => { - const fieldElement = document.getElementById(fieldZUID); - fieldElement?.scrollIntoView({ behavior: "smooth" }); - }; - - return ( - - - - - Item cannot be saved due to invalid field values. - - - Please correct the following {fieldsWithErrors?.length} field - {fieldsWithErrors?.length > 1 && "s"} before saving: - - - {fieldErrors?.map((error, index) => { - if (error.errorMessages.length > 0) { - return ( - - handleErrorClick(error.ZUID)} - > - {error.label} - - {error.errorMessages.length === 1 ? ( - - {error.errorMessages[0]} - ) : ( - - {error.errorMessages.map((msg, idx) => ( -
  • {msg}
  • - ))} +export const FieldError = forwardRef( + ({ errors, fields }: FieldErrorProps, ref) => { + const errorContainerEl = useRef(null); + + useImperativeHandle( + ref, + () => { + return { + scrollToErrors() { + errorContainerEl?.current?.scrollIntoView({ + behavior: "smooth", + block: "center", + inline: "center", + }); + }, + }; + }, + [errorContainerEl] + ); + + // Scroll to the errors on mount + useEffect(() => { + errorContainerEl?.current?.scrollIntoView({ + behavior: "smooth", + block: "center", + inline: "center", + }); + }, []); + + const fieldErrors = useMemo(() => { + const errorMap = Object.entries(errors)?.map(([name, errorDetails]) => { + const errorMessages = getErrorMessage(errorDetails); + + const fieldData = fields?.find((field) => field.name === name); + + return { + label: + fieldData?.label || + SEO_FIELD_LABELS[name as keyof typeof SEO_FIELD_LABELS], + errorMessages, + sort: fieldData?.sort, + ZUID: fieldData?.ZUID || name, + }; + }); + + return errorMap.sort((a, b) => a.sort - b.sort); + }, [errors, fields]); + + const fieldsWithErrors = fieldErrors?.filter( + (error) => error.errorMessages.length > 0 + ); + + const handleErrorClick = (fieldZUID: string) => { + const fieldElement = document.getElementById(fieldZUID); + fieldElement?.scrollIntoView({ behavior: "smooth" }); + }; + + return ( + + + + + Item cannot be saved due to invalid field values. + + + Please correct the following {fieldsWithErrors?.length} field + {fieldsWithErrors?.length > 1 && "s"} before saving: + + + {fieldErrors?.map((error, index) => { + if (error.errorMessages.length > 0) { + return ( + + handleErrorClick(error.ZUID)} + > + {error.label} - )} - - ); - } - })} - - - - ); -}; + {error.errorMessages.length === 1 ? ( + - {error.errorMessages[0]} + ) : ( + + {error.errorMessages.map((msg, idx) => ( +
  • {msg}
  • + ))} +
    + )} +
    + ); + } + })} +
    +
    +
    + ); + } +); diff --git a/src/apps/content-editor/src/app/components/PendingEditsModal/PendingEditsModal.tsx b/src/apps/content-editor/src/app/components/PendingEditsModal/PendingEditsModal.tsx index d0d789e270..f55257c2c4 100644 --- a/src/apps/content-editor/src/app/components/PendingEditsModal/PendingEditsModal.tsx +++ b/src/apps/content-editor/src/app/components/PendingEditsModal/PendingEditsModal.tsx @@ -51,6 +51,7 @@ export default memo(function PendingEditsModal(props: PendingEditsModalProps) { answer(true); }) .catch((err) => { + console.error(err); // @ts-ignore answer(false); }) diff --git a/src/apps/content-editor/src/app/views/ItemCreate/ItemCreate.tsx b/src/apps/content-editor/src/app/views/ItemCreate/ItemCreate.tsx index 2bba258423..fe14bae4f1 100644 --- a/src/apps/content-editor/src/app/views/ItemCreate/ItemCreate.tsx +++ b/src/apps/content-editor/src/app/views/ItemCreate/ItemCreate.tsx @@ -84,6 +84,7 @@ export const ItemCreate = () => { // const [hasSEOErrors, setHasSEOErrors] = useState(false); const [SEOErrors, setSEOErrors] = useState({}); const metaRef = useRef(null); + const fieldErrorRef = useRef(null); const [ createPublishing, @@ -182,7 +183,10 @@ export const ItemCreate = () => { setSaveClicked(true); metaRef.current?.validateMetaFields?.(); - if (hasErrors || hasSEOErrors) return; + if (hasErrors || hasSEOErrors) { + fieldErrorRef.current?.scrollToErrors?.(); + return; + } setSaving(true); @@ -266,6 +270,7 @@ export const ItemCreate = () => { setFieldErrors(errors); // scroll to required field + fieldErrorRef.current?.scrollToErrors?.(); } if (res.error) { @@ -385,6 +390,7 @@ export const ItemCreate = () => { {saveClicked && (hasErrors || hasSEOErrors) && ( diff --git a/src/apps/content-editor/src/app/views/ItemEdit/Content/Content.js b/src/apps/content-editor/src/app/views/ItemEdit/Content/Content.js index fea87575c6..39b45db8a3 100644 --- a/src/apps/content-editor/src/app/views/ItemEdit/Content/Content.js +++ b/src/apps/content-editor/src/app/views/ItemEdit/Content/Content.js @@ -74,6 +74,7 @@ export default function Content(props) { {props.saveClicked && props.hasErrors && ( diff --git a/src/apps/content-editor/src/app/views/ItemEdit/ItemEdit.js b/src/apps/content-editor/src/app/views/ItemEdit/ItemEdit.js index ff3d6293f5..398291f500 100644 --- a/src/apps/content-editor/src/app/views/ItemEdit/ItemEdit.js +++ b/src/apps/content-editor/src/app/views/ItemEdit/ItemEdit.js @@ -82,6 +82,7 @@ export default function ItemEdit() { const location = useLocation(); const { modelZUID, itemZUID } = useParams(); const metaRef = useRef(null); + const fieldErrorRef = useRef(null); const item = useSelector((state) => state.content[itemZUID]); const items = useSelector((state) => state.content); const model = useSelector((state) => state.models[modelZUID]); @@ -403,12 +404,12 @@ export default function ItemEdit() { // fetch new draft history dispatch(fetchAuditTrailDrafting(itemZUID)); } catch (err) { - console.error(err); // we need to set the item to dirty again because the save failed dispatch({ type: "MARK_ITEM_DIRTY", itemZUID, }); + fieldErrorRef.current?.scrollToErrors?.(); throw new Error(err); } finally { if (isMounted.current) { @@ -418,7 +419,6 @@ export default function ItemEdit() { } function discard() { - console.log("discard changes"); dispatch({ type: "UNMARK_ITEMS_DIRTY", items: [itemZUID], @@ -480,7 +480,7 @@ export default function ItemEdit() { sx={{ display: "flex", flexDirection: "column", height: "100%" }} > save().catch((err) => console.error(err))} saving={saving} hasError={Object.keys(fieldErrors)?.length} headerTitle={headerTitle} @@ -523,6 +523,7 @@ export default function ItemEdit() { saveClicked && hasSEOErrors && ( @@ -592,7 +593,7 @@ export default function ItemEdit() { item={item} items={items} user={user} - onSave={save} + onSave={() => save().catch((err) => console.error(err))} dispatch={dispatch} loading={loading} saving={saving} @@ -603,6 +604,7 @@ export default function ItemEdit() { fieldErrors={fieldErrors} hasErrors={hasErrors} activeFields={activeFields} + fieldErrorRef={fieldErrorRef} /> )} From d6d3c576946f00958d926fe248c800d56718ca92 Mon Sep 17 00:00:00 2001 From: Nar Cuenca Date: Tue, 24 Sep 2024 11:51:32 +0800 Subject: [PATCH 10/15] task: add bottom margin --- .../src/app/views/ItemCreate/ItemCreate.tsx | 12 +++++++----- .../src/app/views/ItemEdit/Content/Content.js | 12 +++++++----- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/apps/content-editor/src/app/views/ItemCreate/ItemCreate.tsx b/src/apps/content-editor/src/app/views/ItemCreate/ItemCreate.tsx index fe14bae4f1..cccc677394 100644 --- a/src/apps/content-editor/src/app/views/ItemCreate/ItemCreate.tsx +++ b/src/apps/content-editor/src/app/views/ItemCreate/ItemCreate.tsx @@ -389,11 +389,13 @@ export const ItemCreate = () => { > {saveClicked && (hasErrors || hasSEOErrors) && ( - + + + )} {props.saveClicked && props.hasErrors && ( - + + + )} Date: Tue, 24 Sep 2024 12:12:14 +0800 Subject: [PATCH 11/15] fix: prevent save and publish button from getting stuck in loading state when save fails --- .../components/ItemEditHeader/ItemEditHeaderActions.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/apps/content-editor/src/app/views/ItemEdit/components/ItemEditHeader/ItemEditHeaderActions.tsx b/src/apps/content-editor/src/app/views/ItemEdit/components/ItemEditHeader/ItemEditHeaderActions.tsx index c42ce7fd7f..07c43a29fd 100644 --- a/src/apps/content-editor/src/app/views/ItemEdit/components/ItemEditHeader/ItemEditHeaderActions.tsx +++ b/src/apps/content-editor/src/app/views/ItemEdit/components/ItemEditHeader/ItemEditHeaderActions.tsx @@ -229,7 +229,7 @@ export const ItemEditHeaderActions = ({ onClick={() => { onSave(); }} - loading={saving && !publishAfterSave} + loading={saving} disabled={!canUpdate} id="SaveItemButton" > @@ -314,7 +314,7 @@ export const ItemEditHeaderActions = ({ setIsConfirmPublishModalOpen(true); } }} - loading={publishing || publishAfterSave || isFetching} + loading={publishing || saving || isFetching} color="success" variant="contained" id="PublishButton" @@ -332,7 +332,7 @@ export const ItemEditHeaderActions = ({ onClick={(e) => { setPublishMenu(e.currentTarget); }} - disabled={publishing || publishAfterSave || isFetching} + disabled={publishing || saving || isFetching} data-cy="PublishMenuButton" > From e5aa934ecb356be7053444751648211616ee7355 Mon Sep 17 00:00:00 2001 From: Nar Cuenca Date: Tue, 24 Sep 2024 14:23:40 +0800 Subject: [PATCH 12/15] task: limit path to 1 row --- .../Meta/SocialMediaPreview/GooglePreview.tsx | 42 ++++++++++--------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/src/apps/content-editor/src/app/views/ItemEdit/Meta/SocialMediaPreview/GooglePreview.tsx b/src/apps/content-editor/src/app/views/ItemEdit/Meta/SocialMediaPreview/GooglePreview.tsx index 003c89a57b..0999c1b62f 100644 --- a/src/apps/content-editor/src/app/views/ItemEdit/Meta/SocialMediaPreview/GooglePreview.tsx +++ b/src/apps/content-editor/src/app/views/ItemEdit/Meta/SocialMediaPreview/GooglePreview.tsx @@ -64,38 +64,42 @@ export const GooglePreview = ({ imageURL }: GooglePreviewProps) => { {instance?.name} - - + {fullPathArray.map((path, index) => ( - - {path} - + {path} {index < fullPathArray?.length - 1 && ( - + + › + )} ))} - + theme.palette.text.secondary, }} /> - +
    Date: Tue, 24 Sep 2024 15:20:42 +0800 Subject: [PATCH 13/15] task: move meta description value validation to meta component --- .../Meta/settings/MetaDescription.tsx | 51 +------------------ .../app/views/ItemEdit/Meta/settings/util.ts | 26 ++++++++++ 2 files changed, 28 insertions(+), 49 deletions(-) diff --git a/src/apps/content-editor/src/app/views/ItemEdit/Meta/settings/MetaDescription.tsx b/src/apps/content-editor/src/app/views/ItemEdit/Meta/settings/MetaDescription.tsx index bbf389656f..31f1007ec5 100644 --- a/src/apps/content-editor/src/app/views/ItemEdit/Meta/settings/MetaDescription.tsx +++ b/src/apps/content-editor/src/app/views/ItemEdit/Meta/settings/MetaDescription.tsx @@ -18,46 +18,6 @@ export default connect()(function MetaDescription({ onChange, error, }: MetaDescriptionProps) { - const dispatch = useDispatch(); - const [contentValidationError, setContentValidationError] = useState(""); - - useEffect(() => { - if (value) { - let message = ""; - - if (!(value.indexOf("\u0152") === -1)) { - message = - "Found OE ligature. These special characters are not allowed in meta descriptions."; - } else if (!(value.indexOf("\u0153") === -1)) { - message = - "Found oe ligature. These special characters are not allowed in meta descriptions."; - } else if (!(value.indexOf("\xAB") === -1)) { - message = - "Found << character. These special characters are not allowed in meta descriptions."; - } else if (!(value.indexOf("\xBB") === -1)) { - message = - "Found >> character. These special characters are not allowed in meta descriptions."; - } else if (/[\u201C\u201D\u201E]/.test(value)) { - message = - "Found Microsoft smart double quotes and apostrophe. These special characters are not allowed in meta descriptions."; - } else if (/[\u2018\u2019\u201A]/.test(value)) { - message = - "Found Microsoft Smart single quotes and apostrophe. These special characters are not allowed in meta descriptions."; - } - - setContentValidationError(message); - } - }, [value]); - - if (contentValidationError) { - dispatch( - notify({ - kind: "warn", - message: contentValidationError, - }) - ); - } - return ( onChange(evt.target.value, "metaDescription")} multiline rows={3} - error={hasErrors(error) || !!contentValidationError} + error={hasErrors(error)} /> diff --git a/src/apps/content-editor/src/app/views/ItemEdit/Meta/settings/util.ts b/src/apps/content-editor/src/app/views/ItemEdit/Meta/settings/util.ts index 19c0ebc934..10d385d7b0 100644 --- a/src/apps/content-editor/src/app/views/ItemEdit/Meta/settings/util.ts +++ b/src/apps/content-editor/src/app/views/ItemEdit/Meta/settings/util.ts @@ -5,3 +5,29 @@ export const hasErrors = (errors: Error) => { return Object.values(errors).some((error) => !!error); }; + +export const validateMetaDescription = (value: string) => { + let message = ""; + + if (!(value.indexOf("\u0152") === -1)) { + message = + "Found OE ligature. These special characters are not allowed in meta descriptions."; + } else if (!(value.indexOf("\u0153") === -1)) { + message = + "Found oe ligature. These special characters are not allowed in meta descriptions."; + } else if (!(value.indexOf("\xAB") === -1)) { + message = + "Found << character. These special characters are not allowed in meta descriptions."; + } else if (!(value.indexOf("\xBB") === -1)) { + message = + "Found >> character. These special characters are not allowed in meta descriptions."; + } else if (/[\u201C\u201D\u201E]/.test(value)) { + message = + "Found Microsoft Smart double quotes and/or apostrophe. These special characters are not allowed in meta descriptions as it may lead to incorrect rendering, where characters show up as � or other odd symbols. Please use straight quotes (' and \") instead."; + } else if (/[\u2018\u2019\u201A]/.test(value)) { + message = + "Found Microsoft Smart single quotes and/or apostrophe. These special characters are not allowed in meta descriptions as it may lead to incorrect rendering, where characters show up as � or other odd symbols. Please use straight quotes (' and \") instead."; + } + + return message; +}; From 2a2a26227105697c3ae56feacfc64da80ebef294 Mon Sep 17 00:00:00 2001 From: Nar Cuenca Date: Tue, 24 Sep 2024 15:20:48 +0800 Subject: [PATCH 14/15] task: move meta description value validation to meta component --- .../src/app/views/ItemEdit/Meta/index.tsx | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/apps/content-editor/src/app/views/ItemEdit/Meta/index.tsx b/src/apps/content-editor/src/app/views/ItemEdit/Meta/index.tsx index 679c186ceb..812b760c83 100644 --- a/src/apps/content-editor/src/app/views/ItemEdit/Meta/index.tsx +++ b/src/apps/content-editor/src/app/views/ItemEdit/Meta/index.tsx @@ -25,6 +25,7 @@ import { Web, } from "../../../../../../../shell/services/types"; import { SocialMediaPreview } from "./SocialMediaPreview"; +import { validateMetaDescription } from "./settings/util"; // Fields import { MetaImage } from "./settings/MetaImage"; @@ -150,6 +151,15 @@ export const Meta = forwardRef( }; } + if (name === "metaDescription") { + const metaDescriptionError = validateMetaDescription(value); + + currentErrors.metaDescription = { + ...currentErrors.metaDescription, + CUSTOM_ERROR: !!metaDescriptionError ? metaDescriptionError : "", + }; + } + onUpdateSEOErrors(currentErrors); dispatch({ @@ -207,6 +217,16 @@ export const Meta = forwardRef( }; }); + // Validate meta description value + const metaDescriptionError = validateMetaDescription( + web.metaDescription + ); + + currentErrors.metaDescription = { + ...currentErrors.metaDescription, + CUSTOM_ERROR: !!metaDescriptionError ? metaDescriptionError : "", + }; + // No need to validate pathPart for datasets if (model?.type === "dataset" || web?.pathPart === "zesty_home") { delete currentErrors.pathPart; From 759fb0bfc8bc5babf269d295d875551d5fabd298 Mon Sep 17 00:00:00 2001 From: Nar Cuenca Date: Tue, 24 Sep 2024 16:08:26 +0800 Subject: [PATCH 15/15] task: replace smart quotes with regular quotes --- .../src/app/components/Editor/Editor.js | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/apps/content-editor/src/app/components/Editor/Editor.js b/src/apps/content-editor/src/app/components/Editor/Editor.js index 8cb0e51986..085d999727 100644 --- a/src/apps/content-editor/src/app/components/Editor/Editor.js +++ b/src/apps/content-editor/src/app/components/Editor/Editor.js @@ -275,11 +275,21 @@ export default memo(function Editor({ } if (firstContentField && firstContentField.name === name) { + // Remove tags and replace MS smart quotes with regular quotes + const cleanedValue = value + ?.replace(/<[^>]*>/g, "") + ?.replaceAll(/[\u2018\u2019\u201A]/gm, "'") + ?.replaceAll("’", "'") + ?.replaceAll(/[\u201C\u201D\u201E]/gm, '"') + ?.replaceAll("“", '"') + ?.replaceAll("”", '"') + ?.slice(0, 160); + dispatch({ type: "SET_ITEM_WEB", itemZUID, key: "metaDescription", - value: value.replace(/<[^>]*>/g, "").slice(0, 160), + value: cleanedValue, }); if ("og_description" in metaFields) { @@ -287,7 +297,7 @@ export default memo(function Editor({ type: "SET_ITEM_DATA", itemZUID, key: "og_description", - value: value.replace(/<[^>]*>/g, "").slice(0, 160), + value: cleanedValue, }); } @@ -296,7 +306,7 @@ export default memo(function Editor({ type: "SET_ITEM_DATA", itemZUID, key: "tc_description", - value: value.replace(/<[^>]*>/g, "").slice(0, 160), + value: cleanedValue, }); } }