diff --git a/src/layouts/EditHomepage/EditHomepage.jsx b/src/layouts/EditHomepage/EditHomepage.jsx index 2462c2070a..fd81a712c1 100644 --- a/src/layouts/EditHomepage/EditHomepage.jsx +++ b/src/layouts/EditHomepage/EditHomepage.jsx @@ -31,6 +31,7 @@ import { validateSections, validateHighlights, validateDropdownElems, + validateAnnouncements, } from "utils/validators" import { HomepageStartEditingImage } from "assets" @@ -40,6 +41,8 @@ import { EditableContextProvider } from "../../contexts/EditableContext" import { useDrag, onCreate, onDelete } from "../../hooks/useDrag" import { CustomiseSectionsHeader, Editable } from "../components/Editable" import { AddSectionButton } from "../components/Editable/AddSectionButton" +import { AnnouncementBody } from "../components/Homepage/AnnouncementBody" +import { AnnouncementSection } from "../components/Homepage/AnnouncementSection" import { HeroBody } from "../components/Homepage/HeroBody" import { HeroDropdownSection } from "../components/Homepage/HeroDropdownSection" import { HeroHighlightSection } from "../components/Homepage/HeroHighlightSection" @@ -54,6 +57,8 @@ import { INFOPIC_SECTION, KEY_HIGHLIGHT_SECTION, RESOURCES_SECTION, + ANNOUNCEMENT_BLOCK, + ANNOUNCEMENT_SECTION, } from "./constants" import { HomepagePreview } from "./HomepagePreview" import { getErrorValues } from "./utils" @@ -119,6 +124,11 @@ const enumSection = (type, isError) => { ? { infopic: getErrorValues(INFOPIC_SECTION) } : { infopic: INFOPIC_SECTION } + case "announcementBlock": + return isError + ? { announcementBlock: getErrorValues(ANNOUNCEMENT_BLOCK) } + : { announcementBlock: ANNOUNCEMENT_BLOCK } + default: return isError ? { infobar: getErrorValues(INFOBAR_SECTION) } @@ -139,6 +149,7 @@ const EditHomepage = ({ match }) => { image: "", notification: "", sections: [], + announcementBlock: {}, }) const [originalFrontMatter, setOriginalFrontMatter] = useState({ title: "", @@ -150,12 +161,14 @@ const EditHomepage = ({ match }) => { }) const [sha, setSha] = useState(null) const [displaySections, setDisplaySections] = useState([]) + const [displayAnnouncements, setDisplayAnnouncements] = useState([]) const [displayHighlights, setDisplayHighlights] = useState([]) const [displayDropdownElems, setDisplayDropdownElems] = useState([]) const [errors, setErrors] = useState({ sections: [], highlights: [], dropdownElems: [], + announcements: [], }) const [itemPendingForDelete, setItemPendingForDelete] = useState({ id: "", @@ -172,6 +185,7 @@ const EditHomepage = ({ match }) => { displayDropdownElems, displayHighlights, displaySections, + displayAnnouncements, } const onDrag = useDrag(homepageState) const setHomepageState = ({ @@ -216,6 +230,7 @@ const EditHomepage = ({ match }) => { const sectionsErrors = [] let dropdownElemsErrors = [] let highlightsErrors = [] + const announcementErrors = [] const scrollRefs = [] frontMatter.sections.forEach((section) => { scrollRefs.push(createRef()) @@ -267,6 +282,12 @@ const EditHomepage = ({ match }) => { sectionsErrors.push({ infopic: getErrorValues(INFOPIC_SECTION) }) } + if (section.announcementBlock) { + sectionsErrors.push({ + announcementBlock: getErrorValues(ANNOUNCEMENT_BLOCK), + }) + } + // Minimize all sections by default displaySections.push(false) }) @@ -276,6 +297,7 @@ const EditHomepage = ({ match }) => { sections: sectionsErrors, highlights: highlightsErrors, dropdownElems: dropdownElemsErrors, + announcements: announcementErrors, } setFrontMatter(frontMatter) @@ -332,7 +354,7 @@ const EditHomepage = ({ match }) => { // sectionIndex is the index of the section array in the frontMatter const sectionIndex = parseInt(idArray[1], RADIX_PARSE_INT) - const sectionType = idArray[2] // e.g. "hero" or "infobar" or "resources" + const sectionType = idArray[2] // e.g. "hero" or "infobar" or "resources" or "announcement" const field = idArray[3] // e.g. "title" or "subtitle" const newSections = update(sections, { @@ -441,6 +463,60 @@ const EditHomepage = ({ match }) => { scrollTo(scrollRefs[0]) break } + case "announcement": { + // The field that changed belongs to a hero highlight + const { sections } = frontMatter + + const announcementBlockIndex = sections.findIndex( + (value) => Object.keys(value)[0] === "announcementBlock" + ) + // announcementIndex is the index of the announcements array + const announcementIndex = parseInt(idArray[1], RADIX_PARSE_INT) + const field = idArray[2] // e.g. "title" or "url" + + const newSections = update(sections, { + [announcementBlockIndex]: { + announcementBlock: { + announcements: { + [announcementIndex]: { + [field]: { + $set: value, + }, + }, + }, + }, + }, + }) + + const newErrors = update(errors, { + announcements: { + [announcementIndex]: { + $set: validateAnnouncements( + errors.announcements[announcementIndex], + field, + value + ), + }, + }, + }) + + // Additional validation that depends on other fields + const isLinkTextFilled = !!frontMatter.sections[ + announcementBlockIndex + ].announcementBlock.announcements[announcementIndex].linkText + if (field === "linkUrl" && !value && isLinkTextFilled) { + newErrors.announcements[announcementIndex].linkText = + "Please specify a URL for your link" + } + + setFrontMatter({ + ...frontMatter, + sections: newSections, + }) + setErrors(newErrors) + scrollTo(scrollRefs[0]) + break + } case "dropdownelem": { // The field that changed is a dropdown element (i.e. dropdownelem) const { sections } = frontMatter @@ -582,6 +658,20 @@ const EditHomepage = ({ match }) => { setDisplayHighlights(displayHighlights) break } + case "announcement": { + const val = ANNOUNCEMENT_SECTION + const err = getErrorValues(ANNOUNCEMENT_SECTION) + const updatedHomepageState = onCreate( + homepageState, + elemType, + val, + err + ) + const newScrollRefs = update(scrollRefs, { $push: [createRef()] }) + setHomepageState(updatedHomepageState) + setScrollRefs(newScrollRefs) + break + } default: } } catch (err) { @@ -787,8 +877,21 @@ const EditHomepage = ({ match }) => { }) setDisplaySections(newDisplaySections) + scrollTo(scrollRefs[index]) + break + } + case "announcement": { + const resetAnnouncementSections = _.fill( + Array(displayAnnouncements.length), + false + ) + resetAnnouncementSections[index] = !displayAnnouncements[index] + const newDisplayAnnouncements = update(displayAnnouncements, { + $set: resetAnnouncementSections, + }) scrollTo(scrollRefs[index]) + setDisplayAnnouncements(newDisplayAnnouncements) break } case "highlight": { @@ -861,7 +964,7 @@ const EditHomepage = ({ match }) => { } } - // NOTE: sectionType is one of `resources`, `infopic` or `infobar` + // NOTE: sectionType is one of `announcementBlock, `resources`, `infopic` or `infobar` const onClick = (sectionType) => { createHandler({ target: { @@ -1076,6 +1179,51 @@ const EditHomepage = ({ match }) => { /> )} + + {section.announcementBlock && ( + Announcement + } + title={ + section.announcementBlock.title || + "New Announcement" + } + isInvalid={_.some( + errors.sections[sectionIndex] + .announcementBlock + )} + > + + + + + )} ) )} @@ -1103,6 +1251,19 @@ const EditHomepage = ({ match }) => { subtitle={INFOBAR_SECTION.subtitle} onClick={() => onClick(INFOBAR_SECTION.id)} /> + {/* NOTE: Check if the sections contain any `announcement` + and if it does, prevent creation of another `resources` section + */} + {!frontMatter.sections.some( + ({ announcementBlock }) => !!announcementBlock + ) && ( + onClick(ANNOUNCEMENT_BLOCK.id)} + /> + )} + {/* NOTE: Check if the sections contain any `resources` and if it does, prevent creation of another `resources` section */}