Skip to content

[Content] Create item modal UX updates #3525

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

Open
wants to merge 6 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions cypress/e2e/content/navigation.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@ describe("Navigation through content editor", () => {
cy.get(".ModalAligner--ptdt-.Open--M5j6S button.Close--kVpCO").click();
});

it("Should not navigate to the create item page if no model is selected", () => {
cy.getBySelector("create_new_content_item").should("exist").click();
cy.getBySelector("create_new_content_item_btn").click({ force: true });
cy.contains("Please select a Model to proceed.").should("exist");
cy.getBySelector("discard_new_content_item_btn").should("exist").click();
});

it("Creates a new item from the menu", () => {
cy.getBySelector("create_new_content_item").should("exist").click();
cy.getBySelector("create_new_content_item_dialog").should("exist");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,8 @@ export const UnpublishedRelatedItem = ({
primary={
fieldValue ||
contentItem?.web?.metaTitle ||
contentItem?.web?.metaLinkText
contentItem?.web?.metaLinkText ||
contentItem?.meta?.ZUID
}
secondary={contentItem?.web?.metaDescription}
primaryTypographyProps={{
Expand Down
116 changes: 68 additions & 48 deletions src/apps/content-editor/src/app/views/ItemList/DialogContentItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,62 +36,29 @@ export const DialogContentItem = ({ item }: DialogContentItemProps) => {
bins?.map((bin) => bin.id),
{ skip: !bins?.length }
);

const imageFields = useMemo(() => {
if (!fields?.length) return [];

return fields?.filter((field) => field.datatype === "images");
}, [fields]);

const heroImage = useMemo(() => {
let image = (
item?.data?.[
fields?.find((field) => field.datatype === "images")?.name
] as string
)?.split(",")?.[0];
if (!imageFields?.length || !item?.data) return null;

let image = String(item.data[imageFields[0]?.name])?.split(",")?.[0];

if (image?.startsWith("3-")) {
image = files?.find((file) => file.id === image)?.thumbnail;
}

return image;
}, [fields, item, files]);
}, [imageFields, item, files]);

return (
<List disablePadding>
<ListItem dense disableGutters divider>
{!!heroImage ? (
<ListItemAvatar>
<Avatar
sx={{
width: 40,
height: 40,
borderRadius: 1,
backgroundColor: (theme) => theme.palette.grey[100],
}}
src={heroImage}
imgProps={{
style: {
objectFit: "contain",
},
}}
>
<Typography variant="body2" color="text.secondary">
NA
</Typography>
</Avatar>
</ListItemAvatar>
) : (
<Stack
sx={{
backgroundColor: "grey.100",
width: 40,
height: 40,
minWidth: 40,
minHeight: 40,
alignItems: "center",
justifyContent: "center",
overflow: "hidden",
mr: 2,
my: 0.5,
borderRadius: 1,
}}
>
<ImageRounded fontSize="small" color="action" />
</Stack>
)}
<ListItem dense disableGutters divider sx={{ minHeight: 49 }}>
{!!imageFields?.length && <HeroImage imageURL={heroImage} />}
<ListItemText
primaryTypographyProps={{
variant: "body2",
Expand All @@ -102,10 +69,63 @@ export const DialogContentItem = ({ item }: DialogContentItemProps) => {
secondaryTypographyProps={{
noWrap: true,
}}
primary={item?.web?.metaTitle}
primary={
item?.web?.metaTitle || item?.web?.metaLinkText || item?.meta?.ZUID
}
secondary={item?.web?.metaDescription}
sx={{ ml: !imageFields?.length ? 2 : 0 }}
/>
</ListItem>
</List>
);
};

type HeroImageProps = {
imageURL: string;
};
const HeroImage = ({ imageURL }: HeroImageProps) => {
if (imageURL) {
return (
<ListItemAvatar>
<Avatar
sx={{
width: 40,
height: 40,
borderRadius: 1,
backgroundColor: (theme) => theme.palette.grey[100],
}}
src={imageURL}
imgProps={{
style: {
objectFit: "contain",
},
}}
>
<Typography variant="body2" color="text.secondary">
NA
</Typography>
</Avatar>
</ListItemAvatar>
);
}

return (
<Stack
sx={{
backgroundColor: "grey.100",
width: 40,
height: 40,
minWidth: 40,
minHeight: 40,
alignItems: "center",
justifyContent: "center",
overflow: "hidden",
mr: 2,
my: 0.5,
borderRadius: 1,
}}
>
<ImageRounded fontSize="small" color="action" />
</Stack>
);
};
50 changes: 32 additions & 18 deletions src/shell/components/CreateContentItemDialog.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useEffect, useMemo, useState } from "react";
import { useMemo, useState } from "react";
import {
Box,
Button,
Expand All @@ -10,12 +10,9 @@ import {
InputLabel,
Autocomplete,
Typography,
Avatar,
} from "@mui/material";
import EditRoundedIcon from "@mui/icons-material/EditRounded";
import { useHistory } from "react-router";
import { ThemeProvider } from "@mui/material/styles";
import { theme } from "@zesty-io/material";
import { cloneDeep } from "lodash";

import { useGetContentModelsQuery } from "../services/instance";
Expand All @@ -34,10 +31,8 @@ export const CreateContentItemDialog = ({
}: Props) => {
const { data: models } = useGetContentModelsQuery();
const history = useHistory();
const [selectedModel, setSelectedModel] = useState({
label: "None",
ZUID: "",
});
const [selectedModel, setSelectedModel] = useState(null);
const [hasError, setHasError] = useState(false);

const sortedModels = useMemo(() => {
if (models?.length) {
Expand Down Expand Up @@ -65,8 +60,12 @@ export const CreateContentItemDialog = ({
}, [models, limitTo]);

const onCreateClick = () => {
onClose();
history.push("/content/" + selectedModel.ZUID + "/new");
if (!selectedModel?.ZUID) {
setHasError(true);
} else {
onClose();
history.push("/content/" + selectedModel.ZUID + "/new");
}
};

return (
Expand Down Expand Up @@ -101,17 +100,14 @@ export const CreateContentItemDialog = ({
<InputLabel sx={{ mb: 0.5 }}>Select Model</InputLabel>
<Autocomplete
data-cy="create_new_content_item_input"
openOnFocus
size="small"
fullWidth
value={selectedModel}
disableClearable
options={
sortedModels
? [
{
label: "None",
ZUID: "",
},
{
label: "Internal/External Link",
ZUID: "link",
Expand All @@ -120,10 +116,25 @@ export const CreateContentItemDialog = ({
]
: []
}
renderInput={(params) => <TextField {...params} hiddenLabel />}
renderInput={(params) => (
<TextField
{...params}
placeholder="Select"
hiddenLabel
autoFocus
error={hasError}
helperText={hasError && "Please select a Model to proceed."}
/>
)}
getOptionLabel={(option: any) => option.label}
isOptionEqualToValue={(option, value) => option.ZUID === value.ZUID}
onChange={(event, newValue) => setSelectedModel(newValue)}
onChange={(event, newValue) => {
if (!!newValue?.ZUID) {
setHasError(false);
}

setSelectedModel(newValue);
}}
onKeyDown={(evt) => {
if (evt.key.toLowerCase() === "enter" && !!selectedModel?.ZUID) {
evt.preventDefault();
Expand All @@ -138,14 +149,17 @@ export const CreateContentItemDialog = ({
/>
</DialogContent>
<DialogActions>
<Button onClick={onClose} color="inherit">
<Button
data-cy="discard_new_content_item_btn"
onClick={onClose}
color="inherit"
>
Discard
</Button>
<Button
data-cy="create_new_content_item_btn"
variant="contained"
color="primary"
disabled={!selectedModel.ZUID}
onClick={onCreateClick}
>
Create
Expand Down
Loading