Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Content] SEO tab revamp VQA fixes #2940

Merged
merged 11 commits into from
Sep 3, 2024
4 changes: 4 additions & 0 deletions cypress/e2e/content/actions.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,10 @@ describe("Actions in content editor", () => {
});

cy.get("input[name=title]", { timeout: 5000 }).click().type(timestamp);
cy.getBySelector("metaDescription")
.find("textarea")
.first()
.type(timestamp);
cy.getBySelector("CreateItemSaveButton").click();

cy.contains("Created Item", { timeout: 5000 }).should("exist");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ const FieldLabel = memo(
{(!!customTooltip || settings?.settings?.tooltip) && (
<Tooltip
title={customTooltip ?? settings.settings.tooltip}
placement="top"
placement="right"
>
<InfoRoundedIcon color="action" sx={{ fontSize: 12 }} />
</Tooltip>
Expand Down
4 changes: 2 additions & 2 deletions src/apps/content-editor/src/app/components/FieldTypeMedia.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -878,7 +878,7 @@ export const MediaItem = ({
}}
>
{!isURL && !isBynderAsset && (
<>
<Box>
<MenuItem
onClick={(event) => {
event.stopPropagation();
Expand Down Expand Up @@ -914,7 +914,7 @@ export const MediaItem = ({
</ListItemIcon>
<ListItemText>Copy ZUID</ListItemText>
</MenuItem>
</>
</Box>
)}
<MenuItem
onClick={(event) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,20 @@ export default memo(function PendingEditsModal(props: PendingEditsModalProps) {
switch (action) {
case "save":
setLoading(true);
props.onSave().then(() => {
setLoading(false);
setOpen(false);
// @ts-ignore
answer(true);
});
props
.onSave()
.then((i) => {
// @ts-ignore
answer(true);
})
.catch((err) => {
// @ts-ignore
answer(false);
})
.finally(() => {
setLoading(false);
setOpen(false);
});
break;
case "delete":
setLoading(true);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useEffect, useMemo, useState } from "react";
import { useEffect, useMemo, useState, useRef } from "react";
import { useDispatch, useSelector } from "react-redux";
import useIsMounted from "ismounted";
import { useHistory, useParams } from "react-router-dom";
Expand Down Expand Up @@ -81,6 +81,7 @@ export const ItemCreate = () => {
const [fieldErrors, setFieldErrors] = useState<FieldError>({});
const [saveClicked, setSaveClicked] = useState(false);
const [hasSEOErrors, setHasSEOErrors] = useState(false);
const metaRef = useRef(null);

const [
createPublishing,
Expand Down Expand Up @@ -157,6 +158,7 @@ export const ItemCreate = () => {
const save = async (action: ActionAfterSave) => {
setSaveClicked(true);

metaRef.current?.validateMetaFields?.();
if (hasErrors || hasSEOErrors) return;

setSaving(true);
Expand Down Expand Up @@ -385,6 +387,7 @@ export const ItemCreate = () => {
setHasSEOErrors(hasErrors);
}}
isSaving={saving}
ref={metaRef}
/>
</Box>
<ThemeProvider theme={theme}>
Expand Down
26 changes: 23 additions & 3 deletions src/apps/content-editor/src/app/views/ItemEdit/ItemEdit.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
Redirect,
useParams,
useHistory,
useLocation,
} from "react-router-dom";
import useIsMounted from "ismounted";
import { useDispatch, useSelector } from "react-redux";
Expand Down Expand Up @@ -70,6 +71,7 @@ export default function ItemEdit() {
const dispatch = useDispatch();
const history = useHistory();
const isMounted = useIsMounted();
const location = useLocation();
const { modelZUID, itemZUID } = useParams();
const item = useSelector((state) => state.content[itemZUID]);
const items = useSelector((state) => state.content);
Expand All @@ -87,6 +89,7 @@ export default function ItemEdit() {
const [saveClicked, setSaveClicked] = useState(false);
const [fieldErrors, setFieldErrors] = useState({});
const [hasSEOErrors, setHasSEOErrors] = useState(false);
const [headerTitle, setHeaderTitle] = useState("");
const { data: fields, isLoading: isLoadingFields } =
useGetContentModelFieldsQuery(modelZUID);
const [showDuoModeLS, setShowDuoModeLS] = useLocalStorage(
Expand Down Expand Up @@ -130,6 +133,12 @@ export default function ItemEdit() {
};
}, [modelZUID, itemZUID]);

useEffect(() => {
if (!loading) {
setHeaderTitle(item?.web?.metaTitle || item?.web?.metaLinkText || "");
}
}, [loading]);

const hasErrors = useMemo(() => {
const hasErrors = Object.values(fieldErrors)
?.map((error) => {
Expand Down Expand Up @@ -234,7 +243,15 @@ export default function ItemEdit() {

setSaving(true);
try {
const res = await dispatch(saveItem(itemZUID));
// 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(
saveItem({
itemZUID,
skipContentItemValidation:
location?.pathname?.split("/")?.pop() === "meta",
})
);
if (res.err === "VALIDATION_ERROR") {
const missingRequiredFieldNames = res.missingRequired?.reduce(
(acc, curr) => {
Expand Down Expand Up @@ -302,7 +319,7 @@ export default function ItemEdit() {
}

setFieldErrors(errors);
return;
throw new Error(errors);
}
if (res.status === 400) {
dispatch(
Expand All @@ -311,9 +328,10 @@ export default function ItemEdit() {
kind: "error",
})
);
return;
throw new Error(`Cannot Save: ${item.web.metaTitle}`);
}

setHeaderTitle(item?.web?.metaTitle || item?.web?.metaLinkText || "");
dispatch(
notify({
message: `Item Saved: ${
Expand All @@ -326,6 +344,7 @@ export default function ItemEdit() {
dispatch(fetchAuditTrailDrafting(itemZUID));
} catch (err) {
console.error(err);
throw new Error(err);
// we need to set the item to dirty again because the save failed
dispatch({
type: "MARK_ITEM_DIRTY",
Expand Down Expand Up @@ -403,6 +422,7 @@ export default function ItemEdit() {
onSave={save}
saving={saving}
hasError={Object.keys(fieldErrors)?.length}
headerTitle={headerTitle}
/>
<Switch>
<Route
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Box, Stack, Typography, Chip } from "@mui/material";
import { Add, Remove } from "@mui/icons-material";
import { Check } from "@mui/icons-material";
import { useMemo } from "react";
import { useMemo, useState } from "react";
import { useSelector } from "react-redux";
import { useParams } from "react-router";

Expand All @@ -21,6 +22,7 @@ export const MatchedWords = ({
itemZUID: string;
}>();
const item = useSelector((state: AppState) => state.content[itemZUID]);
const [showAll, setShowAll] = useState(false);

const contentAndMetaWordMatches = useMemo(() => {
const textMetaFieldNames = [
Expand Down Expand Up @@ -70,15 +72,26 @@ export const MatchedWords = ({
Content and Meta Matched Words
</Typography>
<Stack direction="row" gap={1} flexWrap="wrap">
{contentAndMetaWordMatches?.map((word) => (
{contentAndMetaWordMatches
?.slice(0, showAll ? undefined : 9)
?.map((word) => (
<Chip
key={word}
label={word}
size="small"
icon={<Check color="action" />}
variant="outlined"
/>
))}
{contentAndMetaWordMatches?.length > 10 && (
<Chip
key={word}
label={word}
label={`See ${showAll ? "Less" : "More"}`}
size="small"
icon={<Check color="action" />}
variant="outlined"
icon={showAll ? <Remove color="action" /> : <Add color="action" />}
onClick={() => setShowAll(!showAll)}
/>
))}
)}
</Stack>
</Box>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,7 @@ export const GooglePreview = ({}: GooglePreviewProps) => {
let path: string[] = [domain];

if (parent) {
path = [
...path,
...(parent.web?.path?.split("/") || []),
item?.web?.pathPart,
];
} else {
path = [...path, item?.web?.pathPart];
path = [...path, ...(parent.web?.path?.split("/") || [])];
}

// Remove empty strings
Expand Down
Loading
Loading