Skip to content

Commit

Permalink
feat(employees): employee subpage
Browse files Browse the repository at this point in the history
  • Loading branch information
mathiazom committed Oct 29, 2024
1 parent 7d02acc commit 4c077e9
Show file tree
Hide file tree
Showing 11 changed files with 334 additions and 13 deletions.
22 changes: 22 additions & 0 deletions src/app/(main)/[lang]/[...path]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
import { Metadata } from "next";
import { headers } from "next/headers";

import Compensations from "src/components/compensations/Compensations";
import CompensationsPreview from "src/components/compensations/CompensationsPreview";
import CustomerCase from "src/components/customerCases/customerCase/CustomerCase";
import CustomerCases from "src/components/customerCases/CustomerCases";
import CustomerCasesPreview from "src/components/customerCases/CustomerCasesPreview";
import CustomErrorMessage from "src/components/customErrorMessage/CustomErrorMessage";
import EmployeePage from "src/components/employeePage/EmployeePage";
import Legal from "src/components/legal/Legal";
import LegalPreview from "src/components/legal/LegalPreview";
import PageHeader from "src/components/navigation/header/PageHeader";
import { homeLink } from "src/components/utils/linkTypes";
import { ChewbaccaEmployee } from "src/types/employees";
import { getDraftModeInfo } from "src/utils/draftmode";
import { fetchPageDataFromParams } from "src/utils/pageData";
import SectionRenderer from "src/utils/renderSection";
Expand All @@ -21,6 +24,17 @@ type Props = {
params: { lang: string; path: string[] };
};

function seoDataFromChewbaccaEmployee(employee: ChewbaccaEmployee) {
return {
title: employee.name ?? undefined,
description: employee.email ?? undefined,
imageUrl: employee.imageThumbUrl ?? undefined,
keywords: [employee.name, employee.email, employee.telephone]
.filter((d) => d != null)
.join(","),
};
}

function seoDataFromPageData(
data: Awaited<ReturnType<typeof fetchPageDataFromParams>>,
): SeoData | null {
Expand All @@ -42,6 +56,9 @@ function seoDataFromPageData(
case "compensations": {
return data.queryResponse.compensationsPage.data.seo;
}
case "employee": {
return seoDataFromChewbaccaEmployee(data.queryResponse);
}
}
}

Expand All @@ -52,6 +69,7 @@ export async function generateMetadata({ params }: Props): Promise<Metadata> {
language,
path: params.path,
perspective: perspective ?? "published",
hostname: headers().get("host"),
});
return generateMetadataFromSeo(seoDataFromPageData(pageData), language);
}
Expand All @@ -73,6 +91,7 @@ async function Page({ params }: Props) {
language: lang,
path,
perspective: perspective ?? "published",
hostname: headers().get("host"),
});

