Skip to content

Commit

Permalink
feat(employeesSection): fetch and display employees
Browse files Browse the repository at this point in the history
  • Loading branch information
mathiazom committed Oct 24, 2024
1 parent 863ca70 commit c2e0c6c
Show file tree
Hide file tree
Showing 6 changed files with 237 additions and 11 deletions.
4 changes: 4 additions & 0 deletions next.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ const nextConfig = {
protocol: "https",
hostname: "cdn.sanity.io",
},
{
protocol: "https",
hostname: "chewiesald2ijhpvmb34c.blob.core.windows.net",
},
],
},
experimental: {
Expand Down
68 changes: 68 additions & 0 deletions src/components/sections/employees/Employees.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import Image from "next/image";

import { fetchAllChewbaccaEmployees } from "src/utils/employees";
import { EmployeesSection } from "studio/lib/interfaces/pages";

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

export interface EmployeesProps {
section: EmployeesSection;
}

export default async function Employees({ section }: EmployeesProps) {
const employeesResult = await fetchAllChewbaccaEmployees();

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

const employees = employeesResult.value;
const total = employees.length;

return (
<div className={styles.wrapper}>
<div className={styles.employees}>
<h1 className={styles.header}>{section.basicTitle}</h1>
<div className={styles.employeeCountWrapper}>
<p className={styles.employeeCount}>
Viser <span className={styles.employeeCountValue}>{total}</span> av{" "}
<span className={styles.employeeCountValue}>{total}</span>{" "}
konsulenter
</p>
</div>
{employees.map(
(employee) =>
employee.imageThumbUrl &&
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>
<div className={styles.employeeInfo}>
<p className={styles.employeeName}>{employee.name}</p>
{employee.officeName && (
<p className={styles.employeeRole}>{employee.officeName}</p>
)}
{employee.email && (
<p className={styles.employeeEmail}>{employee.email}</p>
)}
{employee.telephone && (
<p className={styles.employeeTelephone}>
{employee.telephone}
</p>
)}
</div>
</div>
),
)}
</div>
</div>
);
}
83 changes: 83 additions & 0 deletions src/components/sections/employees/employees.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
.wrapper {
display: flex;
flex-direction: column;
align-items: center;
margin: 5rem 0;
}

.header {
grid-column: 1 / -1;
color: var(--primary-black);
font-size: 48px;
font-weight: 600;
}

.employeeCountWrapper {
width: 100%;
grid-column: 1 / -1;
margin-bottom: -24px;
}

.employeeCount {
color: var(--primary-black);
font-size: 16px;
}

.employeeCountValue {
font-weight: 500;
}

.employees {
max-width: 1400px;
width: 100%;
text-wrap: wrap;
column-gap: 12px;
row-gap: 52px;
display: grid;
grid-template-columns: repeat(auto-fit, 225px);
justify-content: center;
padding: 1rem;
}

.employee {
display: flex;
flex-direction: column;
width: 100%;
gap: 1rem;
}

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

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

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

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

.employeeEmail,
.employeeTelephone {
color: var(--primary-black);
font-size: 16px;
font-weight: 300;
}
55 changes: 55 additions & 0 deletions src/types/employees.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
export interface ChewbaccaEmployeesResponse {
employees: ChewbaccaEmployee[];
}

export function isChewbaccaEmployeesResponse(
value: unknown,
): value is ChewbaccaEmployeesResponse {
return (
typeof value === "object" &&
value !== null &&
"employees" in value &&
Array.isArray(value.employees) &&
value.employees.every(isChewbaccaEmployee)
);
}

export interface ChewbaccaEmployee {
email?: string | null;
name?: string | null;
telephone?: string | null;
imageUrl?: string | null;
imageThumbUrl?: string | null;
officeName?: string | null;
startDate?: string | null;
}

export function isChewbaccaEmployee(
value: unknown,
): value is ChewbaccaEmployee {
return (
typeof value === "object" &&
value !== null &&
(!("email" in value) ||
typeof value.email === "string" ||
value.email === null) &&
(!("name" in value) ||
typeof value.name === "string" ||
value.name === null) &&
(!("telephone" in value) ||
typeof value.telephone === "string" ||
value.telephone === null) &&
(!("imageUrl" in value) ||
typeof value.imageUrl === "string" ||
value.imageUrl === null) &&
(!("imageThumbUrl" in value) ||
typeof value.imageThumbUrl === "string" ||
value.imageThumbUrl === null) &&
(!("officeName" in value) ||
typeof value.officeName === "string" ||
value.officeName === null) &&
(!("startDate" in value) ||
typeof value.startDate === "string" ||
value.startDate === null)
);
}
25 changes: 25 additions & 0 deletions src/utils/employees.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import {
ChewbaccaEmployee,
isChewbaccaEmployeesResponse,
} from "src/types/employees";
import { Result, ResultError, ResultOk } from "studio/utils/result";

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

export async function fetchAllChewbaccaEmployees(): Promise<
Result<ChewbaccaEmployee[], string>
> {
const employeesRes = await fetch(new URL("employees", CHEWBACCA_URL));
if (!employeesRes.ok) {
return ResultError(
`Fetch returned status ${employeesRes.status} ${employeesRes.statusText}`,
);
}
const employeesData = await employeesRes.json();
if (!isChewbaccaEmployeesResponse(employeesData)) {
return ResultError(
`Expected ChewbaccaEmployeesResponse, was ${employeesData}`,
);
}
return ResultOk(employeesData.employees);
}
13 changes: 2 additions & 11 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 Employees from "src/components/sections/employees/Employees";
import Grid from "src/components/sections/grid/Grid";
import GridPreview from "src/components/sections/grid/GridPreview";
import { Hero } from "src/components/sections/hero/Hero";
Expand Down Expand Up @@ -217,17 +218,7 @@ const SectionRenderer = ({
case "grid":
return renderGridSection(section, sectionIndex, isDraftMode, initialData);
case "employees":
return (
<pre
style={{
background: "hotpink",
padding: "3rem",
margin: 0,
}}
>
{JSON.stringify(section, null, 2)}
</pre>
);
return <Employees section={section} />;
default:
return null;
}
Expand Down

0 comments on commit c2e0c6c

Please sign in to comment.