Skip to content

Commit

Permalink
Partners block (#1336)
Browse files Browse the repository at this point in the history
* add SQL functions for partner-block

* update migration file based on review

* add unique constraint to partner_block table

* create POST endpoint for partners block

* add more accepted block to conditional block

* consume partners block api in main-frontend and also generate-bindings

* + partner_block route in main-frontend

* finalize partners block feature

* reduce width of partners icions

* remove broken breadcrumbs

* make partners block responsive

* fix error with back button in partners block

* + comment to migration file

* add test for partners-block

* remove unused code

* use proper type

* update check for existence of partner-block in a course

* add test asset

* create test for partner-block

* + asset

* stash commit

* remove spinner and error component

* update snapshots

* resolve accessibility issues

* resolve accessibility issues

* update snapshots

* update test

* update test

* update snapshot test
  • Loading branch information
george-misan authored Nov 28, 2024
1 parent bec3610 commit 27fa855
Show file tree
Hide file tree
Showing 42 changed files with 1,000 additions and 85 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,43 @@ const ALLOWED_NESTED_BLOCKS = [
"core/button",
"core/paragraph",
"moocfi/exercise-custom-view-block",
"moocfi/aside",
"moocfi/chapter-progress",
"moocfi/congratulations",
"moocfi/course-chapter-grid",
"moocfi/course-progress",
"moocfi/exercise-slide",
"moocfi/exercise-task",
"moocfi/exercise-slides",
"moocfi/exercise-settings",
"moocfi/exercises-in-chapter",
"moocfi/glossary",
"moocfi/infobox",
"moocfi/latex",
"moocfi/learning-objectives",
"moocfi/pages-in-chapter",
"moocfi/unsupported-block-type",
"moocfi/highlightbox",
"moocfi/instructionbox",
"moocfi/tablebox",
"moocfi/iframe",
"moocfi/map",
"moocfi/author",
"moocfi/author-inner-block",
"moocfi/conditional-block",
"moocfi/exercise-custom-view-block",
"moocfi/top-level-pages",
"moocfi/expandable-content",
"moocfi/expandable-content-inner-block",
"moocfi/revelable-content",
"moocfi/revealable-hidden-content",
"moocfi/aside-with-image",
"moocfi/flip-card",
"moocfi/front-card",
"moocfi/back-card",
"moocfi/code-giveaway",
"moocfi/ingress",
"moocfi/terminology-block",
]

const Wrapper = styled.div`
Expand Down
48 changes: 0 additions & 48 deletions services/cms/src/blocks/Partners/PartnersEditor.tsx

This file was deleted.

11 changes: 0 additions & 11 deletions services/cms/src/blocks/Partners/PartnersSave.tsx

This file was deleted.

18 changes: 0 additions & 18 deletions services/cms/src/blocks/Partners/index.tsx

This file was deleted.

6 changes: 2 additions & 4 deletions services/cms/src/blocks/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,8 @@ import LandingPageCopyText from "./LandingPageCopyText"
import LandingPageHeroSection from "./LandingPageHeroSection"
import Latex from "./Latex"
import LearningObjectives from "./LearningObjectives"
// import LogoLink from "./LogoLink"
import Map from "./Map"
import PagesInChapter from "./PagesInChapter"
import PartnersBlock from "./Partners"
import ResearchFormQuestion from "./ResearchConsentQuestion"
import RevealableContent from "./RevealableContent"
import RevealableHiddenContent from "./RevealableContent//RevealableHiddenContent"
Expand Down Expand Up @@ -78,7 +76,6 @@ export const blockTypeMapForPages = [
["moocfi/author-inner-block", AuthorInnerBlock],
["moocfi/conditional-block", ConditionalBlock],
["moocfi/exercise-custom-view-block", ExerciseCustomView],
["moocfi/partners", PartnersBlock],
["moocfi/top-level-pages", TopLevelPage],
["moocfi/expandable-content", ExpendableContent],
["moocfi/expandable-content-inner-block", ExpendableContentInnerBlock],
Expand All @@ -105,7 +102,6 @@ export const blockTypeMapForFrontPages = [
["moocfi/glossary", Glossary],
["moocfi/landing-page-hero-section", LandingPageHeroSection],
["moocfi/latex", Latex],
["moocfi/partners", PartnersBlock],
["moocfi/top-level-pages", TopLevelPage],
["moocfi/unsupported-block-type", UnsupportedBlock],
["moocfi/landing-page-copy-text", LandingPageCopyText],
Expand All @@ -114,6 +110,8 @@ export const blockTypeMapForFrontPages = [
["moocfi/conditional-block", ConditionalBlock],
["moocfi/exercise-custom-view-block", ExerciseCustomView],
["moocfi/code-giveaway", CodeGiveaway],
["moocfi/expandable-content", ExpendableContent],
["moocfi/expandable-content-inner-block", ExpendableContentInnerBlock],
// eslint-disable-next-line @typescript-eslint/no-explicit-any
] as Array<[string, BlockConfiguration<Record<string, any>>]>

Expand Down
2 changes: 2 additions & 0 deletions services/cms/src/blocks/supportedGutenbergBlocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ export const allowedEmailCoreBlocks: string[] = [
"core/table",
]

export const allowedPartnerCoreBlocks: string[] = ["core/image"]

export const allowedExamInstructionsCoreBlocks: string[] = [
"core/paragraph",
"core/image",
Expand Down
88 changes: 88 additions & 0 deletions services/cms/src/components/editors/PartnersBlockEditor.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/* eslint-disable i18next/no-literal-string */
import { css } from "@emotion/css"
import { BlockInstance } from "@wordpress/blocks"
import dynamic from "next/dynamic"
import React, { useContext, useState } from "react"
import { useTranslation } from "react-i18next"

import { allowedPartnerCoreBlocks } from "../../blocks/supportedGutenbergBlocks"
import CourseContext from "../../contexts/CourseContext"
import mediaUploadBuilder from "../../services/backend/media/mediaUpload"
import { modifyBlocks } from "../../utils/Gutenberg/modifyBlocks"

import { PartnersBlock } from "@/shared-module/common/bindings"
import Button from "@/shared-module/common/components/Button"
import Spinner from "@/shared-module/common/components/Spinner"

interface PartnersBlockEditorProps {
data: PartnersBlock
handleSave: (updatedTemplate: unknown) => Promise<PartnersBlock>
}

const EditorLoading = <Spinner variant="medium" />

const PartnersBlockGutenbergEditor = dynamic(() => import("./GutenbergEditor"), {
ssr: false,
loading: () => EditorLoading,
})

const PartnersSectionEditor: React.FC<React.PropsWithChildren<PartnersBlockEditorProps>> = ({
data,
handleSave,
}) => {
const courseId = useContext(CourseContext)?.courseId
const { t } = useTranslation()
const [content, setContent] = useState<BlockInstance[]>(
modifyBlocks(
(data.content ?? []) as BlockInstance[],
allowedPartnerCoreBlocks,
) as BlockInstance[],
)
const [saving, setSaving] = useState(false)
const [error, setError] = useState<string | null>(null)

const handleOnSave = async () => {
setSaving(true)
try {
const res = await handleSave(content)
setContent(res.content as BlockInstance[])
setError(null)
} catch (e: unknown) {
if (!(e instanceof Error)) {
throw e
}
setError(e.toString())
} finally {
setSaving(false)
}
}

return (
<>
<div className="editor__component">
<div
className={css`
margin: 4rem 0 2.5rem 0;
`}
>
{error && <pre>{error}</pre>}
<Button variant="primary" size="medium" disabled={saving} onClick={handleOnSave}>
{t("save")}
</Button>
</div>
</div>

{courseId && (
<PartnersBlockGutenbergEditor
content={content}
onContentChange={setContent}
allowedBlocks={allowedPartnerCoreBlocks}
mediaUpload={mediaUploadBuilder({ courseId: courseId })}
needToRunMigrationsAndValidations={false}
setNeedToRunMigrationsAndValidations={() => {}}
/>
)}
</>
)
}
export default PartnersSectionEditor
66 changes: 66 additions & 0 deletions services/cms/src/pages/partners-block/[id]/edit.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import dynamic from "next/dynamic"
import React from "react"

import CourseContext from "../../../contexts/CourseContext"

import { fetchPartnersBlock, setPartnerBlockForCourse } from "@/services/backend/partners-block"
import { PartnersBlock } from "@/shared-module/common/bindings"
import ErrorBanner from "@/shared-module/common/components/ErrorBanner"
import Spinner from "@/shared-module/common/components/Spinner"
import { withSignedIn } from "@/shared-module/common/contexts/LoginStateContext"
import useStateQuery from "@/shared-module/common/hooks/useStateQuery"
import dontRenderUntilQueryParametersReady, {
SimplifiedUrlQuery,
} from "@/shared-module/common/utils/dontRenderUntilQueryParametersReady"
import withErrorBoundary from "@/shared-module/common/utils/withErrorBoundary"

const EditorLoading = <Spinner variant="medium" />

const PartnersBlockEditor = dynamic(
() => import("../../../components/editors/PartnersBlockEditor"),
{
ssr: false,
loading: () => EditorLoading,
},
)

export interface PartnersBlockProps {
query: SimplifiedUrlQuery<"id">
}

const PartnersBlockEdit: React.FC<React.PropsWithChildren<PartnersBlockProps>> = ({ query }) => {
// const [needToRunMigrationsAndValidations, setNeedToRunMigrationsAndValidations] = useState(false)
const courseId = query.id
// eslint-disable-next-line i18next/no-literal-string
const blockQuery = useStateQuery(["partners-block", courseId], (courseId) =>
fetchPartnersBlock(courseId),
)

if (blockQuery.state === "error") {
return (
<>
<ErrorBanner variant={"readOnly"} error={blockQuery.error} />
</>
)
}

if (blockQuery.state !== "ready") {
return <Spinner variant={"medium"} />
}

const handleSave = async (data: unknown): Promise<PartnersBlock> => {
const res = await setPartnerBlockForCourse(courseId, data ?? [])
await blockQuery.refetch()
return res
}

return (
<CourseContext.Provider value={{ courseId: courseId }}>
<PartnersBlockEditor data={blockQuery.data} handleSave={handleSave} />
</CourseContext.Provider>
)
}

export default withErrorBoundary(
withSignedIn(dontRenderUntilQueryParametersReady(PartnersBlockEdit)),
)
22 changes: 22 additions & 0 deletions services/cms/src/services/backend/partners-block.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { cmsClient } from "./cmsClient"

import { PartnersBlock } from "@/shared-module/common/bindings"
import { isPartnersBlock } from "@/shared-module/common/bindings.guard"
import { validateResponse } from "@/shared-module/common/utils/fetching"

export const setPartnerBlockForCourse = async (
courseId: string,
data: object | null,
): Promise<PartnersBlock> => {
const response = await cmsClient.post(`/courses/${courseId}/partners-block`, data)
return validateResponse(response, isPartnersBlock)
}

export const fetchPartnersBlock = async (courseId: string): Promise<PartnersBlock> => {
const response = await cmsClient.get(`/courses/${courseId}/partners-block`)
return validateResponse(response, isPartnersBlock)
}

export const deletePartnersBlock = async (courseId: string): Promise<void> => {
await cmsClient.delete(`/courses/${courseId}/partners-block`)
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ import LearningObjectiveBlock from "./moocfi/LearningObjectiveBlock"
import LogoLink from "./moocfi/LogoLink"
import Map from "./moocfi/Map"
import PagesInChapterBlock from "./moocfi/PagesInChapterBlock"
import PartnersBlock from "./moocfi/PartnersBlock"
import ResearchConsentQuestionBlock from "./moocfi/ResearchConsentQuestionBlock"
import RevealableContentBlock from "./moocfi/RevealableContentBlock/RevealableContentBlock"
import RevealableHiddenContentBlock from "./moocfi/RevealableContentBlock/RevealableHiddenContentBlock"
Expand Down Expand Up @@ -157,7 +156,6 @@ export const blockToRendererMap: { [blockName: string]: any } = {
"moocfi/latex": LatexBlock,
"moocfi/learning-objectives": LearningObjectiveBlock,
"moocfi/pages-in-chapter": PagesInChapterBlock,
"moocfi/partners": PartnersBlock,
"moocfi/highlightbox": HighlightBox,
"moocfi/instructionbox": InstructionBoxBlock,
"moocfi/tablebox": TableBox,
Expand Down
Loading

0 comments on commit 27fa855

Please sign in to comment.