if (pageData == null) {
Expand All @@ -93,6 +112,7 @@ async function Page({ params }: Props) {
{queryResponse.data?.sections?.map((section, index) => (
<SectionRenderer
key={section._key}
language={lang}
section={section}
isDraftMode={isDraftMode}
initialData={queryResponse}
Expand Down Expand Up @@ -130,6 +150,8 @@ async function Page({ params }: Props) {
) : (
<Legal document={queryResponse.data} />
);
case "employee":
return <EmployeePage employee={queryResponse} />;
}
return Page404;
})()}
Expand Down
1 change: 1 addition & 0 deletions src/app/(main)/[lang]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ const Home = async ({ params }: Props) => {
{initialLandingPage.data.sections.map((section, index) => (
<SectionRenderer
key={section._key}
language={params.lang}
section={section}
isDraftMode={isDraftMode}
initialData={initialLandingPage}
Expand Down
52 changes: 52 additions & 0 deletions src/components/employeePage/EmployeePage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import Image from "next/image";

import Text from "src/components/text/Text";
import { ChewbaccaEmployee } from "src/types/employees";

import styles from "./employeePage.module.css";

export interface EmployeePageProps {
employee: ChewbaccaEmployee;
}

export default function EmployeePage({ employee }: EmployeePageProps) {
const image = employee.imageUrl ?? employee.imageThumbUrl ?? null;
return (
employee.name && (
<div className={styles.wrapper}>
<div className={styles.content}>
<div className={styles.employee}>
{image != null && (
<div className={styles.employeeImage}>
<Image
src={image}
alt={employee.name}
objectFit="cover"
fill={true}
/>
</div>
)}
<div className={styles.employeeInfo}>
<Text type={"h2"}>{employee.name}</Text>
{employee.email && (
<Text type={"bodyBig"} className={styles.employeeEmail}>
{employee.email}
</Text>
)}
{employee.telephone && (
<Text type={"bodyBig"} className={styles.employeeTelephone}>
{employee.telephone}
</Text>
)}
{employee.officeName && (
<Text type={"bodyNormal"} className={styles.employeeRole}>
{employee.officeName}
</Text>
)}
</div>
</div>
</div>
</div>
)
);
}
68 changes: 68 additions & 0 deletions src/components/employeePage/employeePage.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
.wrapper {
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
}

.content {
width: 100%;
max-width: 1200px;
display: flex;
flex-direction: column;
align-items: center;
padding: 4rem 0 8rem 0;
}

.employee {
display: flex;
gap: 3rem;
flex-direction: column;
margin: 1rem;

@media (min-width: 1024px) {
flex-direction: row;
align-items: center;
}
}

.employeeImage {
display: flex;
flex-direction: column;
align-items: center;
background-color: var(--primary-black);
border-radius: 12px;
width: 300px;
height: 300px;
padding: 1rem;
position: relative;

@media (max-width: 1024px) {
flex-direction: column;
width: 200px;
height: 200px;
}
}

.employeeInfo {
display: flex;
flex-direction: column;
gap: 6px;
}

.employeeName {
color: var(--primary-black);
font-size: 64px;
font-weight: 600;
}

.employeeRole {
color: var(--primary-black);
font-weight: 300;
}

.employeeEmail,
.employeeTelephone {
color: var(--primary-black);
font-weight: 300;
}
48 changes: 37 additions & 11 deletions src/components/sections/employees/Employees.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,45 @@
import { headers } from "next/headers";
import Image from "next/image";
import Link from "next/link";

import { fetchAllChewbaccaEmployees } from "src/utils/employees";
import {
aliasFromEmail,
domainFromEmail,
fetchAllChewbaccaEmployees,
} from "src/utils/employees";
import { domainFromHostname } from "src/utils/url";
import { EmployeesSection } from "studio/lib/interfaces/pages";
import { EMPLOYEE_PAGE_SLUG_QUERY } from "studio/lib/queries/siteSettings";
import { loadStudioQuery } from "studio/lib/store";

import styles from "./employees.module.css";

export interface EmployeesProps {
language: string;
section: EmployeesSection;
}

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

const employeesResult = await fetchAllChewbaccaEmployees();

if (!employeesResult.ok) {
console.error("Failed to fetch employees: ", employeesResult.error);
return;
}

const employees = employeesResult.value;
const domain = domainFromHostname(headers().get("host"));
const employees = employeesResult.value.filter(
(employee) =>
employee.email != null && domainFromEmail(employee.email) === domain,
);
const total = employees.length;

return (
Expand All @@ -37,14 +59,18 @@ export default async function Employees({ section }: EmployeesProps) {
employee.name &&
employee.email && (
<div key={employee.email} className={styles.employee}>
<div className={styles.employeeImage}>
<Image
src={employee.imageUrl ?? employee.imageThumbUrl}
alt={employee.name}
objectFit="cover"
fill={true}
/>
</div>
<Link
href={`/${language}/${employeesPageSlug}/${aliasFromEmail(employee.email)}`}
>
<div className={styles.employeeImage}>
<Image
src={employee.imageUrl ?? employee.imageThumbUrl}
alt={employee.name}
objectFit="cover"
fill={true}
/>
</div>
</Link>
<div className={styles.employeeInfo}>
<p className={styles.employeeName}>{employee.name}</p>
{employee.officeName && (
Expand Down
30 changes: 29 additions & 1 deletion src/middlewares/languageMiddleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,26 @@ async function translateCustomerCasePath(
);
}

async function translateEmployeePagePath(
path: string[],
targetLanguageId: string,
sourceLanguageId?: string,
) {
if (path.length !== 2) {
return undefined;
}
const pageSlugTranslation = await translateSlug(
path[0],
targetLanguageId,
sourceLanguageId,
"pageBuilder",
);
if (pageSlugTranslation === undefined) {
return undefined;
}
return [pageSlugTranslation, path[1]];
}

async function translatePath(
path: string[],
targetLanguageId: string,
Expand All @@ -158,7 +178,15 @@ async function translatePath(
(slug) => (slug !== undefined ? [slug] : undefined),
);
}
const pathTranslation = await translateCustomerCasePath(
let pathTranslation = await translateCustomerCasePath(
path,
targetLanguageId,
sourceLanguageId,
);
if (pathTranslation !== undefined) {
return pathTranslation;
}
pathTranslation = await translateEmployeePagePath(
path,
targetLanguageId,
sourceLanguageId,
Expand Down
33 changes: 33 additions & 0 deletions src/utils/employees.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import {
} from "src/types/employees";
import { Result, ResultError, ResultOk } from "studio/utils/result";

import { domainFromHostname } from "./url";

const CHEWBACCA_URL = "https://chewie-webapp-ld2ijhpvmb34c.azurewebsites.net";

export async function fetchAllChewbaccaEmployees(): Promise<
Expand All @@ -23,3 +25,34 @@ export async function fetchAllChewbaccaEmployees(): Promise<
}
return ResultOk(employeesData.employees);
}

export async function fetchChewbaccaEmployee(
email: string,
): Promise<Result<ChewbaccaEmployee, string>> {
const allEmployeesRes = await fetchAllChewbaccaEmployees();
if (!allEmployeesRes.ok) {
return allEmployeesRes;
}
const employee = allEmployeesRes.value.find(
(employee) => employee.email === email,
);
if (!employee) {
return ResultError("Employee does not exist for given email");
}
return ResultOk(employee);
}

export function emailFromAliasAndHostname(
alias: string,
hostname: string | null,
) {
return `${alias}@${domainFromHostname(hostname)}`;
}

export function aliasFromEmail(email: string): string {
return email.split("@")[0];
}

export function domainFromEmail(email: string) {
return email.split("@")[1];
}
Loading

0 comments on commit 4c077e9

Please sign in to comment.