diff --git a/src/components/buttons/Button.tsx b/src/components/buttons/Button.tsx index 75edfd9f9..1a0b77f68 100644 --- a/src/components/buttons/Button.tsx +++ b/src/components/buttons/Button.tsx @@ -2,8 +2,8 @@ import React from "react"; import styles from "./button.module.css"; -type ButtonType = "primary" | "secondary"; -type ButtonSize = "large" | "small"; +type ButtonType = "primary" | "secondary" | "secondaryFilled"; +type ButtonSize = "large" | "small" | "extraSmall"; interface IButton { size?: ButtonSize; @@ -18,11 +18,13 @@ interface IButton { const sizeClassMap: { [key in ButtonSize]: string } = { large: styles.large, small: styles.small, + extraSmall: styles.extraSmall, }; const typeClassMap: { [key in ButtonType]: string } = { primary: styles.primary, secondary: styles.secondary, + secondaryFilled: styles.secondaryFilled, }; const Button = ({ diff --git a/src/components/buttons/button.module.css b/src/components/buttons/button.module.css index 06ef56415..8ff950baf 100644 --- a/src/components/buttons/button.module.css +++ b/src/components/buttons/button.module.css @@ -37,6 +37,17 @@ } } +.extraSmall { + composes: button; + padding: 0.375rem 1.25rem; + font-size: 1rem; + font-weight: 400; + + @media (min-width: 1024px) { + font-size: 1.125rem; + } +} + .primary { background: var(--primary-dark); color: var(--primary-white); @@ -65,6 +76,20 @@ } } +.secondaryFilled { + background: var(--primary-black); + color: var(--primary-white); + border: 1px solid var(--primary-black); + + &:hover { + background: var(--primary-black-darker); + } + + &:active { + background: var(--primary-black-darker); + } +} + .back { composes: secondary; diff --git a/src/components/consultantCard/ConsultantCard.tsx b/src/components/consultantCard/ConsultantCard.tsx new file mode 100644 index 000000000..046cde83a --- /dev/null +++ b/src/components/consultantCard/ConsultantCard.tsx @@ -0,0 +1,74 @@ +import Image from "next/image"; +import Link from "next/link"; + +import CustomLink from "src/components/link/CustomLink"; +import { ChewbaccaEmployee } from "src/types/employees"; +import { aliasFromEmail } from "src/utils/employees"; +import { LinkType } from "studio/lib/interfaces/navigation"; + +import styles from "./consultantCard.module.css"; + +export interface ConsultantCardProps { + currentLanguage: string; + consultant: ChewbaccaEmployee; + employeePageSlug?: string; +} + +export default function ConsultantCard({ + currentLanguage, + consultant, + employeePageSlug, +}: ConsultantCardProps) { + const title =

{consultant.name}

; + return ( + consultant.imageThumbUrl && + consultant.name && + consultant.email && ( +
+
+ {consultant.name} +
+
+ {employeePageSlug !== undefined ? ( + + {title} + + ) : ( + title + )} + {consultant.officeName && ( +

{consultant.officeName}

+ )} + {consultant.email && ( +

{consultant.email}

+ )} + {consultant.telephone && ( +

{consultant.telephone}

+ )} + {employeePageSlug && ( + + )} +
+
+ ) + ); +} diff --git a/src/components/consultantCard/consultantCard.module.css b/src/components/consultantCard/consultantCard.module.css new file mode 100644 index 000000000..b9df285ca --- /dev/null +++ b/src/components/consultantCard/consultantCard.module.css @@ -0,0 +1,43 @@ +.consultant { + display: flex; + width: 100%; + gap: 1rem; +} + +.consultantImage { + display: flex; + flex-direction: column; + align-items: center; + background-color: var(--primary-black); + border-radius: 12px; + height: 125px; + width: 50%; + padding: 1rem; + position: relative; +} + +.consultantInfo { + display: flex; + flex-direction: column; + width: 50%; + gap: 0.5rem; +} + +.consultantName { + color: var(--primary-black); + font-size: 16px; + font-weight: 600; +} + +.consultantRole { + color: var(--primary-black); + font-size: 16px; + font-weight: 300; +} + +.consultantEmail, +.consultantTelephone { + color: var(--primary-black); + font-size: 14px; + font-weight: 300; +} diff --git a/src/components/customerCases/customerCase/CustomerCase.tsx b/src/components/customerCases/customerCase/CustomerCase.tsx index a1ae4e072..7e55c09d2 100644 --- a/src/components/customerCases/customerCase/CustomerCase.tsx +++ b/src/components/customerCases/customerCase/CustomerCase.tsx @@ -6,6 +6,7 @@ import { Delivery, } from "studioShared/lib/interfaces/customerCases"; +import ContactInformation from "./contactInformation/ContactInformation"; import styles from "./customerCase.module.css"; import FeaturedCases from "./featuredCases/FeaturedCases"; import CustomerCaseConsultants from "./sections/customerCaseConsultants/CustomerCaseConsultants"; @@ -129,6 +130,7 @@ export default async function CustomerCase({ customerCasesPath={customerCasesPagePath} /> )} + ); diff --git a/src/components/customerCases/customerCase/contactInformation/ContactInformation.tsx b/src/components/customerCases/customerCase/contactInformation/ContactInformation.tsx new file mode 100644 index 000000000..71651ad57 --- /dev/null +++ b/src/components/customerCases/customerCase/contactInformation/ContactInformation.tsx @@ -0,0 +1,75 @@ +import Text from "src/components/text/Text"; +import { fetchEmployeesByEmails } from "src/utils/employees"; +import { CompanyLocation } from "studio/lib/interfaces/companyDetails"; +import { COMPANY_LOCATIONS_QUERY } from "studio/lib/queries/admin"; +import { EMPLOYEE_PAGE_SLUG_QUERY } from "studio/lib/queries/siteSettings"; +import { loadStudioQuery } from "studio/lib/store"; + +import styles from "./contactInformation.module.css"; +import ContactSelector, { + ContactByLocationMap, +} from "./contactSelector/ContactSelector"; + +interface ContactInformationProps { + language: string; +} + +async function fetchContactByLocationMap( + companyLocations: CompanyLocation[], +): Promise { + const contactByLocation: ContactByLocationMap = {}; + for (const location of companyLocations) { + if ( + location.contactPerson === undefined || + location.contactPerson.length === 0 + ) { + continue; + } + const contactRes = await fetchEmployeesByEmails([location.contactPerson]); + if (!contactRes.ok || contactRes.value.length === 0) { + continue; + } + contactByLocation[location._id] = contactRes.value[0]; + } + return contactByLocation; +} + +export default async function ContactInformation({ + language, +}: ContactInformationProps) { + const employeePageSlug = ( + await loadStudioQuery<{ slug: string } | null>(EMPLOYEE_PAGE_SLUG_QUERY, { + language, + }) + ).data?.slug; + const companyLocations = ( + await loadStudioQuery(COMPANY_LOCATIONS_QUERY, {}) + ).data; + const contactByLocation = await fetchContactByLocationMap(companyLocations); + const locationIdsWithContact = Object.keys(contactByLocation); + const locationsWithContact = companyLocations.filter((location) => + locationIdsWithContact.includes(location._id), + ); + + return ( +
+
+
+ {/* TODO: translation */} + + Trenger du hjelp med lignende eller noe helt annet? + + Kontakt salg! +
+
+ +
+
+
+ ); +} diff --git a/src/components/customerCases/customerCase/contactInformation/contactInformation.module.css b/src/components/customerCases/customerCase/contactInformation/contactInformation.module.css new file mode 100644 index 000000000..e86f6bf9c --- /dev/null +++ b/src/components/customerCases/customerCase/contactInformation/contactInformation.module.css @@ -0,0 +1,32 @@ +.wrapper { + display: flex; + flex-direction: column; + margin: 4rem 0; + + @media (min-width: 1024px) { + align-items: center; + } +} + +.content { + display: flex; + flex-direction: row; + gap: 1rem; + max-width: 960px; + + @media (max-width: 1024px) { + flex-direction: column; + gap: 2rem; + } +} + +.titleSection { + display: flex; + flex-direction: column; + gap: 0.75rem; +} + +.contactSection { + display: flex; + gap: 1.5rem; +} diff --git a/src/components/customerCases/customerCase/contactInformation/contactSelector/ContactSelector.tsx b/src/components/customerCases/customerCase/contactInformation/contactSelector/ContactSelector.tsx new file mode 100644 index 000000000..479bb362e --- /dev/null +++ b/src/components/customerCases/customerCase/contactInformation/contactSelector/ContactSelector.tsx @@ -0,0 +1,68 @@ +"use client"; + +import { useState } from "react"; + +import Button from "src/components/buttons/Button"; +import ConsultantCard from "src/components/consultantCard/ConsultantCard"; +import { ChewbaccaEmployee } from "src/types/employees"; +import { CompanyLocation } from "studio/lib/interfaces/companyDetails"; + +import styles from "./contactSelector.module.css"; + +export type ContactByLocationMap = { + [locationId: string]: ChewbaccaEmployee; +}; + +export interface ContactSelectorProps { + language: string; + locations: CompanyLocation[]; + contactByLocation: ContactByLocationMap; + employeePageSlug?: string; +} + +export default function ContactSelector({ + language, + locations, + contactByLocation, + employeePageSlug, +}: ContactSelectorProps) { + const locationIds = Object.keys(contactByLocation); + + const [selectedLocationId, setSelectedLocationId] = useState( + locationIds.length === 0 ? locationIds[0] : null, + ); + + if (locationIds.length === 0) { + return; + } + + const selectedOrDefaultLocationId = selectedLocationId ?? locationIds[0]; + + return ( + <> +
+ {locations.map((location) => ( + + ))} +
+
+ +
+ + ); +} diff --git a/src/components/customerCases/customerCase/contactInformation/contactSelector/contactSelector.module.css b/src/components/customerCases/customerCase/contactInformation/contactSelector/contactSelector.module.css new file mode 100644 index 000000000..e0f2ce2ef --- /dev/null +++ b/src/components/customerCases/customerCase/contactInformation/contactSelector/contactSelector.module.css @@ -0,0 +1,9 @@ +.locationSection { + display: flex; + flex-direction: column; + gap: 0.75rem; +} + +.consultantSection { + min-width: 400px; +} diff --git a/src/components/customerCases/customerCase/sections/customerCaseConsultants/CustomerCaseConsultants.tsx b/src/components/customerCases/customerCase/sections/customerCaseConsultants/CustomerCaseConsultants.tsx index 385872e7d..ed91f8204 100644 --- a/src/components/customerCases/customerCase/sections/customerCaseConsultants/CustomerCaseConsultants.tsx +++ b/src/components/customerCases/customerCase/sections/customerCaseConsultants/CustomerCaseConsultants.tsx @@ -1,11 +1,6 @@ -import Image from "next/image"; -import Link from "next/link"; - -import CustomLink from "src/components/link/CustomLink"; +import ConsultantCard from "src/components/consultantCard/ConsultantCard"; import Text from "src/components/text/Text"; import { ChewbaccaEmployee } from "src/types/employees"; -import { aliasFromEmail } from "src/utils/employees"; -import { LinkType } from "studio/lib/interfaces/navigation"; import { EMPLOYEE_PAGE_SLUG_QUERY } from "studio/lib/queries/siteSettings"; import { loadStudioQuery } from "studio/lib/store"; @@ -32,63 +27,14 @@ export default async function CustomerCaseConsultants({
Varianter på prosjektet
- {consultants.map((consultant) => { - const title = ( -

{consultant.name}

- ); - return ( - consultant.imageThumbUrl && - consultant.name && - consultant.email && ( -
-
- {consultant.name} -
-
- {employeePageSlug !== undefined ? ( - - {title} - - ) : ( - title - )} - {consultant.officeName && ( -

- {consultant.officeName} -

- )} - {consultant.email && ( -

{consultant.email}

- )} - {consultant.telephone && ( -

- {consultant.telephone} -

- )} - -
-
- ) - ); - })} + {consultants.map((consultant) => ( + + ))}
); diff --git a/src/components/customerCases/customerCase/sections/customerCaseConsultants/customerCaseConsulants.module.css b/src/components/customerCases/customerCase/sections/customerCaseConsultants/customerCaseConsulants.module.css index 09d000704..0745727f4 100644 --- a/src/components/customerCases/customerCase/sections/customerCaseConsultants/customerCaseConsulants.module.css +++ b/src/components/customerCases/customerCase/sections/customerCaseConsultants/customerCaseConsulants.module.css @@ -14,47 +14,3 @@ grid-template-columns: repeat(auto-fit, 350px); justify-content: space-between; } - -.consultant { - display: flex; - width: 100%; - gap: 1rem; -} - -.consultantImage { - display: flex; - flex-direction: column; - align-items: center; - background-color: var(--primary-black); - border-radius: 12px; - height: 125px; - width: 50%; - padding: 1rem; - position: relative; -} - -.consultantInfo { - display: flex; - flex-direction: column; - width: 50%; - gap: 0.5rem; -} - -.consultantName { - color: var(--primary-black); - font-size: 16px; - font-weight: 600; -} - -.consultantRole { - color: var(--primary-black); - font-size: 16px; - font-weight: 300; -} - -.consultantEmail, -.consultantTelephone { - color: var(--primary-black); - font-size: 14px; - font-weight: 300; -} diff --git a/src/components/text/text.module.css b/src/components/text/text.module.css index ea365fbd9..d30fe116c 100644 --- a/src/components/text/text.module.css +++ b/src/components/text/text.module.css @@ -73,7 +73,7 @@ .bodyNormal { font-size: 20px; - font-weight: 400; + font-weight: 300; } .bodySmall { diff --git a/src/styles/global.css b/src/styles/global.css index d20a2e753..e266074ff 100644 --- a/src/styles/global.css +++ b/src/styles/global.css @@ -18,6 +18,7 @@ html { --primary-white-bright: #ffffff; --primary-white: #faf8f5; --primary-black: #2d2d2d; + --primary-black-darker: #000000; --secondary-off-white1: #f4efe8; --secondary-off-white2: #ece1d3; diff --git a/studio/lib/interfaces/companyDetails.ts b/studio/lib/interfaces/companyDetails.ts index 81dec6502..5cd64b12c 100644 --- a/studio/lib/interfaces/companyDetails.ts +++ b/studio/lib/interfaces/companyDetails.ts @@ -10,4 +10,5 @@ export interface CompanyLocation { _id: string; _updatedAt: string; companyLocationName: string; + contactPerson?: string; } diff --git a/studio/schemas/documents/admin/companyLocation.ts b/studio/schemas/documents/admin/companyLocation.ts index f2bad4951..04ee26a6b 100644 --- a/studio/schemas/documents/admin/companyLocation.ts +++ b/studio/schemas/documents/admin/companyLocation.ts @@ -4,6 +4,7 @@ import { StringInputWithCharacterCount } from "studio/components/stringInputWith export const companyLocationID = "companyLocation"; export const companyLocationNameID = "companyLocationName"; +export const companyLocationContactPersonID = "contactPerson"; const companyLocation = defineType({ name: companyLocationID, @@ -21,6 +22,12 @@ const companyLocation = defineType({ StringInputWithCharacterCount({ ...props, maxCount: 50 }), }, }), + defineField({ + name: companyLocationContactPersonID, + type: "email", + title: "Contact person for Sales", + description: "Add the email of the contact person for Sales", + }), ], });