Skip to content

Commit

Permalink
feat: add salary calculator based on legacy site
Browse files Browse the repository at this point in the history
Co-authored-by: Ane <[email protected]>
  • Loading branch information
mathiazom and anemne committed Aug 23, 2024
1 parent 6be8e37 commit 094e510
Show file tree
Hide file tree
Showing 9 changed files with 229 additions and 8 deletions.
8 changes: 7 additions & 1 deletion src/components/forms/inputField/InputField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@ interface InputFieldProps {
autoComplete?: HTMLInputAutoCompleteAttribute;
autoCorrect?: string;
type?: HTMLInputTypeAttribute;
max?: number;
min?: number;
spellCheck?: "true" | "false";
autoCapitalize?: string;
value: string;
value: string | number;
onChange: (name: string, value: string) => void;
required?: boolean;
}
Expand All @@ -24,6 +26,8 @@ const InputField = ({
autoComplete,
autoCorrect = "off",
type = "text",
max,
min,
spellCheck,
autoCapitalize,
value,
Expand Down Expand Up @@ -56,6 +60,8 @@ const InputField = ({
autoComplete={autoComplete}
autoCorrect={autoCorrect}
type={type}
max={max}
min={min}
className={styles.input}
spellCheck={spellCheck}
value={value}
Expand Down
14 changes: 7 additions & 7 deletions src/components/forms/radioButtonGroup/RadioButtonGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ import styles from "src/components/forms/radioButtonGroup/radioButtonGroup.modul
import { RadioButton } from "./components/RadioButton";
import textStyles from "src/components/text/text.module.css";

interface IOption {
export interface IOption {
id: string;
label: string;
disabled: boolean;
currentChecked: boolean;
disabled?: boolean;
currentSelected: boolean;
}

interface RenderOptionsProps {
Expand Down Expand Up @@ -41,8 +41,8 @@ interface RadioButtonGroupProps {
*
* ```
* const options = [
* { id: 'radio1', label: 'Option 1', value: '1', currentChecked: false },
* { id: 'radio2', label: 'Option 2', value: '2', currentChecked: true },
* { id: 'radio1', label: 'Option 1', value: '1', currentSelected: false },
* { id: 'radio2', label: 'Option 2', value: '2', currentSelected: true },
* ];
*
* <RadioButtonGroup
Expand Down Expand Up @@ -82,15 +82,15 @@ export const RadioButtonGroup = ({
const RenderOptions = ({ options, onChange }: RenderOptionsProps) => {
return (
<>
{options.map(({ id, label, disabled, currentChecked }) => (
{options.map(({ id, label, disabled, currentSelected }) => (
<RadioButton
key={id}
id={id}
label={label}
name="radio"
disabled={disabled}
value={label}
defaultChecked={currentChecked}
defaultChecked={currentSelected}
onChange={onChange}
/>
))}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
.fieldset{
border: 0 none;
padding: 0;
}

.wrapper {
Expand Down
70 changes: 70 additions & 0 deletions src/salaryAndBenefits/SalaryAndBenefits.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,86 @@
"use client";

import styles from "./salaryAndBenefits.module.css";
import Text from "src/components/text/Text";
import { SalaryAndBenefitsPage } from "studio/lib/payloads/salaryAndBenefits";
import { RichText } from "src/components/richText/RichText";
import SalaryCalculator, {
Degree,
} from "./components/salaryCalculator/SalaryCalculator";
import { useState } from "react";
import {
calculatePension,
calculateSalary,
maxExperience,
} from "./utils/calculateSalary";

interface SalaryAndBenefitsProps {
salaryAndBenefits: SalaryAndBenefitsPage;
}

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

const SalaryAndBenefits = ({ salaryAndBenefits }: SalaryAndBenefitsProps) => {
const currentYear = new Date().getFullYear();
const minExaminationYear = maxExperience(currentYear);
const maxExaminationYear = currentYear - 1;

const [formState, setFormState] = useState<SalaryCalculatorFormState>({
examinationYear: currentYear - 1,
selectedDegree: "bachelor",
});
const [salary, setSalary] = useState<number | null>(null);

const updateSelectedDegree = (newDegree: Degree) => {
setFormState((prevState) => ({
...prevState,
selectedDegree: newDegree,
}));
};

const updateExaminationYear = (newYear: number) => {
setFormState((prevState) => ({
...prevState,
examinationYear: newYear,
}));
};

const handleSubmit = (event: React.FormEvent) => {
event.preventDefault();
setSalary(
calculateSalary(
currentYear,
formState.examinationYear,
formState.selectedDegree,
),
);
};

return (
<div className={styles.wrapper}>
<Text type="h1">{salaryAndBenefits.basicTitle}</Text>
{salaryAndBenefits.showSalaryCalculator && (
<SalaryCalculator
// TODO: should also take in degree state (this requires changes to IOption of RadioButtonGroup)
examinationYear={formState.examinationYear}
minExaminationYear={minExaminationYear}
maxExaminationYear={maxExaminationYear}
onDegreeChanged={updateSelectedDegree}
onExaminationYearChanged={updateExaminationYear}
onSubmit={handleSubmit}
/>
)}
{salary !== null ? (
<div aria-live="polite">
<Text> Du vil få en årlig lønn på {salary}</Text>
<Text>
Du vil få en årlig pensjon på omtrent {calculatePension(salary)}
</Text>
</div>
) : null}
<div className={styles.benefits}>
{salaryAndBenefits.benefits.map((benefit) => (
<div key={benefit._key} className={styles.benefitWrapper}>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import styles from "./salaryCalculator.module.css";
import InputField from "src/components/forms/inputField/InputField";
import {
IOption,
RadioButtonGroup,
} from "src/components/forms/radioButtonGroup/RadioButtonGroup";
import Button from "src/components/buttons/Button";

export type Degree = "bachelor" | "master";

const degreeOptions: IOption[] = [
{
id: "bachelor",
label: "Bachelor",
currentSelected: true,
disabled: false,
},
{ id: "master", label: "Master", currentSelected: false, disabled: false },
];

interface SalaryCalculatorProps {
examinationYear: number;
minExaminationYear: number;
maxExaminationYear: number;
onDegreeChanged: (degree: Degree) => void;
onExaminationYearChanged: (examinationYear: number) => void;
onSubmit: (event: React.FormEvent) => void;
}

export default function SalaryCalculator({
examinationYear,
minExaminationYear,
maxExaminationYear,
onDegreeChanged,
onExaminationYearChanged,
onSubmit,
}: SalaryCalculatorProps) {
return (
<form
aria-label="salary calculator"
className={styles.calculator}
onSubmit={onSubmit}
>
<RadioButtonGroup
id="degree-group"
label="Choose your degree"
options={degreeOptions}
onValueChange={(value) =>
(value.id === "bachelor" || value.id === "master") &&
onDegreeChanged(value.id)
}
/>
<InputField
label="year"
name="examinationYear"
type="number"
max={maxExaminationYear}
min={minExaminationYear}
value={examinationYear}
onChange={(_name, value) => onExaminationYearChanged(parseInt(value))}
required
/>
<Button type="secondary" size="small">
Submit
</Button>
</form>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.calculator{
display: flex;
flex-direction: column;
gap: 2rem;
}
29 changes: 29 additions & 0 deletions src/salaryAndBenefits/utils/calculateSalary.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { payscale } from "./salaryData";

interface PayScale {
[year: number]: {
[examinationYear: number]: number;
};
}

const salaryPayscale: PayScale = payscale;

export function calculateSalary(
currentYear: number,
examinationYear: number,
degree: string
): number {

const degreeValue = degree === "bachelor" ? 1 : 0;
const adjustedYear = (examinationYear + degreeValue);
return salaryPayscale[currentYear][adjustedYear];
}

export function calculatePension(salary: number): number {
return Math.round(salary * 0.07);
}

export function maxExperience(thisYear: number): number {
const years = Object.keys(salaryPayscale[thisYear]).map(Number)
return Math.min(...years);
}
41 changes: 41 additions & 0 deletions src/salaryAndBenefits/utils/salaryData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
export const payscale = {
2024: {
2024 : 600000,
2023 : 635833,
2022 : 681829,
2021 : 734982,
2020 : 789982,
2019 : 838539,
2018 : 879553,
2017 : 916886,
2016 : 949000,
2015 : 977333,
2014 : 1005324,
2013 : 1031405,
2012 : 1064738,
2011 : 1091489,
2010 : 1113742,
2009 : 1138742,
2008 : 1166667,
2007 : 1192460,
2006 : 1210126,
2005 : 1233560,
2004 : 1264767,
2003 : 1289780,
2002 : 1299680,
2001 : 1295953,
2000 : 1305501,
1999 : 1328501,
1998 : 1349349,
1997 : 1365121,
1996 : 1384832,
1995 : 1399711,
1994 : 1422069,
1993 : 1429358,
1992 : 1452891,
1991 : 1458021,
1990 : 1467321,
1989 : 1484721
}
} ;

1 change: 1 addition & 0 deletions studio/lib/payloads/salaryAndBenefits.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,5 @@ export interface SalaryAndBenefitsPage {
page: string;
slug: Slug;
benefits: Benefit[];
showSalaryCalculator: boolean;
}

0 comments on commit 094e510

Please sign in to comment.