Skip to content

Commit

Permalink
Add various fields for the calculator
Browse files Browse the repository at this point in the history
  • Loading branch information
pookmish committed May 3, 2024
1 parent 2f2567d commit d7dbd1d
Show file tree
Hide file tree
Showing 5 changed files with 236 additions and 105 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {HtmlHTMLAttributes} from "react";
import {ParagraphSumCalculator} from "@lib/gql/__generated__/drupal.d";
import SumCalculator from "@components/paragraphs/sum-calculator/sum-calculator";
import Wysiwyg from "@components/elements/wysiwyg";

type Props = HtmlHTMLAttributes<HTMLDivElement> & {
paragraph: ParagraphSumCalculator
Expand All @@ -13,14 +14,13 @@ const SumCalculatorParagraph = ({paragraph, ...props}: Props) => {
costPerStudentType.set("highschool", new Map(paragraph.sumCalcHighUnitCost.map(cost => [cost.first as number, cost.second as number])))
costPerStudentType.set("graduate", new Map(paragraph.sumCalcGradUnitCost.map(cost => [cost.first as number, cost.second as number])))

const appCosts =new Map(paragraph.sumCalcAppFee.map(item => [item.first as string, item.second as number]));
const progCosts =new Map(paragraph.sumCalcProgFee.map(item => [item.first as string, item.second as number]));
const housingCosts =new Map(paragraph.sumCalcHouseFees.map(item => [item.first as string, item.second as number]));
const progCosts = new Map(paragraph.sumCalcProgFee.map(item => [item.first as string, item.second as number]));
const housingCosts = new Map(paragraph.sumCalcHouseFees.map(item => [item.first as string, item.second as number]));

return (
<SumCalculator
costPerStudentTypes={costPerStudentType}
appCosts={appCosts}
appCost={paragraph.sumCalcAppFee}
progCosts={progCosts}
i20Cost={paragraph.sumCalcI20Fee}
housingCosts={housingCosts}
Expand All @@ -31,6 +31,17 @@ const SumCalculatorParagraph = ({paragraph, ...props}: Props) => {
booksSuppliesCost={paragraph.sumCalcBooks}
healthServiceCost={paragraph.sumCalcHealthFee}
documentsCost={paragraph.sumCalcDocuments}
commuterHelp={<Wysiwyg html={paragraph.sumCalcCommuteHelp?.processed}/>}
graduateApplicationHelp={<Wysiwyg html={paragraph.sumCalcGradAppHelp?.processed}/>}
graduateUnitsHelp={<Wysiwyg html={paragraph.sumCalcGradUnitHelp?.processed}/>}
highSchoolAppHelp={<Wysiwyg html={paragraph.sumCalcHighAppHelp?.processed}/>}
highSchoolUnitHelp={<Wysiwyg html={paragraph.sumCalcHighUnitHelp?.processed}/>}
onCampusHousingHelp={<Wysiwyg html={paragraph.sumCalcHouseHelp?.processed}/>}
i20Help={<Wysiwyg html={paragraph.sumCalcI20Help?.processed}/>}
insuranceHelp={<Wysiwyg html={paragraph.sumCalcInsHelp?.processed}/>}
wavedInsuranceHelp={<Wysiwyg html={paragraph.sumCalcInsWaveHelp?.processed}/>}
undergradAppHelp={<Wysiwyg html={paragraph.sumCalcUgAppHelp?.processed}/>}
undergradUnitsHelp={<Wysiwyg html={paragraph.sumCalcUgUnitHelp?.processed}/>}
{...props}
/>
)
Expand Down
196 changes: 116 additions & 80 deletions src/components/paragraphs/sum-calculator/sum-calculator.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
"use client";

import {HtmlHTMLAttributes, useId, useState} from "react";
import {HtmlHTMLAttributes, useState, JSX, useRef} from "react";
import SelectList from "@components/elements/select-list";
import {H2, H3} from "@components/elements/headers";
import {useBoolean, useCounter} from "usehooks-ts";
import {formatCurrency} from "@lib/utils/format-currency";
import useAccordion from "@lib/hooks/useAccordion";
import {clsx} from "clsx";
import {ChevronDownIcon} from "@heroicons/react/20/solid";
import useOutsideClick from "@lib/hooks/useOutsideClick";

type Props = HtmlHTMLAttributes<HTMLDivElement> & {
costPerStudentTypes: Map<string, Map<number, number>>
appCosts: Map<string, number>
appCost: number
progCosts: Map<string, number>
i20Cost: number
housingCosts: Map<string, number>
Expand All @@ -22,11 +22,22 @@ type Props = HtmlHTMLAttributes<HTMLDivElement> & {
booksSuppliesCost: number
healthServiceCost: number
documentsCost: number
commuterHelp?: JSX.Element | string
graduateApplicationHelp?: JSX.Element | string
graduateUnitsHelp?: JSX.Element | string
highSchoolAppHelp?: JSX.Element | string
highSchoolUnitHelp?: JSX.Element | string
onCampusHousingHelp?: JSX.Element | string
i20Help?: JSX.Element | string
insuranceHelp?: JSX.Element | string
wavedInsuranceHelp?: JSX.Element | string
undergradAppHelp?: JSX.Element | string
undergradUnitsHelp?: JSX.Element | string
}

const SumCalculatorParagraph = ({
costPerStudentTypes,
appCosts,
appCost,
progCosts,
i20Cost,
housingCosts,
Expand All @@ -37,19 +48,32 @@ const SumCalculatorParagraph = ({
booksSuppliesCost,
healthServiceCost,
documentsCost,
commuterHelp,
graduateApplicationHelp,
graduateUnitsHelp,
highSchoolAppHelp,
highSchoolUnitHelp,
onCampusHousingHelp,
i20Help,
insuranceHelp,
wavedInsuranceHelp,
undergradAppHelp,
undergradUnitsHelp,
...props
}: Props) => {
const id = useId();

const [studentType, setStudentType] = useState("")
const {value: needsI20, setValue: setNeedsI20} = useBoolean(false)
const {value: onCampus, setValue: setOnCampus} = useBoolean(false)
const {count: units, setCount: setUnits} = useCounter(0)
const {value: waivingInsurance, setValue: setWaivingInsurance} = useBoolean(true)
const [studentType, setStudentType] = useState<"highschool" | "graduate" | "undergraduate" | "">("")
const [needsI20, setNeedsI20] = useState<boolean | undefined>();
const [onCampus, setOnCampus] = useState<boolean | undefined>();
const [waivingInsurance, setWaivingInsurance] = useState<boolean | undefined>();
const [units, setUnits] = useState<number>(0)

const {buttonProps, panelProps, expanded} = useAccordion();
const {buttonProps, panelProps, expanded, toggleExpanded} = useAccordion();

const appFee = appCosts.get(studentType) || 0
const summaryRef = useRef(null)
useOutsideClick(summaryRef, () => expanded && toggleExpanded())

const appFee = studentType ? appCost : 0
const progFee = progCosts.get(studentType) || 0
const i20Fee = needsI20 ? i20Cost : 0
const housingFee = onCampus ? housingCosts.get(studentType) || 0 : 0
Expand All @@ -60,7 +84,7 @@ const SumCalculatorParagraph = ({

const unitsCost = costPerStudentTypes.get(studentType)?.get(units) || 0

const totalCost = appFee + progFee + i20Fee + housingFee + mealPlan + techFee + mailFee + insurance + unitsCost + booksSuppliesCost + healthServiceCost + documentsCost;
const totalCost = !studentType ? 0 : appFee + progFee + i20Fee + housingFee + mealPlan + techFee + mailFee + insurance + unitsCost + booksSuppliesCost + healthServiceCost + documentsCost;
const unitOptions: { value: string, label: string }[] = [];

for (let i = 3; i <= 20; i++) {
Expand All @@ -69,27 +93,28 @@ const SumCalculatorParagraph = ({

return (
<div {...props}>
<div className="max-w-7xl mx-auto pb-72">
<div className="max-w-7xl mx-auto pb-72 flex flex-col gap-20">
<div>
<div id={`${id}-type`}>I am a/an _________ student</div>

<SelectList
ariaLabelledby={`${id}-type`}
label="I am a/an _________ student"
options={[
{value: "undergraduate", label: "Undergraduate"},
{value: "highschool", label: "High School"},
{value: "graduate", label: "Graduate"}
]}
onChange={(_e, value) => setStudentType(value as string)}
onChange={(_e, value) => setStudentType(value as "highschool" | "graduate" | "undergraduate")}
required
/>

{studentType === "undergraduate" && undergradAppHelp}
{studentType === "graduate" && graduateApplicationHelp}
{studentType === "highschool" && highSchoolAppHelp}
</div>

<div>
<div id={`${id}-i20`}>Are you an international student that requires a Stanford issued I-20?</div>

<SelectList
ariaLabelledby={`${id}-i20`}
label="Are you an international student that requires a Stanford issued I-20?"
options={[
{value: "yes", label: "Yes, I am an international student requiring a Stanford Sponsored I-20"},
{value: "no1", label: "No, I am a US citizen or permanent US resident"},
Expand All @@ -99,116 +124,127 @@ const SumCalculatorParagraph = ({
required
disabled={!studentType}
/>

{needsI20 === true && i20Help}
</div>

<div>
<div id={`${id}-housing`}>Will you be living on campus?</div>
<SelectList
ariaLabelledby={`${id}-housing`}
label="Will you be living on campus?"
options={[
{value: "yes", label: "On-Campus"},
{value: "no", label: "Living off campus and commuting"},
]}
onChange={(_e, value) => setOnCampus(value === "yes")}
required
disabled={!studentType}
disabled={needsI20 ===undefined}
/>

{onCampus && onCampusHousingHelp}
{onCampus === false && commuterHelp}
</div>

<div>
<div id={`${id}-units`}>How many units will you be taking?</div>

<SelectList
ariaLabelledby={`${id}-units`}
label="How many units will you be taking?"
options={unitOptions}
onChange={(_e, value) => setUnits(parseInt(value as string))}
required
disabled={!studentType}
disabled={onCampus === undefined}
/>

{(studentType === "undergraduate" && units > 0) && undergradUnitsHelp}
{(studentType === "graduate" && units > 0) && graduateUnitsHelp}
{(studentType === "highschool" && units > 0) && highSchoolUnitHelp}
</div>

<div>
<div id={`${id}-insurance`}>Will you be waiving Cardinal Care Health Insurance?</div>

<SelectList
ariaLabelledby={`${id}-insurance`}
label="Will you be waiving Cardinal Care Health Insurance?"
options={[
{value: "yes", label: "Yes, I will be waiving Cardinal Care."},
{value: "no", label: "No, I would like to stay enrolled in Cardinal Care Health Insurance"},
]}
onChange={(_e, value) => setWaivingInsurance(value === "yes")}
required
disabled={!studentType}
disabled={units < 3}
/>

{waivingInsurance && wavedInsuranceHelp}
{waivingInsurance === false && insuranceHelp}
</div>
</div>

<div className="absolute bottom-0 bg-black-10 w-screen left-1/2 -translate-x-1/2">
<div className="max-w-7xl mx-auto">
<H2 className="flex justify-between" aria-live="polite" aria-atomic>
<span>Estimated total cost</span>
<span>{formatCurrency(totalCost)}</span>
</H2>
<p className="text-left">* Disclaimer: this is only an estimate. Actual fees are subject to change.</p>
<div ref={summaryRef} className="sticky bottom-0">

<div {...panelProps} className={clsx({"hidden": !expanded})}>
<div className="absolute bottom-0 w-full">
<div className="absolute -z-10 top-0 w-screen h-full bg-black-10 left-1/2 -translate-x-1/2"></div>

<div className="max-w-7xl mx-auto my-5">
<H2 className="flex justify-between" aria-live="polite" aria-atomic>
<span>Estimated total cost</span>
<span>{formatCurrency(totalCost)}</span>
</H2>
<p className="text-left">* Disclaimer: this is only an estimate. Actual fees are subject to change.</p>

{!!units &&
<div>
<div className="flex items-baseline gap-5"><H3>Tuition</H3>(Based on the total number of units)</div>
<SummaryCost label={`${units} Units`} cost={unitsCost}/>
</div>
}
<div {...panelProps} className={clsx({"hidden": !expanded})}>

{studentType &&
<div>
<H3>General Fees</H3>
<SummaryCost label="Application Fee" cost={appFee}/>
<SummaryCost label="Program Fee" cost={progFee}/>
<SummaryCost label="Campus Health Services Fee" cost={healthServiceCost}/>
{needsI20 &&
<SummaryCost label="I-20 Processing Fee" cost={i20Fee}/>
}
</div>
}

{onCampus &&
<div>
<H3>On-campus Fees</H3>
<SummaryCost label="Housing Fee" cost={housingFee}/>
<SummaryCost label="Meal Plan" cost={mealPlan}/>
<SummaryCost label="Mail Service Fee" cost={mailFee}/>
<SummaryCost label="Technology Fee " cost={techFee}/>
</div>
}
{!!units &&
<div>
<div className="flex items-baseline gap-5"><H3>Tuition</H3>(Based on the total number of units)</div>
<SummaryCost label={`${units} Units`} cost={unitsCost}/>
</div>
}

{studentType &&
<div>
<H3>General Fees</H3>
<SummaryCost label="Application Fee" cost={appFee}/>
<SummaryCost label="Program Fee" cost={progFee}/>
<SummaryCost label="Campus Health Services Fee" cost={healthServiceCost}/>
{needsI20 &&
<SummaryCost label="I-20 Processing Fee" cost={i20Fee}/>
}
</div>
}

<div>
<H3>Extra Fees</H3>
<SummaryCost label="Books and Supplies (optional)" cost={booksSuppliesCost}/>
<SummaryCost label="Document Fee" cost={documentsCost}/>
{!waivingInsurance &&
<SummaryCost label="Cardinal Care Health Insurance optional" cost={insurance}/>
{onCampus &&
<div>
<H3>On-campus Fees</H3>
<SummaryCost label="Housing Fee" cost={housingFee}/>
<SummaryCost label="Meal Plan" cost={mealPlan}/>
<SummaryCost label="Mail Service Fee" cost={mailFee}/>
<SummaryCost label="Technology Fee " cost={techFee}/>
</div>
}
</div>

<div>
<p className="text-m4 flex justify-between">
<span>Estimated total cost</span> <span>{formatCurrency(totalCost)}</span>
</p>

<p className="text-left">* Disclaimer: this is only an estimate. Actual fees are subject to change.</p>
<div>
<H3>Extra Fees</H3>
<SummaryCost label="Books and Supplies (optional)" cost={booksSuppliesCost}/>
<SummaryCost label="Document Fee" cost={documentsCost}/>
{!waivingInsurance &&
<SummaryCost label="Cardinal Care Health Insurance optional" cost={insurance}/>
}
</div>

<div>
<p className="text-m4 flex justify-between">
<span>Estimated total cost</span> <span>{formatCurrency(totalCost)}</span>
</p>

<p className="text-left">* Disclaimer: this is only an estimate. Actual fees are subject to change.</p>
</div>
</div>
</div>

<button {...buttonProps} className="block ml-auto">
<button {...buttonProps} className="block ml-auto">
<span className="flex items-center">
{expanded ? "Close" : "See"} details
<ChevronDownIcon width={20} className={clsx("transition duration-150", {"rotate-180": expanded})}/>
</span>
</button>
</button>
</div>
</div>
</div>
</div>
Expand Down
Loading

0 comments on commit d7dbd1d

Please sign in to comment.