Skip to content

Commit

Permalink
Stage Release (#3054)
Browse files Browse the repository at this point in the history
Created by Github action

---------

Co-authored-by: Stuart Runyan <shrunyan@gmail.com>
Co-authored-by: Nar -- <28705606+finnar-bin@users.noreply.github.com>
  • Loading branch information
3 people authored Nov 5, 2024
1 parent 51ce943 commit e98c511
Show file tree
Hide file tree
Showing 8 changed files with 201 additions and 8 deletions.
28 changes: 28 additions & 0 deletions cypress/e2e/content/meta.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -123,4 +123,32 @@ describe("Content Meta", () => {

cy.contains("/page/otherpage/all-field-types/").should("exist");
});

it("Supports a dedicated Twitter title, description and image", () => {
cy.waitOn("/v1/content/models*", () => {
cy.waitOn("/v1/env/nav", () => {
cy.waitOn("/v1/search/items*", () => {
cy.visit("/content/6-b6cde1aa9f-wftv50/7-92ab81c5a8-bhvb0l/meta");
});
});
});

const title = `Twitter title ${today}`;
const description = `Twitter description ${today}`;

cy.getBySelector("TCTitle").find("input").type(`{selectAll}{del}${title}`);
cy.getBySelector("TCDescription")
.find("textarea")
.first()
.type(`{selectAll}{del}${description}`);
cy.getBySelector("SocialMediaPreviewTwitter").click();

cy.getBySelector("TwitterCardTitle").contains(title);
cy.getBySelector("TwitterCardDescription").contains(description);
cy.getBySelector("TwitterCardImage").should(
"have.attr",
"src",
"https://wave-trial.getbynder.com/m/45b0d3ba0b271504/original/kim-cruickshanks-176374.jpg"
);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ export default memo(function Editor({
"og_description",
"tc_title",
"tc_description",
"tc_image",
].includes(field.name)
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useEffect } from "react";
import { useEffect, useState } from "react";
import { Typography, Box, Stack } from "@mui/material";
import { ImageRounded } from "@mui/icons-material";
import { useLocation, useParams } from "react-router";
Expand All @@ -17,12 +17,38 @@ export const TwitterPreview = ({ imageURL }: TwitterPreviewProps) => {
}>();
const domain = useDomain();
const location = useLocation();
const [tcImageURL, setTcImageURL] = useState<string>(null);
const isCreateItemPage = location?.pathname?.split("/")?.pop() === "new";
const item = useSelector(
(state: AppState) =>
state.content[isCreateItemPage ? `new:${modelZUID}` : itemZUID]
);

useEffect(() => {
if (!!item?.data?.tc_image) {
const tcImage = String(item?.data?.tc_image)
?.split(",")
?.filter((el: string) => el)?.[0];

if (tcImage.startsWith("3-")) {
setTcImageURL(
`${
// @ts-ignore
CONFIG.SERVICE_MEDIA_RESOLVER
}/resolve/${
item?.data?.tc_image
}/getimage/?w=${128}&h=${128}&type=fit`
);
} else {
setTcImageURL(tcImage);
}
} else {
setTcImageURL(
!!imageURL ? `${imageURL}?width=128&height=128&fit=cover` : null
);
}
}, [item?.data?.tc_image]);

return (
<Stack
direction="row"
Expand All @@ -31,18 +57,26 @@ export const TwitterPreview = ({ imageURL }: TwitterPreviewProps) => {
border={1}
borderColor="border"
>
{!!imageURL ? (
{!!tcImageURL ? (
<Box
data-cy="TwitterCardImage"
component="img"
sx={{
backgroundColor: (theme) => theme.palette.grey[100],
objectFit: "cover",
}}
width={128}
height={128}
src={`${imageURL}?width=128&height=128&fit=cover`}
src={tcImageURL}
flexShrink={0}
borderRadius="8px 0 0 8px"
onError={(evt: any) => {
if (!!imageURL) {
evt.currentTarget.src = `${imageURL}?width=128&height=128&fit=cover`;
} else {
setTcImageURL(null);
}
}}
/>
) : (
<Stack
Expand Down Expand Up @@ -75,6 +109,7 @@ export const TwitterPreview = ({ imageURL }: TwitterPreviewProps) => {
{domain.replace(/http:\/\/|https:\/\//gm, "")}
</Typography>
<Typography
data-cy="TwitterCardTitle"
variant="body2"
color={
!!item?.data?.tc_title || !!item?.web?.metaTitle
Expand All @@ -95,6 +130,7 @@ export const TwitterPreview = ({ imageURL }: TwitterPreviewProps) => {
{item?.data?.tc_title || item?.web?.metaTitle || "Meta Title"}
</Typography>
<Typography
data-cy="TwitterCardDescription"
variant="body2"
color={
!!item?.data?.tc_title || !!item?.web?.metaDescription
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ export const SocialMediaPreview = ({}: SocialMediaPreviewProps) => {
iconPosition="start"
label="Twitter (X)"
value={SocialMediaTab.Twitter}
data-cy="SocialMediaPreviewTwitter"
/>
<Tab
icon={<FacebookRounded />}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export const useImageURL: () => string = () => {
!field.deletedAt &&
field.datatype === "images" &&
field?.name !== "og_image" &&
field?.name !== "tc_image" &&
!!item?.data?.[field.name]
) {
if (
Expand Down
16 changes: 11 additions & 5 deletions src/apps/content-editor/src/app/views/ItemEdit/Meta/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,7 @@ import {
import { AppState } from "../../../../../../../shell/store/types";
import { Error } from "../../../components/Editor/Field/FieldShell";
import { fetchGlobalItem } from "../../../../../../../shell/store/content";
import {
ContentModelField,
Web,
} from "../../../../../../../shell/services/types";
import { ContentModelField } from "../../../../../../../shell/services/types";
import { SocialMediaPreview } from "./SocialMediaPreview";
import { validateMetaDescription } from "./settings/util";

Expand All @@ -54,7 +51,7 @@ import { OGTitle } from "./settings/OGTitle";
import { OGDescription } from "./settings/OGDescription";
import { TCTitle } from "./settings/TCTitle";
import { TCDescription } from "./settings/TCDescription";
import { FieldError } from "../../../components/Editor/FieldError";
import { TCImage } from "./settings/TCImage";

const rotateAnimation = keyframes`
0% {
Expand Down Expand Up @@ -99,6 +96,7 @@ export const DYNAMIC_META_FIELD_NAMES = [
"og_description",
"tc_title",
"tc_description",
"tc_image",
];

type Errors = Record<string, Error>;
Expand Down Expand Up @@ -514,6 +512,14 @@ export const Meta = forwardRef(
field={metaFields.tc_description}
/>
)}
{"tc_image" in metaFields && (
<TCImage
field={metaFields.tc_image}
onChange={handleOnChange}
error={errors?.tc_image}
value={data.tc_image as string}
/>
)}
</Stack>
{model?.type !== "dataset" && web?.pathPart !== "zesty_home" && (
<Stack gap={3}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ export const MetaImage = ({ onChange }: MetaImageProps) => {
!field.deletedAt &&
field.datatype === "images" &&
field?.name !== "og_image" &&
field?.name !== "tc_image" &&
!!item?.data?.[field.name]
) {
if (
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import { useState, useMemo } from "react";
import { MemoryRouter } from "react-router";
import { Dialog } from "@mui/material";
import { IconButton } from "@zesty-io/material";
import { Close } from "@mui/icons-material";

import { FieldShell } from "../../../../components/Editor/Field/FieldShell";
import { FieldTypeMedia } from "../../../../components/FieldTypeMedia";
import { MediaApp } from "../../../../../../../media/src/app";
import { ContentModelField } from "../../../../../../../../shell/services/types";
import { Error } from "../../../../components/Editor/Field/FieldShell";
import { hasErrors } from "./util";

type TCImageProps = {
field: ContentModelField;
error: Error;
onChange: (value: string, name: string) => void;
value: string;
};
export const TCImage = ({ field, error, onChange, value }: TCImageProps) => {
const [imageModal, setImageModal] = useState(null);

const imagesArray = useMemo(() => {
if (!value) return [];

return ((value as string) || "").split(",").filter((el: string) => el);
}, [value]);

return (
<>
<FieldShell
settings={{
label: field?.label,
required: field?.required,
}}
withInteractiveTooltip={false}
errors={error ?? {}}
>
<FieldTypeMedia
hasError={hasErrors(error)}
limit={1}
images={imagesArray}
openMediaBrowser={(opts: any) => {
setImageModal({
...opts,
locked: Boolean(
field?.settings &&
field?.settings.group_id &&
field?.settings.group_id != "0"
),
});
}}
settings={{
fileExtensions: [
".png",
".jpg",
".jpeg",
".svg",
".gif",
".tif",
".webp",
],
fileExtensionsErrorMessage:
"Only files with the following extensions are allowed: .png, .jpg, .jpeg, .svg, .gif, .tif, .webp",
}}
name={field?.name}
onChange={onChange}
lockedToGroupId={
field?.settings?.group_id && field?.settings?.group_id !== "0"
? field?.settings.group_id
: null
}
/>
</FieldShell>
{imageModal && (
<MemoryRouter initialEntries={["/media?filetype=Image"]}>
<Dialog
open
fullScreen
sx={{ my: 2.5, mx: 10 }}
PaperProps={{
style: {
borderRadius: "4px",
overflow: "hidden",
},
}}
onClose={() => setImageModal(null)}
>
<IconButton
sx={{
position: "fixed",
right: 5,
top: 0,
}}
onClick={() => setImageModal(null)}
>
<Close sx={{ color: "common.white" }} />
</IconButton>
<MediaApp
limitSelected={1}
isSelectDialog={true}
showHeaderActions={false}
lockedToGroupId={
field?.settings?.group_id && field?.settings?.group_id !== "0"
? field?.settings.group_id
: null
}
addImagesCallback={(images) => {
imageModal.callback(images);
setImageModal(null);
}}
isReplace={imageModal.isReplace}
/>
</Dialog>
</MemoryRouter>
)}
</>
);
};

0 comments on commit e98c511

Please sign in to comment.