From f6b26ff721c99ef0ef4e1583de12d206b286ec0e Mon Sep 17 00:00:00 2001 From: Mathias Oterhals Myklebust <24361490+mathiazom@users.noreply.github.com> Date: Wed, 30 Oct 2024 08:05:53 +0000 Subject: [PATCH] v3 - featured customer cases (#837) * fix(customerCase): prevent content overflow * feat(customerCase): featured customer cases * feat(featuredCases): case link in title --- src/app/(main)/[lang]/[...path]/page.tsx | 7 ++- .../customerCase/CustomerCase.tsx | 22 +++++++-- .../customerCase/customerCase.module.css | 4 +- .../featuredCases/FeaturedCases.tsx | 42 ++++++++++++++++ .../featuredCases/featuredCases.module.css | 34 +++++++++++++ src/utils/pageData.ts | 13 ++++- studioShared/lib/interfaces/customerCases.ts | 1 + studioShared/lib/queries/customerCases.ts | 3 ++ .../schemas/documents/customerCase.ts | 49 ++++++++++++++++++- 9 files changed, 164 insertions(+), 11 deletions(-) create mode 100644 src/components/customerCases/customerCase/featuredCases/FeaturedCases.tsx create mode 100644 src/components/customerCases/customerCase/featuredCases/featuredCases.module.css diff --git a/src/app/(main)/[lang]/[...path]/page.tsx b/src/app/(main)/[lang]/[...path]/page.tsx index ecc4a66f5..a5ebe84bd 100644 --- a/src/app/(main)/[lang]/[...path]/page.tsx +++ b/src/app/(main)/[lang]/[...path]/page.tsx @@ -123,7 +123,12 @@ async function Page({ params }: Props) { ); case "customerCase": - return ; + return ( + + ); case "legalDocument": return isDraftMode ? ( diff --git a/src/components/customerCases/customerCase/CustomerCase.tsx b/src/components/customerCases/customerCase/CustomerCase.tsx index c5448462e..0aac97cf5 100644 --- a/src/components/customerCases/customerCase/CustomerCase.tsx +++ b/src/components/customerCases/customerCase/CustomerCase.tsx @@ -7,13 +7,10 @@ import { } from "studioShared/lib/interfaces/customerCases"; import styles from "./customerCase.module.css"; +import FeaturedCases from "./featuredCases/FeaturedCases"; import ImageSection from "./sections/image/ImageSection"; import RichTextSection from "./sections/richText/RichTextSection"; -export interface CustomerCaseProps { - customerCase: CustomerCaseDocument; -} - function CustomerCaseSection({ section, }: { @@ -36,7 +33,15 @@ function CustomerCaseSection({ } } -export default function CustomerCase({ customerCase }: CustomerCaseProps) { +export interface CustomerCaseProps { + customerCase: CustomerCaseDocument; + customerCasesPagePath: string[]; +} + +export default function CustomerCase({ + customerCase, + customerCasesPagePath, +}: CustomerCaseProps) { return (
@@ -129,6 +134,13 @@ export default function CustomerCase({ customerCase }: CustomerCaseProps) { ))}
+ {customerCase.featuredCases && + customerCase.featuredCases.length > 0 && ( + + )}
); diff --git a/src/components/customerCases/customerCase/customerCase.module.css b/src/components/customerCases/customerCase/customerCase.module.css index 4c84e30be..3e494e622 100644 --- a/src/components/customerCases/customerCase/customerCase.module.css +++ b/src/components/customerCases/customerCase/customerCase.module.css @@ -1,11 +1,11 @@ .wrapper { display: flex; flex-direction: column; - margin: 4rem 0; + margin: 4rem 2rem; align-items: center; @media (max-width: 1024px) { - margin: 2rem 0; + margin: 2rem 1rem; } } diff --git a/src/components/customerCases/customerCase/featuredCases/FeaturedCases.tsx b/src/components/customerCases/customerCase/featuredCases/FeaturedCases.tsx new file mode 100644 index 000000000..e1996305e --- /dev/null +++ b/src/components/customerCases/customerCase/featuredCases/FeaturedCases.tsx @@ -0,0 +1,42 @@ +import Link from "next/link"; + +import { SanitySharedImage } from "src/components/image/SanityImage"; +import Text from "src/components/text/Text"; +import { CustomerCaseBase } from "studioShared/lib/interfaces/customerCases"; + +import styles from "./featuredCases.module.css"; + +export interface FeaturedCasesProps { + featuredCases: CustomerCaseBase[]; + customerCasesPath: string[]; +} + +export default function FeaturedCases({ + featuredCases, + customerCasesPath, +}: FeaturedCasesProps) { + return ( + featuredCases.length > 0 && ( +
+ Lignende prosjekter +
+ {featuredCases.map((featuredCase) => ( +
+
+ +
+
+ + {featuredCase.basicTitle} + + {featuredCase.description} +
+
+ ))} +
+
+ ) + ); +} diff --git a/src/components/customerCases/customerCase/featuredCases/featuredCases.module.css b/src/components/customerCases/customerCase/featuredCases/featuredCases.module.css new file mode 100644 index 000000000..66e0ad32b --- /dev/null +++ b/src/components/customerCases/customerCase/featuredCases/featuredCases.module.css @@ -0,0 +1,34 @@ +.wrapper { + display: flex; + flex-direction: column; + gap: 2rem; + margin: 4rem 0; +} + +.content { + display: flex; + gap: 5rem; + + @media (max-width: 1024px) { + flex-direction: column; + } +} + +.caseWrapper { + display: flex; + flex-direction: column; + gap: 1rem; + max-width: 500px; + flex-grow: 1; + flex-basis: 0; +} + +.caseImageWrapper { + width: 100%; + height: 200px; +} + +.caseImageWrapper img { + border-radius: 0.75rem; + width: 100% !important; +} diff --git a/src/utils/pageData.ts b/src/utils/pageData.ts index 9cfd39760..bdf0853a8 100644 --- a/src/utils/pageData.ts +++ b/src/utils/pageData.ts @@ -148,7 +148,13 @@ async function fetchCustomerCase({ perspective, }: PageDataParams): Promise< | PageFromParams, "customerCasesPage"> - | PageFromParams, "customerCase"> + | PageFromParams< + { + customerCase: QueryResponseInitial; + customerCasesPagePath: string[]; + }, + "customerCase" + > | null > { if (path.length === 0) { @@ -204,7 +210,10 @@ async function fetchCustomerCase({ }, ); return { - queryResponse: customerCaseResult, + queryResponse: { + customerCase: customerCaseResult, + customerCasesPagePath: [language, customerCasesPageResult.data.slug], + }, docType: customerCaseID, pathTranslations: casePathTranslations.data?.reduce( diff --git a/studioShared/lib/interfaces/customerCases.ts b/studioShared/lib/interfaces/customerCases.ts index 12acee40f..48d14d16c 100644 --- a/studioShared/lib/interfaces/customerCases.ts +++ b/studioShared/lib/interfaces/customerCases.ts @@ -32,4 +32,5 @@ export type CustomerCaseSection = RichTextBlock | ImageBlock | QuoteBlock; export interface CustomerCase extends CustomerCaseBase { projectInfo: CustomerCaseProjectInfo; sections: CustomerCaseSection[]; + featuredCases?: CustomerCaseBase[] | null; } diff --git a/studioShared/lib/queries/customerCases.ts b/studioShared/lib/queries/customerCases.ts index b0544be5d..49f68ed7a 100644 --- a/studioShared/lib/queries/customerCases.ts +++ b/studioShared/lib/queries/customerCases.ts @@ -63,6 +63,9 @@ export const CUSTOMER_CASE_QUERY = groq` "quote": ${translatedFieldFragment("quote")}, "author": ${translatedFieldFragment("author")}, }, + }, + "featuredCases": featuredCases[] -> { + ${CUSTOMER_CASE_BASE_FRAGMENT} } } `; diff --git a/studioShared/schemas/documents/customerCase.ts b/studioShared/schemas/documents/customerCase.ts index 7ee52261f..d9a602a8d 100644 --- a/studioShared/schemas/documents/customerCase.ts +++ b/studioShared/schemas/documents/customerCase.ts @@ -1,9 +1,11 @@ -import { defineField, defineType } from "sanity"; +import { groq } from "next-sanity"; +import { Reference, defineField, defineType } from "sanity"; import { isInternationalizedString } from "studio/lib/interfaces/global"; import { internationalizedImage } from "studio/schemas/fields/media"; import { titleID } from "studio/schemas/fields/text"; import { titleSlug } from "studio/schemas/schemaTypes/slug"; +import { buildDraftId, buildPublishedId } from "studio/utils/documentUtils"; import { firstTranslation } from "studio/utils/i18n"; import { customerCaseProjectInfo } from "studioShared/schemas/fields/customerCaseProjectInfo"; import imageBlock from "studioShared/schemas/objects/imageBlock"; @@ -73,6 +75,51 @@ const customerCase = defineType({ type: "array", of: [richTextBlock, imageBlock, listBlock, quoteBlock], }), + defineField({ + name: "featuredCases", + title: "Featured Cases", + description: + "List of Customer Cases that should be displayed at the bottom of this Customer Case", + type: "array", + of: [ + { + type: "reference", + to: [{ type: customerCaseID }], + validation: (rule) => + rule.custom((value: Reference, context) => { + if ( + context.document !== undefined && + buildPublishedId(value._ref) === + buildPublishedId(context.document._id) + ) { + return "Can not feature itself"; + } + return true; + }), + options: { + disableNew: true, + filter: ({ document, parent }) => ({ + // hide current and already featured customer cases + filter: groq`!(_id in $forbiddenIds)`, + params: { + forbiddenIds: [ + buildPublishedId(document._id), + buildDraftId(document._id), + ...(Array.isArray(parent) + ? parent.flatMap((r) => + typeof r._ref === "string" + ? [buildPublishedId(r._ref), buildDraftId(r._ref)] + : undefined, + ) + : []), + ], + }, + }), + }, + }, + ], + validation: (rule) => rule.max(3).unique(), + }), ], preview: { select: {