diff --git a/src/app/(main)/[lang]/[slug]/page.tsx b/src/app/(main)/[lang]/[slug]/page.tsx index 83611c4d2..854309b26 100644 --- a/src/app/(main)/[lang]/[slug]/page.tsx +++ b/src/app/(main)/[lang]/[slug]/page.tsx @@ -16,12 +16,14 @@ import { fetchSeoData, generateMetadataFromSeo } from "src/utils/seo"; import { CompanyLocation } from "studio/lib/interfaces/companyDetails"; import { CompensationsPage } from "studio/lib/interfaces/compensations"; import { LegalDocument } from "studio/lib/interfaces/legalDocuments"; +import { LocaleDocument } from "studio/lib/interfaces/locale"; import { BlogPage, PageBuilder, Post } from "studio/lib/interfaces/pages"; import { CustomerCasePage } from "studio/lib/interfaces/specialPages"; import { COMPANY_LOCATIONS_QUERY, LEGAL_DOCUMENTS_BY_SLUG_AND_LANG_QUERY, } from "studio/lib/queries/admin"; +import { LOCALE_QUERY } from "studio/lib/queries/locale"; import { BLOG_PAGE_QUERY, POSTS_QUERY, @@ -66,6 +68,7 @@ async function Page({ params }: Props) { initialLocationsData, initialCustomerCases, initialLegalDocument, + initialLocale, ] = await Promise.all([ loadStudioQuery(SLUG_QUERY, { slug }, { perspective }), loadStudioQuery(BLOG_PAGE_QUERY, { slug }, { perspective }), @@ -89,6 +92,7 @@ async function Page({ params }: Props) { { slug, language: lang }, { perspective }, ), + loadStudioQuery(LOCALE_QUERY, {}, { perspective }), ]); if (initialPage.data) { @@ -139,11 +143,13 @@ async function Page({ params }: Props) { ) : ( ); } diff --git a/src/compensations/Compensations.tsx b/src/compensations/Compensations.tsx index b41ae3fd4..d018d1d87 100644 --- a/src/compensations/Compensations.tsx +++ b/src/compensations/Compensations.tsx @@ -6,8 +6,10 @@ import { RadioButtonGroup, } from "src/components/forms/radioButtonGroup/RadioButtonGroup"; import Text from "src/components/text/Text"; +import { formatAsCurrency } from "src/utils/i18n"; import { CompanyLocation } from "studio/lib/interfaces/companyDetails"; import { CompensationsPage } from "studio/lib/interfaces/compensations"; +import { LocaleDocument } from "studio/lib/interfaces/locale"; import styles from "./compensations.module.css"; import BenefitsByLocation from "./components/benefitsByLocation/BenefitsByLocation"; @@ -26,6 +28,7 @@ import { interface CompensationsProps { compensations: CompensationsPage; locations: CompanyLocation[]; + locale: LocaleDocument; } interface SalaryCalculatorFormState { @@ -33,7 +36,11 @@ interface SalaryCalculatorFormState { selectedDegree: Degree; } -const Compensations = ({ compensations, locations }: CompensationsProps) => { +const Compensations = ({ + compensations, + locations, + locale, +}: CompensationsProps) => { const [selectedLocation, setSelectedLocation] = useState( locations[0]._id, ); @@ -121,11 +128,17 @@ const Compensations = ({ compensations, locations }: CompensationsProps) => { /> {salary !== null ? (
- Du vil få en årlig lønn på {salary} + + {`Du vil få en årlig lønn på ${formatAsCurrency(salary, locale.locale, locale.currency)}`} + {compensations.pensionPercent && ( Du vil få en årlig pensjon på omtrent{" "} - {calculatePension(salary, compensations.pensionPercent)} + {formatAsCurrency( + calculatePension(salary, compensations.pensionPercent), + locale.locale, + locale.currency, + )} )}
@@ -133,7 +146,7 @@ const Compensations = ({ compensations, locations }: CompensationsProps) => { )} {yearlyBonusesForLocation && ( - + )} diff --git a/src/compensations/CompensationsPreview.tsx b/src/compensations/CompensationsPreview.tsx index 872a1534f..0c49ad5c9 100644 --- a/src/compensations/CompensationsPreview.tsx +++ b/src/compensations/CompensationsPreview.tsx @@ -5,7 +5,9 @@ import { Suspense } from "react"; import { CompanyLocation } from "studio/lib/interfaces/companyDetails"; import { CompensationsPage } from "studio/lib/interfaces/compensations"; +import { LocaleDocument } from "studio/lib/interfaces/locale"; import { COMPANY_LOCATIONS_QUERY } from "studio/lib/queries/admin"; +import { LOCALE_QUERY } from "studio/lib/queries/locale"; import { COMPENSATIONS_PAGE_QUERY } from "studio/lib/queries/specialPages"; import Compensations from "./Compensations"; @@ -13,11 +15,13 @@ import Compensations from "./Compensations"; interface CompensationsPreviewProps { initialCompensations: QueryResponseInitial; initialLocations: QueryResponseInitial; + initialLocale: QueryResponseInitial; } const CompensationsPreview = ({ initialCompensations, initialLocations, + initialLocale, }: CompensationsPreviewProps) => { const { data: compensationsData } = useQuery( COMPENSATIONS_PAGE_QUERY, @@ -30,16 +34,22 @@ const CompensationsPreview = ({ { initial: initialLocations }, ); + const { data: locale } = useQuery(LOCALE_QUERY, { + initial: initialLocale, + }); + compensationsData.salariesByLocation = stegaClean( compensationsData.salariesByLocation, ); return ( - locationData && ( + locationData && + locale && ( ) diff --git a/src/compensations/components/yearlyBonuses/YearlyBonuses.tsx b/src/compensations/components/yearlyBonuses/YearlyBonuses.tsx index f00680b27..b91e75a3e 100644 --- a/src/compensations/components/yearlyBonuses/YearlyBonuses.tsx +++ b/src/compensations/components/yearlyBonuses/YearlyBonuses.tsx @@ -1,13 +1,16 @@ import Text from "src/components/text/Text"; +import { formatAsCurrency } from "src/utils/i18n"; import { BonusPage } from "studio/lib/interfaces/compensations"; +import { LocaleDocument } from "studio/lib/interfaces/locale"; import styles from "./yearlyBonuses.module.css"; interface YearlyBonusesProps { bonuses: BonusPage[]; + locale: LocaleDocument; } -const YearlyBonuses = ({ bonuses }: YearlyBonusesProps) => { +const YearlyBonuses = ({ bonuses, locale }: YearlyBonusesProps) => { return (
Historisk bonus @@ -31,7 +34,13 @@ const YearlyBonuses = ({ bonuses }: YearlyBonusesProps) => { {bonus.year} - {bonus.bonus} + + {formatAsCurrency( + bonus.bonus, + locale.locale, + locale.currency, + )} + ))} diff --git a/src/utils/i18n.ts b/src/utils/i18n.ts new file mode 100644 index 000000000..68a2d62e4 --- /dev/null +++ b/src/utils/i18n.ts @@ -0,0 +1,9 @@ +export function formatAsCurrency( + number: number, + locale: string, + currency: string, +) { + return new Intl.NumberFormat(locale, { style: "currency", currency }).format( + number, + ); +} diff --git a/studio/deskStructure.ts b/studio/deskStructure.ts index 7361593c5..a72c47273 100644 --- a/studio/deskStructure.ts +++ b/studio/deskStructure.ts @@ -2,6 +2,7 @@ import { CaseIcon, CogIcon, DoubleChevronRightIcon, + EarthGlobeIcon, HeartIcon, ImagesIcon, InfoOutlineIcon, @@ -24,6 +25,7 @@ import { languageSettingsID } from "./schemas/documents/languageSettings"; import { pageBuilderID } from "./schemas/documents/pageBuilder"; import { brandAssetsID } from "./schemas/documents/siteSettings/brandAssets"; import { brokenLinkID } from "./schemas/documents/siteSettings/brokenLink"; +import { localeID } from "./schemas/documents/siteSettings/locale"; import { soMeLinksID } from "./schemas/documents/siteSettings/socialMediaProfiles"; import { customerCasesPageID } from "./schemas/documents/specialPages/customerCasesPage"; @@ -102,6 +104,15 @@ const siteSettingSection = (S: StructureBuilder) => .documentId(languageSettingsID) .title("Languages"), ), + S.listItem() + .title("Region") + .icon(EarthGlobeIcon) + .child( + S.document() + .schemaType(localeID) + .documentId(localeID) + .title("Region"), + ), S.listItem() .title("Default SEO") .icon(SearchIcon) diff --git a/studio/lib/interfaces/locale.ts b/studio/lib/interfaces/locale.ts new file mode 100644 index 000000000..1a66c8902 --- /dev/null +++ b/studio/lib/interfaces/locale.ts @@ -0,0 +1,4 @@ +export interface LocaleDocument { + locale: string; + currency: string; +} diff --git a/studio/lib/queries/locale.ts b/studio/lib/queries/locale.ts new file mode 100644 index 000000000..2c4186973 --- /dev/null +++ b/studio/lib/queries/locale.ts @@ -0,0 +1,5 @@ +import { groq } from "next-sanity"; + +import { localeID } from "studio/schemas/documents/siteSettings/locale"; + +export const LOCALE_QUERY = groq`*[_type == "${localeID}" && _id == "${localeID}"][0]`; diff --git a/studio/schema.ts b/studio/schema.ts index 1481719a2..b662c4053 100644 --- a/studio/schema.ts +++ b/studio/schema.ts @@ -11,6 +11,7 @@ import pageBuilder from "./schemas/documents/pageBuilder"; import posts from "./schemas/documents/post"; import brandAssets from "./schemas/documents/siteSettings/brandAssets"; import brokenLink from "./schemas/documents/siteSettings/brokenLink"; +import locale from "./schemas/documents/siteSettings/locale"; import navigationManager from "./schemas/documents/siteSettings/navigationManager"; import socialMediaLinks from "./schemas/documents/siteSettings/socialMediaProfiles"; import customerCasesPage from "./schemas/documents/specialPages/customerCasesPage"; @@ -43,5 +44,6 @@ export const schema: { types: SchemaTypeDefinition[] } = { defaultSeo, brandAssets, languageSettings, + locale, ], }; diff --git a/studio/schemas/documents/siteSettings/locale.ts b/studio/schemas/documents/siteSettings/locale.ts new file mode 100644 index 000000000..23cf2e96f --- /dev/null +++ b/studio/schemas/documents/siteSettings/locale.ts @@ -0,0 +1,41 @@ +import { defineField, defineType } from "sanity"; + +import { relevantCurrencies } from "studio/utils/currencies"; +import { relevantLocales } from "studio/utils/locales"; + +export const localeID = "locale"; + +const locale = defineType({ + name: localeID, + type: "document", + fields: [ + defineField({ + name: "locale", + type: "string", + title: "Region", + description: "Select the most relevant region for the website.", + initialValue: relevantLocales[0].code, + options: { + list: relevantLocales.map(({ title, code }) => ({ + title: `${title} (${code})`, + value: code, + })), + }, + }), + defineField({ + name: "currency", + type: "string", + title: "Currency", + description: "Select the most relevant currency for the website.", + initialValue: relevantCurrencies[0].code, + options: { + list: relevantCurrencies.map(({ title, code }) => ({ + title: `${title} (${code})`, + value: code, + })), + }, + }), + ], +}); + +export default locale; diff --git a/studio/utils/currencies.ts b/studio/utils/currencies.ts new file mode 100644 index 000000000..52ec48253 --- /dev/null +++ b/studio/utils/currencies.ts @@ -0,0 +1,36 @@ +interface Currency { + title: string; + code: string; +} + +// ISO 4217 currency codes (https://en.wikipedia.org/wiki/ISO_4217#List_of_ISO_4217_currency_codes) +export const relevantCurrencies: Currency[] = [ + { + title: "🇳🇴 Norwegian Krone", + code: "NOK", + }, + { + title: "🇸🇪 Swedish Krona", + code: "SEK", + }, + { + title: "🇪🇺 Euro", + code: "EUR", + }, + { + title: "🇬🇧 British Pound", + code: "GBP", + }, + { + title: "🇺🇸 US Dollar", + code: "USD", + }, + { + title: "🇩🇰 Danish Krone", + code: "DKK", + }, + { + title: "🇮🇸 Icelandic Króna", + code: "ISK", + }, +]; diff --git a/studio/utils/locales.ts b/studio/utils/locales.ts new file mode 100644 index 000000000..409cc512d --- /dev/null +++ b/studio/utils/locales.ts @@ -0,0 +1,39 @@ +interface Locale { + title: string; + code: string; +} + +export const relevantLocales: Locale[] = [ + { + title: "🇳🇴 Norway", + code: "nb-NO", + }, + // { + // title: "🇳🇴 Norway", + // code: "nn-NO", + // }, + { + title: "🇸🇪 Sweden", + code: "sv-SE", + }, + { + title: "🇬🇧 United Kingdom", + code: "en-GB", + }, + { + title: "🇺🇸 United States", + code: "en-US", + }, + { + title: "🇩🇰 Denmark", + code: "da-DK", + }, + { + title: "🇫🇮 Finland", + code: "fi-FI", + }, + { + title: "🇮🇸 Iceland", + code: "is-IS", + }, +];