Skip to content

Commit

Permalink
feat: adds component and basic functionality for contact box
Browse files Browse the repository at this point in the history
  • Loading branch information
mikaelbr committed Nov 29, 2024
1 parent d4ce7df commit 11f5360
Show file tree
Hide file tree
Showing 11 changed files with 254 additions and 52 deletions.
84 changes: 43 additions & 41 deletions src/components/employeeCard/EmployeeCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,50 +24,52 @@ export default function EmployeeCard({
employee.name &&
employee.email && (
<div className={styles.employeeWrapper}>
<Link
href={`/${language}/${employeePageSlug}/${aliasFromEmail(employee.email)}`}
>
<div className={styles.employeeImage}>
<Image
src={employee.imageUrl}
alt={employee.name}
style={{ objectFit: "cover" }}
fill={true}
/>
</div>
</Link>
<div className={styles.employeeInfoWrapper}>
<Text type="h4" as="h3">
<Link
href={`/${language}/${employeePageSlug}/${aliasFromEmail(employee.email)}`}
className={styles.employeeNameLink}
>
{employee.name}
</Link>
</Text>

<div className={styles.employeeRole}>
{employee.competences.map((competence) => (
<Text
className={styles.employeeRoleDot}
type="labelRegular"
key={competence}
<div className={styles.employeeWrapper__inner}>
<Link
href={`/${language}/${employeePageSlug}/${aliasFromEmail(employee.email)}`}
>
<div className={styles.employeeImage}>
<Image
src={employee.imageUrl}
alt={employee.name}
style={{ objectFit: "cover" }}
fill={true}
/>
</div>
</Link>
<div className={styles.employeeInfoWrapper}>
<Text type="h4" as="h3">
<Link
href={`/${language}/${employeePageSlug}/${aliasFromEmail(employee.email)}`}
className={styles.employeeNameLink}
>
{competence}
</Text>
))}
</div>
{employee.name}
</Link>
</Text>

<div className={styles.employeeRole}>
{employee.competences.map((competence) => (
<Text
className={styles.employeeRoleDot}
type="labelRegular"
key={competence}
>
{competence}
</Text>
))}
</div>

<Text type="bodyExtraSmall">
<a href={`mailto:${employee.email}`}>{employee.email}</a>
</Text>
{employee.telephone && (
<Text type="bodyExtraSmall">
<a href={`tel:${employee.telephone}`}>
{formatPhoneNumber(employee.telephone)}
</a>
<Text type="bodyExtraSmall" className={styles.employeeEmail}>
<a href={`mailto:${employee.email}`}>{employee.email}</a>
</Text>
)}
{employee.telephone && (
<Text type="bodyExtraSmall">
<a href={`tel:${employee.telephone}`}>
{formatPhoneNumber(employee.telephone)}
</a>
</Text>
)}
</div>
</div>
</div>
)
Expand Down
16 changes: 14 additions & 2 deletions src/components/employeeCard/employeeCard.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,24 @@
}

.employeeWrapper {
container-type: inline-size;
container-name: employee;
}
.employeeWrapper__inner {
display: flex;
flex-direction: column;
align-items: flex-start;
min-width: 280px;
max-width: var(--Text-paragraph, 537px);
gap: var(--small, 6px);
gap: 1rem;
row-gap: var(--small, 6px);
}
@container employee (min-width: 400px) {
.employeeWrapper__inner {
flex-direction: row;
}
.employeeEmail {
margin-top: auto;
}
}

.employeeInfoWrapper {
Expand Down
74 changes: 74 additions & 0 deletions src/components/sections/contact-box/ContactBox.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { Suspense } from "react";

import { EmployeeCardSkeleton } from "src/components/employeeCard/EmployeeCard";
import Text from "src/components/text/Text";
import { ChewbaccaEmployee } from "src/types/employees";
import { fetchEmployeesByEmails } from "src/utils/employees";
import { ContactBoxSection } from "studio/lib/interfaces/pages";
import { EMPLOYEE_PAGE_SLUG_QUERY } from "studio/lib/queries/siteSettings";
import { loadStudioQuery } from "studio/lib/store";

import styles from "./contact-box.module.css";
import ContactSelector, { EmployeeAndTag } from "./ContactSelector";

export interface ContactBoxProps {
section: ContactBoxSection;
language: string;
}

export default async function ContactBox({
section,
language,
}: ContactBoxProps) {
const employeesPageRes = await loadStudioQuery<{ slug: string }>(
EMPLOYEE_PAGE_SLUG_QUERY,
{
language,
},
);
const employeesPageSlug = employeesPageRes.data.slug;

const contactPoints = fetchEmployeesByEmails(
section.contactPoints.map((contactPoint) => contactPoint.email),
).then((result) =>
result.ok
? result.value.map((e) => employeeAndTag(e, section.contactPoints))
: [],
);
return (
<section className={styles.contactBox}>
<div>
<Text type="h3" as="h2">
{section.basicTitle}
</Text>

{section.optionalSubtitle && (
<Text type="bodyBig">{section.optionalSubtitle}</Text>
)}
</div>

<div>
<Suspense fallback={<EmployeeCardSkeleton />}>
<ContactSelector
employeesPageSlug={employeesPageSlug}
contactPoints={contactPoints}
language={language}
/>
</Suspense>
</div>
</section>
);
}

function employeeAndTag(
employee: ChewbaccaEmployee,
contactPoints: ContactBoxSection["contactPoints"],
): EmployeeAndTag {
const tag =
contactPoints.find((contactPoint) => contactPoint.email === employee.email)
?.tag ?? "";
return {
employee,
tag,
};
}
37 changes: 37 additions & 0 deletions src/components/sections/contact-box/ContactBoxPreview.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
"use client";

import { useQuery } from "@sanity/react-loader";
import { Suspense } from "react";

import { PreviewProps } from "src/types/preview";
import { ContactBoxSection, PageBuilder } from "studio/lib/interfaces/pages";
import { PAGE_QUERY } from "studio/lib/queries/pages";

import ContactBox from "./ContactBox";

export default function ContactBoxPreview({
initialData,
sectionIndex,
}: PreviewProps) {
const { data: newData } = useQuery<PageBuilder | null>(
PAGE_QUERY,
{ id: initialData.data._id, language: initialData.data.language },
{ initial: initialData },
);

const section = newData
? (newData.sections.find(
(section, index) =>
section._type === "contactBox" && index === sectionIndex,
) as ContactBoxSection)
: (initialData.data.sections.find(
(section, index) =>
section._type === "contactBox" && index === sectionIndex,
) as ContactBoxSection);

return (
<Suspense>
<ContactBox section={section} language={initialData.data.language} />
</Suspense>
);
}
58 changes: 58 additions & 0 deletions src/components/sections/contact-box/ContactSelector.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
"use client";

import { use, useState } from "react";

import EmployeeCard from "src/components/employeeCard/EmployeeCard";
import { Tag } from "src/components/tag";
import { ChewbaccaEmployee } from "src/types/employees";

export type EmployeeAndTag = {
employee: ChewbaccaEmployee;
tag: string;
};

export type ContactSelectorProps = {
contactPoints: Promise<EmployeeAndTag[]>;
employeesPageSlug: string;
language: string;
};

export default function ContactSelector({
contactPoints: contactPointsPromise,
employeesPageSlug,
language,
}: ContactSelectorProps) {
const contactPoints = use(contactPointsPromise);

const [selectedTag, setSelectedTag] = useState<string | null>(
contactPoints[0].tag,
);
const selectedContactPoint = contactPoints.find(
(contactPoint) => selectedTag == contactPoint.tag,
);

return (
<div>
<div>
{contactPoints.map((contactPoint) => (
<Tag
key={contactPoint.tag}
type="button"
active={selectedTag === contactPoint.tag}
onClick={() => setSelectedTag(contactPoint.tag)}
text={contactPoint.tag}
/>
))}
</div>
<div>
{selectedContactPoint?.employee && (
<EmployeeCard
employee={selectedContactPoint.employee}
employeePageSlug={employeesPageSlug}
language={language}
/>
)}
</div>
</div>
);
}
Empty file.
3 changes: 3 additions & 0 deletions src/utils/renderSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import Callout from "src/components/sections/callout/Callout";
import CalloutPreview from "src/components/sections/callout/CalloutPreview";
import CallToAction from "src/components/sections/callToAction/CallToAction";
import CallToActionPreview from "src/components/sections/callToAction/CallToActionPreview";
import ContactBox from "src/components/sections/contact-box/ContactBox";
import Employees from "src/components/sections/employees/Employees";
import Grid from "src/components/sections/grid/Grid";
import GridPreview from "src/components/sections/grid/GridPreview";
Expand Down Expand Up @@ -219,6 +220,8 @@ const SectionRenderer = ({
);
case "grid":
return renderGridSection(section, sectionIndex, isDraftMode, initialData);
case "contactBox":
return <ContactBox section={section} language={language} />;
case "employees":
return <Employees language={language} section={section} />;
default:
Expand Down
3 changes: 2 additions & 1 deletion studio/lib/interfaces/pages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ export interface ContactBoxSection {
_type: "contactBox";
_key: string;
basicTitle: string;
optionalSubtitle: string;
optionalSubtitle?: string;
contactPoints: {
_key: string;
_type: string;
Expand All @@ -108,6 +108,7 @@ export type Section =
| TestimonialsSection
| ImageSection
| GridSection
| ContactBoxSection
| EmployeesSection;

export interface PageBuilder {
Expand Down
4 changes: 2 additions & 2 deletions studio/lib/queries/pages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ const SECTIONS_FRAGMENT = groq`
},
_type == "employees" => {
"basicTitle": ${translatedFieldFragment("basicTitle")}
}
},
_type == "contactBox" => {
"basicTitle": ${translatedFieldFragment("basicTitle")}
"basicTitle": ${translatedFieldFragment("basicTitle")},
"optionalSubtitle": ${translatedFieldFragment("optionalSubtitle")}
}
}
Expand Down
2 changes: 1 addition & 1 deletion studio/schemas/documents/pageBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { titleID } from "studio/schemas/fields/text";
import article from "studio/schemas/objects/sections/article";
import callout from "studio/schemas/objects/sections/callout";
import callToAction from "studio/schemas/objects/sections/callToAction";
import contactBox from "studio/schemas/objects/sections/contact-box";
import { employees } from "studio/schemas/objects/sections/employees";
import grid from "studio/schemas/objects/sections/grid";
import hero from "studio/schemas/objects/sections/hero";
Expand All @@ -14,7 +15,6 @@ import testimonals from "studio/schemas/objects/sections/testimonials";
import seo from "studio/schemas/objects/seo";
import { titleSlug } from "studio/schemas/schemaTypes/slug";
import { firstTranslation } from "studio/utils/i18n";
import contactBox from "../objects/sections/contact-box";

export const pageBuilderID = "pageBuilder";

Expand Down
Loading

0 comments on commit 11f5360

Please sign in to comment.