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: {