From 0f283fb9b65080e26695de48251ee3cfac8956d8 Mon Sep 17 00:00:00 2001 From: Giacomo Baggio Date: Wed, 1 Sep 2021 16:26:30 +0200 Subject: [PATCH 1/7] Add single project handling. Needs blocks implementation --- .../mainNavigation/blocks/NavigationBlock.tsx | 4 +- frontend/graphql/generated.ts | 42 +- frontend/graphql/getProjects.graphql | 4 +- frontend/graphql/saveChanges.graphql | 1 + frontend/graphql/updateProject.graphql | 16 + frontend/pages/[[...slug]].tsx | 6 +- frontend/pages/projects/[...handle].tsx | 448 ++++++++++++++++++ frontend/pages/projects/index.tsx | 2 +- frontend/theme/index.ts | 8 + 9 files changed, 522 insertions(+), 9 deletions(-) create mode 100644 frontend/graphql/updateProject.graphql create mode 100644 frontend/pages/projects/[...handle].tsx diff --git a/frontend/features/mainNavigation/blocks/NavigationBlock.tsx b/frontend/features/mainNavigation/blocks/NavigationBlock.tsx index 76dbe4a3..f873c9ae 100644 --- a/frontend/features/mainNavigation/blocks/NavigationBlock.tsx +++ b/frontend/features/mainNavigation/blocks/NavigationBlock.tsx @@ -31,7 +31,6 @@ export function NavigationBlock({ url }: NavigationBlockProps) { px="2.5" py="3" letterSpacing="0.08em" - color="dark" position="relative" transition="all 0.3s" fontSize="sm" @@ -53,7 +52,8 @@ export function NavigationBlock({ url }: NavigationBlockProps) { opacity: "1", w: "full", }, - }}> + }} + > diff --git a/frontend/graphql/generated.ts b/frontend/graphql/generated.ts index 9ec0faac..f51955b0 100644 --- a/frontend/graphql/generated.ts +++ b/frontend/graphql/generated.ts @@ -1877,6 +1877,7 @@ export type GetGlobalQuery = ( ); export type GetProjectsQueryVariables = Exact<{ + where?: Maybe; locale?: Maybe; }>; @@ -1967,6 +1968,29 @@ export type UpdateMenuMutation = ( )> } ); +export type UpdateProjectMutationVariables = Exact<{ + projectInput?: Maybe; + menuInput?: Maybe; +}>; + + +export type UpdateProjectMutation = ( + { __typename?: 'Mutation' } + & { updateProject?: Maybe<( + { __typename?: 'updateProjectPayload' } + & { project?: Maybe<( + { __typename?: 'Project' } + & Pick + )> } + )>, updateMenu?: Maybe<( + { __typename?: 'updateMenuPayload' } + & { menu?: Maybe<( + { __typename?: 'Menu' } + & Pick + )> } + )> } +); + export const GetPages = ` query GetPages($where: JSON, $locale: String) { @@ -2074,8 +2098,8 @@ export const GetGlobal = ` } `; export const GetProjects = ` - query getProjects($locale: String) { - projects(locale: $locale) { + query getProjects($where: JSON, $locale: String) { + projects(where: $where, locale: $locale) { id linkPath linkLabel @@ -2153,5 +2177,19 @@ export const UpdateMenu = ` id } } +} + `; +export const UpdateProject = ` + mutation updateProject($projectInput: updateProjectInput, $menuInput: updateMenuInput) { + updateProject(input: $projectInput) { + project { + id + } + } + updateMenu(input: $menuInput) { + menu { + id + } + } } `; \ No newline at end of file diff --git a/frontend/graphql/getProjects.graphql b/frontend/graphql/getProjects.graphql index f2233276..f36193da 100644 --- a/frontend/graphql/getProjects.graphql +++ b/frontend/graphql/getProjects.graphql @@ -1,5 +1,5 @@ -query getProjects($locale: String) { - projects(locale: $locale) { +query getProjects($where: JSON, $locale: String) { + projects(where: $where, locale: $locale) { id linkPath linkLabel diff --git a/frontend/graphql/saveChanges.graphql b/frontend/graphql/saveChanges.graphql index 979a29ce..67dca359 100644 --- a/frontend/graphql/saveChanges.graphql +++ b/frontend/graphql/saveChanges.graphql @@ -4,6 +4,7 @@ mutation saveChanges($pageInput: updatePageInput, $menuInput: updateMenuInput) { id } } + updateMenu(input: $menuInput) { menu { id diff --git a/frontend/graphql/updateProject.graphql b/frontend/graphql/updateProject.graphql new file mode 100644 index 00000000..d93f9667 --- /dev/null +++ b/frontend/graphql/updateProject.graphql @@ -0,0 +1,16 @@ +mutation updateProject( + $projectInput: updateProjectInput + $menuInput: updateMenuInput +) { + updateProject(input: $projectInput) { + project { + id + } + } + + updateMenu(input: $menuInput) { + menu { + id + } + } +} diff --git a/frontend/pages/[[...slug]].tsx b/frontend/pages/[[...slug]].tsx index c424df7d..6cfa93c7 100644 --- a/frontend/pages/[[...slug]].tsx +++ b/frontend/pages/[[...slug]].tsx @@ -58,6 +58,8 @@ const StyledInlineBlocks = chakra(InlineBlocks); export default function DynamicPage({ data: data, preview }: DynamicPageProps) { const { colorMode } = useColorMode(); + console.log("data slug", data); + const itemProps = React.useMemo(() => { return { isPreview: preview, @@ -156,7 +158,7 @@ export const getStaticPaths: GetStaticPaths = async (context) => { return { paths, fallback: true }; }; -function wrap(value: T | T[]): T[] { +export function wrap(value: T | T[]): T[] { if (Array.isArray(value)) { return value; } @@ -391,7 +393,7 @@ function getPageData( path: page.path ? page.path : undefined, localizations: page.localizations ? filterListNullableItems( - page.localizations?.map((localization) => { + page.localizations.map((localization) => { return { id: localization?.id, locale: localization?.locale, diff --git a/frontend/pages/projects/[...handle].tsx b/frontend/pages/projects/[...handle].tsx new file mode 100644 index 00000000..1b401176 --- /dev/null +++ b/frontend/pages/projects/[...handle].tsx @@ -0,0 +1,448 @@ +import { Box, Img, Text } from "@chakra-ui/react"; +import { + LocaleMenu, + LocaleMenuButton, + LocaleMenuList, + LocaleMenuLink, +} from "@components/LocaleMenu"; +import { MobileNavDrawer } from "@components/MobileNavDrawer"; +import { WordmarkLogo } from "@components/WordmarkLogo"; +import { + NavBar, + NavMenuMobile, + NavMenuDesktop, +} from "@features/mainNavigation"; +import { + GetGlobal, + GetGlobalQuery, + GetGlobalQueryVariables, + GetProjects, + GetProjectsQuery, + GetProjectsQueryVariables, + UpdateMenuInput, + UpdateProject, + UpdateProjectInput, +} from "@graphql/generated"; +import { fetchGraphQL } from "@graphql/utils"; +import { SiteLayout } from "@layouts/siteLayout"; +import { + GlobalData, + LocalizationsData, + MenuData, +} from "@plugins/usePagePlugin"; +import { filterListNullableItems } from "@utils"; +import { GetStaticPaths, GetStaticProps } from "next"; +import { useRouter } from "next/router"; +import { wrap } from "pages/[[...slug]]"; +import React from "react"; +import { InlineForm, InlineText } from "react-tinacms-inline"; +import { useCMS, useForm, usePlugin } from "tinacms"; +import { FormOptions } from "tinacms"; +import { Form } from "tinacms"; +import { getGlobalData } from "."; +import NextLink from "next/link"; +import { STRAPI_URL } from "@config/env"; + +interface ProjectData { + id: string; + path: string; + linkPath: Nullable; + linkLabel: Nullable; + description: Nullable; + locale: Nullable; + companyName: Nullable; + projectType: Nullable; + image: Nullable; + localizations?: LocalizationsData[]; + blocks: string; +} + +interface ProjectImage { + id: string; + url: string; + alternativeText: Nullable; +} + +interface DynamicPageProps { + locale: string; + preview: boolean; + data: { + global: GlobalData; + project: ProjectData; + }; +} + +export default function DynamicPage({ data: data }: DynamicPageProps) { + console.log("data", JSON.stringify(data, null, " ")); + const [_, form] = useProjectPlugin(data); + const router = useRouter(); + + return ( + + + + + + + + + + + + + + + + {router.locale!.toUpperCase()} + + + + {router.locale?.toUpperCase()} + + {data ? ( + data.project.localizations?.map((pageLocale) => { + return ( + + {pageLocale.locale?.toUpperCase()} + + ); + }) + ) : ( + + )} + + + + + + + + + + + + + + + + + + + + + + + Blocchi + + + + + + ); +} + +export const getStaticPaths: GetStaticPaths = async (context) => { + if (context.locales == null) { + throw new Error("No locale has been defined!"); + } + const allProjectsRequests = context.locales.map(async (locale) => { + const localeProjects = await fetchGraphQL< + GetProjectsQuery, + GetProjectsQueryVariables + >(GetProjects, { + locale, + }); + + if (localeProjects.projects) { + return filterListNullableItems(localeProjects.projects); + } + return []; + }); + + const allProjects = await Promise.all(allProjectsRequests); + const projects = allProjects.flat(); + + const paths = projects.map((page) => { + const pagePath = page.path?.replace(/^\/+/, "") || ""; + + const slugArray: any = + pagePath.length > 0 ? pagePath.split("/") : undefined; + + console.log("slugArray", slugArray); + + return { + params: { handle: slugArray }, + locale: page.locale!, + }; + }); + + return { paths, fallback: "blocking" }; +}; + +export const getStaticProps: GetStaticProps< + DynamicPageProps | { notFound: boolean } +> = async (context) => { + const pathParts = wrap(context.params?.handle || []); + const path = `/projects/${pathParts.join("/")}`; + const locale = context.locale; + if (locale == null) { + throw new Error(`Path "${pathParts.join("/")}" has no locale!`); + } + const preview = context.preview === true; + + console.log("path", path); + + const availableProjects = await fetchGraphQL< + GetProjectsQuery, + GetProjectsQueryVariables + >(GetProjects, { + locale, + where: { + path, + }, + }); + + if (availableProjects.projects == null) { + return { + notFound: true, + }; + } + + const availableGlobal = await fetchGraphQL< + GetGlobalQuery, + GetGlobalQueryVariables + >(GetGlobal); + + if (availableGlobal.global == null) { + return { + notFound: true, + }; + } + + const projectData = getProjectData(availableProjects.projects, locale); + + const globalData = getGlobalData(availableGlobal.global); + + if (projectData == null) { + return { + notFound: true, + }; + } + + if (globalData == null) { + return { + notFound: true, + }; + } + + if (preview) { + return { + props: { + path: pathParts, + locale, + preview, + previewData: context.previewData, + data: { + global: globalData, + project: projectData, + }, + }, + }; + } + + return { + props: { + path: pathParts, + locale, + preview, + data: { + global: globalData, + project: projectData, + }, + }, + }; +}; + +function getProjectData( + projects: GetProjectsQuery["projects"], + locale: string +): ProjectData | undefined { + const project = projects?.find((project) => project?.locale === locale); + if (project == null) { + return undefined; + } + return { + id: project.id, + companyName: project.companyName || null, + description: project.description || null, + projectType: project.projectType || null, + linkLabel: project.linkLabel || null, + linkPath: project.linkPath || null, + path: project.path, + locale: project.locale || null, + blocks: "aa", + image: project.image + ? { + id: project.image.id, + url: project.image.url, + alternativeText: project.image.alternativeText || null, + } + : null, + localizations: project.localizations + ? filterListNullableItems(project.localizations).map( + (localization) => { + return { + id: localization.id, + locale: localization.locale || null, + path: localization.path || null, + }; + } + ) + : [], + }; +} + +function getProjectInput(data: ProjectData): UpdateProjectInput { + return { + where: { id: data.id }, + data: { + companyName: data.companyName, + description: data.description, + projectType: data.projectType, + linkLabel: data.linkLabel, + linkPath: data.linkPath, + path: data.path, + locale: data.locale, + blocks: undefined, + image: data.image ? data.image.id : null, + }, + }; +} + +interface Data { + project: ProjectData; + global: GlobalData; +} + +function useProjectPlugin(data: Data): [Data, Form] { + const cms = useCMS(); + const formConfig: FormOptions = { + id: data.project.id, + label: "Project settings", + initialValues: data, + onSubmit: async (data) => { + const projectInput = getProjectInput(data.project); + const menuInput = getMenuInput(data.global.topbar.menu); + try { + const response = await cms.api.strapi.fetchGraphql(UpdateProject, { + projectInput: projectInput, + menuInput: menuInput, + }); + + if (response.errors != null) { + cms.alerts.error("Error while saving data", 10000); + } else { + if (response.data) { + cms.alerts.success("Changes saved!"); + } else { + cms.alerts.error("Error while saving changes"); + } + } + } catch (error) { + console.log(error); + cms.alerts.error("Error while saving changes"); + } + }, + fields: [], + }; + + const [formData, form] = useForm(formConfig, { values: data }); + usePlugin(form); + + return [formData, form]; +} + +function getMenuInput(data: MenuData): UpdateMenuInput { + return { + where: { id: data.id }, + data: { + title: data.title, + links: data.links.map((link) => { + return { + id: link.id, + label: link.label || null, + url: link.url || null, + }; + }), + }, + }; +} diff --git a/frontend/pages/projects/index.tsx b/frontend/pages/projects/index.tsx index 36d63110..fa595bd5 100644 --- a/frontend/pages/projects/index.tsx +++ b/frontend/pages/projects/index.tsx @@ -498,7 +498,7 @@ function getMenuInput(data: GlobalData): UpdateMenuInput { }; } -function getGlobalData( +export function getGlobalData( global: GetGlobalQuery["global"] ): GlobalData | undefined { if (global == null) { diff --git a/frontend/theme/index.ts b/frontend/theme/index.ts index 9e784626..27e36b82 100644 --- a/frontend/theme/index.ts +++ b/frontend/theme/index.ts @@ -48,6 +48,14 @@ const overrides: ThemeOverride = { Define custom components */ }, + styles: { + global: { + body: { + fontSize: "sm", + letterSpacing: "0.02em", + }, + }, + }, }; const customTheme = extendTheme(overrides); From 55d246ee83c58b471de6c5d2258415bb09e6c171 Mon Sep 17 00:00:00 2001 From: Giacomo Baggio Date: Wed, 1 Sep 2021 16:31:56 +0200 Subject: [PATCH 2/7] Update index.tsx --- frontend/features/mainNavigation/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/features/mainNavigation/index.tsx b/frontend/features/mainNavigation/index.tsx index 7f97a4f1..086c8fcf 100644 --- a/frontend/features/mainNavigation/index.tsx +++ b/frontend/features/mainNavigation/index.tsx @@ -20,7 +20,7 @@ const NavigationInlineBlocks = chakra(InlineBlocks); export function NavBar({ children }: React.PropsWithChildren) { return ( - + ) { {children} - + ); } From a146f2d132ae9b7462bb38e7443bab81d9021b59 Mon Sep 17 00:00:00 2001 From: Giacomo Baggio Date: Wed, 1 Sep 2021 16:51:55 +0200 Subject: [PATCH 3/7] Fixes --- frontend/pages/projects/[...handle].tsx | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/frontend/pages/projects/[...handle].tsx b/frontend/pages/projects/[...handle].tsx index 1b401176..d7db2320 100644 --- a/frontend/pages/projects/[...handle].tsx +++ b/frontend/pages/projects/[...handle].tsx @@ -73,12 +73,11 @@ interface DynamicPageProps { } export default function DynamicPage({ data: data }: DynamicPageProps) { - console.log("data", JSON.stringify(data, null, " ")); const [_, form] = useProjectPlugin(data); const router = useRouter(); return ( - + @@ -237,8 +236,6 @@ export const getStaticPaths: GetStaticPaths = async (context) => { const slugArray: any = pagePath.length > 0 ? pagePath.split("/") : undefined; - console.log("slugArray", slugArray); - return { params: { handle: slugArray }, locale: page.locale!, @@ -259,8 +256,6 @@ export const getStaticProps: GetStaticProps< } const preview = context.preview === true; - console.log("path", path); - const availableProjects = await fetchGraphQL< GetProjectsQuery, GetProjectsQueryVariables From 6bed6f08600051f5bf69eb5670d08e7ac575abe7 Mon Sep 17 00:00:00 2001 From: Giacomo Baggio Date: Wed, 1 Sep 2021 16:56:17 +0200 Subject: [PATCH 4/7] Force project type to be uppercase --- frontend/pages/projects/[...handle].tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/pages/projects/[...handle].tsx b/frontend/pages/projects/[...handle].tsx index d7db2320..de539557 100644 --- a/frontend/pages/projects/[...handle].tsx +++ b/frontend/pages/projects/[...handle].tsx @@ -372,7 +372,7 @@ function getProjectInput(data: ProjectData): UpdateProjectInput { data: { companyName: data.companyName, description: data.description, - projectType: data.projectType, + projectType: data.projectType?.toUpperCase(), linkLabel: data.linkLabel, linkPath: data.linkPath, path: data.path, From 6bc9621339edce0020f052cf2699357e8efd5894 Mon Sep 17 00:00:00 2001 From: Giacomo Baggio Date: Wed, 1 Sep 2021 16:58:52 +0200 Subject: [PATCH 5/7] Update [...handle].tsx --- frontend/pages/projects/[...handle].tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/pages/projects/[...handle].tsx b/frontend/pages/projects/[...handle].tsx index de539557..cb4d93f6 100644 --- a/frontend/pages/projects/[...handle].tsx +++ b/frontend/pages/projects/[...handle].tsx @@ -78,7 +78,7 @@ export default function DynamicPage({ data: data }: DynamicPageProps) { return ( - + From 9571bfb6323aaad9ca76a73b50a6482410196161 Mon Sep 17 00:00:00 2001 From: Giacomo Baggio Date: Wed, 1 Sep 2021 17:04:36 +0200 Subject: [PATCH 6/7] Remove console.logs --- frontend/pages/[[...slug]].tsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/frontend/pages/[[...slug]].tsx b/frontend/pages/[[...slug]].tsx index 6cfa93c7..e07858f3 100644 --- a/frontend/pages/[[...slug]].tsx +++ b/frontend/pages/[[...slug]].tsx @@ -57,9 +57,6 @@ const StyledInlineBlocks = chakra(InlineBlocks); export default function DynamicPage({ data: data, preview }: DynamicPageProps) { const { colorMode } = useColorMode(); - - console.log("data slug", data); - const itemProps = React.useMemo(() => { return { isPreview: preview, From 2fa739d622355d900e83bd7f2737af184faf3ec8 Mon Sep 17 00:00:00 2001 From: Giacomo Baggio Date: Wed, 1 Sep 2021 17:09:24 +0200 Subject: [PATCH 7/7] Update [...handle].tsx --- frontend/pages/projects/[...handle].tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/pages/projects/[...handle].tsx b/frontend/pages/projects/[...handle].tsx index cb4d93f6..8947a7f3 100644 --- a/frontend/pages/projects/[...handle].tsx +++ b/frontend/pages/projects/[...handle].tsx @@ -200,7 +200,7 @@ export default function DynamicPage({ data: data }: DynamicPageProps) { pos="relative" > - Blocchi + Blocks