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

fix(edithomepage): move error msg extraction into component #1479

Closed
wants to merge 12 commits into from
2 changes: 1 addition & 1 deletion public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>Isomer CMS</title>
<title>IsomerCMS</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
Expand Down
2 changes: 1 addition & 1 deletion src/components/Header.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ const Header = ({
<Box w="180px">
<img
src={`${process.env.PUBLIC_URL}/img/logo.svg`}
alt="Isomer CMS logo"
alt="IsomerCMS logo"
/>
</Box>
) : (
Expand Down
2 changes: 1 addition & 1 deletion src/components/Header/AllSitesHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export const AllSitesHeader = (): JSX.Element => {
<Flex w="180px" justifyContent="center">
<Image
src={`${process.env.PUBLIC_URL}/img/logo.svg`}
alt="Isomer CMS logo"
alt="IsomerCMS logo"
/>
</Flex>
<Spacer />
Expand Down
2 changes: 1 addition & 1 deletion src/components/VerifyUserDetailsModal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ const VerifyUserDetailsModal = () => {
<>
<div>
In order to improve security, a verified email is now required for
all users of Isomer CMS. Only <b>.gov.sg</b> or{" "}
all users of IsomerCMS. Only <b>.gov.sg</b> or{" "}
<b>whitelisted email addresses</b> will be accepted. You must
verify your email before proceeding.{" "}
<Link isExternal href={IDENTITY_GUIDE_LINK}>
Expand Down
6 changes: 4 additions & 2 deletions src/components/navbar/NavSection.jsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Box } from "@chakra-ui/react"
import { Button, IconButton } from "@opengovsg/design-system-react"
import PropTypes from "prop-types"
import { useState, useRef } from "react"
Expand Down Expand Up @@ -269,7 +270,7 @@ const NavSection = ({
</div>
)}
</Droppable>
<div className="d-flex justify-content-between mt-4">
<Box mt="2rem" mb="1rem">
<Select
ref={selectInputRef}
className="w-50"
Expand All @@ -278,14 +279,15 @@ const NavSection = ({
options={sectionCreationOptions}
/>
<Button
mt="1rem"
onClick={sectionCreationHandler}
isDisabled={!newSectionType}
variant="solid"
colorScheme="primary"
>
Create New Menu
</Button>
</div>
</Box>
<span className={elementStyles.info}>
{`Note: you can specify a folder ${
hasResourceRoom ? `or resource room ` : ``
Expand Down
125 changes: 59 additions & 66 deletions src/layouts/EditHomepage/EditHomepage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,11 @@ import {
RESOURCES_SECTION,
} from "./constants"
import { HomepagePreview } from "./HomepagePreview"
import { getErrorValues } from "./utils"
import {
getDefaultValues,
getErrorsFromHomepageState,
validateButton,
} from "./utils"

/* eslint-disable react/no-array-index-key */

Expand All @@ -78,51 +82,23 @@ const getHasError = (errorArray) =>
_.some(err, (errorMessage) => errorMessage.length > 0)
)

const getHasErrors = (errors) => {
const hasSectionErrors = _.some(errors.sections, (section) => {
// Section is an object, e.g. { hero: {} }
// _.keys(section) produces an array with length 1
// The 0th element of the array contains the sectionType
const sectionType = _.keys(section)[0]
return (
_.some(
section[sectionType],
(errorMessage) => errorMessage.length > 0
) === true
)
})

const hasHighlightErrors = getHasError(errors.highlights)
const hasDropdownElemErrors = getHasError(errors.dropdownElems)

return hasSectionErrors || hasHighlightErrors || hasDropdownElemErrors
}

// Constants
// Section constructors
// TODO: Export all these as const and write wrapper for error...

const enumSection = (type, isError) => {
const enumSection = (type) => {
switch (type) {
case "resources":
return isError
? { resources: getErrorValues(RESOURCES_SECTION) }
: { resources: RESOURCES_SECTION }
return { resources: getDefaultValues(RESOURCES_SECTION) }

case "infobar":
return isError
? { infobar: getErrorValues(INFOBAR_SECTION) }
: { infobar: INFOBAR_SECTION }
return { infobar: getDefaultValues(INFOBAR_SECTION) }

case "infopic":
return isError
? { infopic: getErrorValues(INFOPIC_SECTION) }
: { infopic: INFOPIC_SECTION }
return { infopic: getDefaultValues(INFOPIC_SECTION) }

default:
return isError
? { infobar: getErrorValues(INFOBAR_SECTION) }
: { infobar: INFOBAR_SECTION }
return { infobar: getDefaultValues(INFOBAR_SECTION) }
}
}

Expand Down Expand Up @@ -238,14 +214,14 @@ const EditHomepage = ({ match }) => {
)
// Fill in dropdown elem errors array
dropdownElemsErrors = _.map(dropdown.options, () =>
getErrorValues(DROPDOWN_ELEMENT_SECTION)
getDefaultValues(DROPDOWN_ELEMENT_SECTION)
)
}
if (keyHighlights) {
displayHighlights = _.fill(Array(keyHighlights.length), false)
// Fill in highlights errors array
highlightsErrors = _.map(keyHighlights, () =>
getErrorValues(KEY_HIGHLIGHT_SECTION)
getDefaultValues(KEY_HIGHLIGHT_SECTION)
)
}
// Fill in sectionErrors for hero
Expand All @@ -255,16 +231,16 @@ const EditHomepage = ({ match }) => {
// Check if there is already a resources section
if (section.resources) {
sectionsErrors.push({
resources: getErrorValues(RESOURCES_SECTION),
resources: getDefaultValues(RESOURCES_SECTION),
})
}

if (section.infobar) {
sectionsErrors.push({ infobar: getErrorValues(INFOBAR_SECTION) })
sectionsErrors.push({ infobar: getDefaultValues(INFOBAR_SECTION) })
}

if (section.infopic) {
sectionsErrors.push({ infopic: getErrorValues(INFOPIC_SECTION) })
sectionsErrors.push({ infopic: getDefaultValues(INFOPIC_SECTION) })
}

// Minimize all sections by default
Expand Down Expand Up @@ -349,24 +325,15 @@ const EditHomepage = ({ match }) => {

// Set special error message if hero button has text but hero url is empty
// This needs to be done separately because it relies on the state of another field
if (
field === "url" &&
!value &&
frontMatter.sections[sectionIndex][sectionType].button &&
(frontMatter.sections[sectionIndex][sectionType].button || value)
) {
const errorMessage = "Please specify a URL for your button"
newSectionError = _.cloneDeep(errors.sections[sectionIndex])
newSectionError[sectionType][field] = errorMessage
} else if (
field === "button" &&
!frontMatter.sections[sectionIndex][sectionType].url &&
(value || frontMatter.sections[sectionIndex][sectionType].url) &&
sectionType !== "resources"
) {
const errorMessage = "Please specify a URL for your button"
if (field === "url" || field === "button") {
const buttonError = validateButton(
field,
frontMatter.sections[sectionIndex][sectionType],
sectionType,
value
)
newSectionError = _.cloneDeep(errors.sections[sectionIndex])
newSectionError[sectionType].url = errorMessage
newSectionError[sectionType].url = buttonError
} else {
newSectionError = validateSections(
_.cloneDeep(errors.sections[sectionIndex]),
Expand Down Expand Up @@ -536,8 +503,8 @@ const EditHomepage = ({ match }) => {

switch (elemType) {
case "section": {
const val = enumSection(value, false)
const err = enumSection(value, true)
const val = enumSection(value)
const err = enumSection(value)

const newScrollRefs = update(scrollRefs, { $push: [createRef()] })

Expand All @@ -553,8 +520,8 @@ const EditHomepage = ({ match }) => {
break
}
case "dropdownelem": {
const val = DROPDOWN_ELEMENT_SECTION
const err = getErrorValues(DROPDOWN_ELEMENT_SECTION)
const val = getDefaultValues(DROPDOWN_ELEMENT_SECTION)
const err = getDefaultValues(DROPDOWN_ELEMENT_SECTION)

const updatedHomepageState = onCreate(
homepageState,
Expand All @@ -569,8 +536,9 @@ const EditHomepage = ({ match }) => {
case "highlight": {
// depends on index to generate
// If key highlights section exists
const val = KEY_HIGHLIGHT_SECTION
const err = getErrorValues(KEY_HIGHLIGHT_SECTION)
const val = getDefaultValues(KEY_HIGHLIGHT_SECTION)
const err = getDefaultValues(KEY_HIGHLIGHT_SECTION)

const updatedHomepageState = onCreate(
homepageState,
elemType,
Expand Down Expand Up @@ -964,13 +932,19 @@ const EditHomepage = ({ match }) => {
{({ currentSelectedOption }) =>
currentSelectedOption === "dropdown" ? (
<HeroDropdownSection
{...section.hero}
{...section.hero.dropdown}
state={section.hero}
errors={errors}
errors={{
...errors,
...errors.sections[0].hero,
}}
/>
) : (
<HeroHighlightSection
errors={errors}
errors={{
...errors,
...errors.sections[0].hero,
}}
highlights={section.hero.key_highlights}
/>
)
Expand Down Expand Up @@ -1119,8 +1093,27 @@ const EditHomepage = ({ match }) => {
/>
</HStack>
<Footer>
{/* NOTE: We have to call this method twice because `homepageState` isn't guaranteed to be loaded
if we put the declaration out of the components.
This is because we have a blocking conditional `isLoaded` that gets set only after data is fetched.
*/}
{getErrorsFromHomepageState(homepageState).some(
(message) =>
message.includes("longer") || message.includes("specify")
) && (
<Text
mr="0.25rem"
textStyle="body-2"
textColor="base.content.medium"
>
You have blocks without content. Please add content to your
empty blocks before saving.
</Text>
)}
<LoadingButton
isDisabled={getHasErrors(errors)}
isDisabled={
getErrorsFromHomepageState(homepageState).length > 0
}
onClick={savePage}
>
Save
Expand Down
34 changes: 15 additions & 19 deletions src/layouts/EditHomepage/HomepagePreview.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// NOTE: Below eslint disable is inherited from our legacy code :(
/* eslint-disable react/no-array-index-key */
import _ from "lodash"
import { Ref, useState } from "react"
import { useParams } from "react-router-dom"

Expand All @@ -18,6 +19,12 @@ import {
InfopicFrontmatterSection,
} from "types/homepage"

import {
INFOBAR_SECTION,
INFOPIC_SECTION,
RESOURCES_SECTION,
} from "./constants"

const isLeftInfoPic = (
sectionIndex: number,
frontMatter: EditorHomepageState["frontMatter"]
Expand Down Expand Up @@ -114,9 +121,8 @@ export const HomepagePreview = ({
<>
<TemplateResourcesSection
key={`section-${sectionIndex}`}
title={section.resources.title}
subtitle={section.resources.subtitle}
button={section.resources.button}
{...RESOURCES_SECTION}
{..._.pickBy(section.resources)}
sectionIndex={sectionIndex}
ref={scrollRefs[sectionIndex]}
/>
Expand All @@ -127,10 +133,8 @@ export const HomepagePreview = ({
<>
<TemplateInfobarSection
key={`section-${sectionIndex}`}
title={section.infobar.title}
subtitle={section.infobar.subtitle}
description={section.infobar.description}
button={section.infobar.button}
{...INFOBAR_SECTION}
{..._.pickBy(section.infobar)}
sectionIndex={sectionIndex}
ref={scrollRefs[sectionIndex]}
/>
Expand All @@ -142,24 +146,16 @@ export const HomepagePreview = ({
{isLeftInfoPic(sectionIndex, frontMatter) ? (
<TemplateInfopicLeftSection
key={`section-${sectionIndex}`}
title={section.infopic.title}
subtitle={section.infopic.subtitle}
description={section.infopic.description}
imageUrl={section.infopic.image}
imageAlt={section.infopic.alt}
button={section.infopic.button}
{...INFOPIC_SECTION}
{..._.pickBy(section.infopic)}
sectionIndex={sectionIndex}
ref={scrollRefs[sectionIndex]}
/>
) : (
<TemplateInfopicRightSection
key={`section-${sectionIndex}`}
title={section.infopic.title}
subtitle={section.infopic.subtitle}
description={section.infopic.description}
imageUrl={section.infopic.image}
imageAlt={section.infopic.alt}
button={section.infopic.button}
{...INFOPIC_SECTION}
{..._.pickBy(section.infopic)}
sectionIndex={sectionIndex}
ref={scrollRefs[sectionIndex]}
/>
Expand Down
1 change: 1 addition & 0 deletions src/layouts/EditHomepage/constants.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export const RESOURCES_SECTION = {
title: "Resources",
subtitle: "Add a preview and link to your Resource Room",
button: "",
id: "resources",
} as const

Expand Down
Loading
Loading