Skip to content

Commit

Permalink
feat(i18n): format currency based on Sanity locale fields
Browse files Browse the repository at this point in the history
  • Loading branch information
mathiazom committed Sep 18, 2024
1 parent 6cd173d commit 6a7ced0
Show file tree
Hide file tree
Showing 12 changed files with 198 additions and 8 deletions.
6 changes: 6 additions & 0 deletions src/app/(main)/[slug]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@ import SectionRenderer from "src/utils/renderSection";
import { fetchSeoData, generateMetadataFromSeo } from "src/utils/seo";
import { CompanyLocation } from "studio/lib/interfaces/companyDetails";
import { CompensationsPage } from "studio/lib/interfaces/compensations";
import { LocaleDocument } from "studio/lib/interfaces/locale";
import { BlogPage, PageBuilder, Post } from "studio/lib/interfaces/pages";
import { COMPANY_LOCATIONS_QUERY } from "studio/lib/queries/companyDetails";
import { LOCALE_QUERY } from "studio/lib/queries/locale";
import {
BLOG_PAGE_QUERY,
COMPENSATIONS_PAGE_QUERY,
Expand Down Expand Up @@ -53,6 +55,7 @@ async function Page({ params }: Props) {
initialBlogPage,
initialCompensationsPage,
initialLocationsData,
initialLocale,
] = await Promise.all([
loadQuery<PageBuilder>(SLUG_QUERY, { slug }, { perspective }),
loadQuery<BlogPage>(BLOG_PAGE_QUERY, { slug }, { perspective }),
Expand All @@ -62,6 +65,7 @@ async function Page({ params }: Props) {
{ perspective },
),
loadQuery<CompanyLocation[]>(COMPANY_LOCATIONS_QUERY, {}, { perspective }),
loadQuery<LocaleDocument>(LOCALE_QUERY, {}, { perspective }),
]);

if (initialPage.data) {
Expand Down Expand Up @@ -112,11 +116,13 @@ async function Page({ params }: Props) {
<CompensationsPreview
initialCompensations={initialCompensationsPage}
initialLocations={initialLocationsData}
initialLocale={initialLocale}
/>
) : (
<Compensations
compensations={initialCompensationsPage.data}
locations={initialLocationsData.data}
locale={initialLocale.data}
/>
);
}
Expand Down
23 changes: 19 additions & 4 deletions src/compensations/Compensations.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -26,14 +28,19 @@ import {
interface CompensationsProps {
compensations: CompensationsPage;
locations: CompanyLocation[];
locale: LocaleDocument;
}

interface SalaryCalculatorFormState {
examinationYear: number;
selectedDegree: Degree;
}

const Compensations = ({ compensations, locations }: CompensationsProps) => {
const Compensations = ({
compensations,
locations,
locale,
}: CompensationsProps) => {
const [selectedLocation, setSelectedLocation] = useState<string>(
locations[0]._id,
);
Expand Down Expand Up @@ -121,19 +128,27 @@ const Compensations = ({ compensations, locations }: CompensationsProps) => {
/>
{salary !== null ? (
<div aria-live="polite">
<Text> Du vil få en årlig lønn på {salary}</Text>
<Text>
{" "}
Du vil få en årlig lønn på{" "}
{formatAsCurrency(salary, locale.locale, locale.currency)}
</Text>
{compensations.pensionPercent && (
<Text>
Du vil få en årlig pensjon på omtrent{" "}
{calculatePension(salary, compensations.pensionPercent)}
{formatAsCurrency(
calculatePension(salary, compensations.pensionPercent),
locale.locale,
locale.currency,
)}
</Text>
)}
</div>
) : null}
</>
)}
{yearlyBonusesForLocation && (
<YearlyBonuses bonuses={yearlyBonusesForLocation} />
<YearlyBonuses bonuses={yearlyBonusesForLocation} locale={locale} />
)}
<BenefitsByLocation benefits={benefitsFilteredByLocation} />
</div>
Expand Down
17 changes: 15 additions & 2 deletions src/compensations/CompensationsPreview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,23 @@ 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/companyDetails";
import { LOCALE_QUERY } from "studio/lib/queries/locale";
import { COMPENSATIONS_PAGE_QUERY } from "studio/lib/queries/pages";

import Compensations from "./Compensations";

interface CompensationsPreviewProps {
initialCompensations: QueryResponseInitial<CompensationsPage>;
initialLocations: QueryResponseInitial<CompanyLocation[]>;
initialLocale: QueryResponseInitial<LocaleDocument>;
}

const CompensationsPreview = ({
initialCompensations,
initialLocations,
initialLocale,
}: CompensationsPreviewProps) => {
const { data } = useQuery<CompensationsPage>(
COMPENSATIONS_PAGE_QUERY,
Expand All @@ -29,10 +33,19 @@ const CompensationsPreview = ({
{ initial: initialLocations },
);

const { data: locale } = useQuery<LocaleDocument>(LOCALE_QUERY, {
initial: initialLocale,
});

return (
locationData && (
locationData &&
locale && (
<Suspense>
<Compensations compensations={data} locations={locationData} />
<Compensations
compensations={data}
locations={locationData}
locale={locale}
/>
</Suspense>
)
);
Expand Down
13 changes: 11 additions & 2 deletions src/compensations/components/yearlyBonuses/YearlyBonuses.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<div className={styles.wrapper}>
<Text type={"h3"}>Historisk bonus</Text>
Expand All @@ -31,7 +34,13 @@ const YearlyBonuses = ({ bonuses }: YearlyBonusesProps) => {
<Text type={"small"}>{bonus.year}</Text>
</th>
<td className={styles.bonusCell}>
<Text type={"small"}>{bonus.bonus}</Text>
<Text type={"small"}>
{formatAsCurrency(
bonus.bonus,
locale.locale,
locale.currency,
)}
</Text>
</td>
</tr>
))}
Expand Down
9 changes: 9 additions & 0 deletions src/utils/i18n.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export function formatAsCurrency(
number: number,
locale: string,
currency: string,
) {
return new Intl.NumberFormat(locale, { style: "currency", currency }).format(
number,
);
}
4 changes: 4 additions & 0 deletions studio/lib/interfaces/locale.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export interface LocaleDocument {
locale: string;
currency: string;
}
5 changes: 5 additions & 0 deletions studio/lib/queries/locale.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { groq } from "next-sanity";

import { localeID } from "studio/schemas/documents/locale";

export const LOCALE_QUERY = groq`*[_type == "${localeID}" && _id == "${localeID}"][0]`;
2 changes: 2 additions & 0 deletions studio/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import companyInfo from "./schemas/documents/companyInfo";
import companyLocation from "./schemas/documents/companyLocation";
import compensations from "./schemas/documents/compensations";
import legalDocument from "./schemas/documents/legalDocuments";
import locale from "./schemas/documents/locale";
import navigationManager from "./schemas/documents/navigationManager";
import posts from "./schemas/documents/post";
import redirect from "./schemas/documents/redirect";
Expand Down Expand Up @@ -41,5 +42,6 @@ export const schema: { types: SchemaTypeDefinition[] } = {
supportedLanguages,
defaultSeo,
brandAssets,
locale,
],
};
11 changes: 11 additions & 0 deletions studio/schemas/deskStructure.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {
CaseIcon,
CogIcon,
DoubleChevronRightIcon,
EarthGlobeIcon,
HeartIcon,
ImagesIcon,
InfoOutlineIcon,
Expand All @@ -23,6 +24,7 @@ import { companyInfoID } from "./documents/companyInfo";
import { companyLocationID } from "./documents/companyLocation";
import { compensationsId } from "./documents/compensations";
import { legalDocumentID } from "./documents/legalDocuments";
import { localeID } from "./documents/locale";
import { redirectId } from "./documents/redirect";
import { soMeLinksID } from "./documents/socialMediaProfiles";
import { supportedLanguagesID } from "./documents/supportedLanguages";
Expand Down Expand Up @@ -102,6 +104,15 @@ const siteSettingSection = (S: StructureBuilder) =>
.documentId(supportedLanguagesID)
.title("Supported Languages"),
),
S.listItem()
.title("Locale")
.icon(EarthGlobeIcon)
.child(
S.document()
.schemaType(localeID)
.documentId(localeID)
.title("Locale"),
),
S.listItem()
.title("Default SEO")
.icon(SearchIcon)
Expand Down
41 changes: 41 additions & 0 deletions studio/schemas/documents/locale.ts
Original file line number Diff line number Diff line change
@@ -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: "Locale",
description: "Select the most relevant locale 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;
36 changes: 36 additions & 0 deletions studio/utils/currencies.ts
Original file line number Diff line number Diff line change
@@ -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",
},
];
39 changes: 39 additions & 0 deletions studio/utils/locales.ts
Original file line number Diff line number Diff line change
@@ -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",
},
];

0 comments on commit 6a7ced0

Please sign in to comment.