diff --git a/app/MarriageApp.jsx b/app/MarriageApp.jsx index 79fd14a..7e43ce4 100644 --- a/app/MarriageApp.jsx +++ b/app/MarriageApp.jsx @@ -2,9 +2,10 @@ import { useState, useEffect, useRef } from "react"; import InputForm from "./components/InputForm"; +import HouseholdSummary from "./components/HouseholdSummary"; import ResultsDisplay from "./components/ResultsDisplay"; +import { Dialog, DialogContent, DialogDescription, DialogTitle } from "@policyengine/ui-kit/primitives"; import { getCategorizedPrograms, getHeatmapData } from "@/lib/api"; -import { formatCurrency } from "@/lib/utils"; import { getCountry, COUNTRIES, DEFAULT_COUNTRY, LEGACY_HASH_COUNTRY, DEFAULT_BRMA } from "@/lib/countries"; const BASE_PATH = @@ -186,12 +187,11 @@ export default function MarriageApp({ initialCountry = null }) { const [formData, setFormData] = useState(null); const [valentine, setValentine] = useState(false); const [showConfetti, setShowConfetti] = useState(false); - const [externalIncomes, setExternalIncomes] = useState(null); - const [sidebarOpen, setSidebarOpen] = useState(true); - const [guidedSetup, setGuidedSetup] = useState(true); + const [editingSection, setEditingSection] = useState(null); + const [editingCountryId, setEditingCountryId] = useState(countryId); const resultsPanel = useRef(null); - const focusEditor = useRef(false); - const inputPanel = useRef(null); + const editTrigger = useRef(null); + const savedEdit = useRef(false); const didAutoCalc = useRef(false); const calculationId = useRef(0); const activeRequest = useRef(null); @@ -208,20 +208,15 @@ export default function MarriageApp({ initialCountry = null }) { const resolvedCountry = decoded.current?.countryId || hashCountry || initialCountry || DEFAULT_COUNTRY; setCountryId(resolvedCountry); setIsEmbedded(window.self !== window.top); - setGuidedSetup(!decoded.current); setMounted(true); }, [initialCountry]); useEffect(() => { - if (loading) resultsPanel.current?.focus(); - }, [loading]); - - useEffect(() => { - if (!guidedSetup && focusEditor.current) { - inputPanel.current?.querySelector("button, input")?.focus(); - focusEditor.current = false; + if (loading) { + resultsPanel.current?.focus({ preventScroll: true }); + resultsPanel.current?.closest(".results-workspace")?.scrollIntoView?.({ block: "start" }); } - }, [guidedSetup]); + }, [loading]); // Fire the tool_engaged conversion event after the user has been on // the page long enough to count as genuinely engaged. Matches the @@ -296,11 +291,10 @@ export default function MarriageApp({ initialCountry = null }) { setHeatmapLoading(false); setError(null); setHeatmapError(null); - setExternalIncomes(null); } - function updateHash(data) { - const hash = `#${encodeToHash(countryId, data, isEmbedded)}`; + function updateHash(data, nextCountryId = countryId) { + const hash = `#${encodeToHash(nextCountryId, data, isEmbedded)}`; window.history.replaceState(null, "", hash); if (window.self !== window.top) { window.parent.postMessage({ type: "hashchange", hash }, "*"); @@ -368,15 +362,15 @@ export default function MarriageApp({ initialCountry = null }) { } } - async function handleCalculate(data) { - setGuidedSetup(false); + async function handleCalculate(data, nextCountryId = countryId) { // Retry the submitted values, never a partially edited form or mutable // object retained by the caller. Country changes clear this snapshot. - const snapshot = { countryId, data: structuredClone(data) }; + const snapshot = { countryId: nextCountryId, data: structuredClone(data) }; retrySnapshot.current = snapshot; const { requestId, controller } = startRequest(); + setCountryId(nextCountryId); setFormData(snapshot.data); - updateHash(snapshot.data); + updateHash(snapshot.data, nextCountryId); setLoading(true); setError(null); @@ -402,7 +396,7 @@ export default function MarriageApp({ initialCountry = null }) { } function retryCalculation() { - if (retrySnapshot.current) handleCalculate(retrySnapshot.current.data); + if (retrySnapshot.current) handleCalculate(retrySnapshot.current.data, retrySnapshot.current.countryId); } function retryHeatmap() { @@ -412,18 +406,30 @@ export default function MarriageApp({ initialCountry = null }) { } function handleCellClick(headIncome, spouseIncome) { - setExternalIncomes({ headIncome, spouseIncome }); const data = { ...formData, headIncome, spouseIncome }; setFormData(data); updateHash(data); } + function openEdit(section, event) { + editTrigger.current = event.currentTarget; + savedEdit.current = false; + setEditingCountryId(countryId); + setEditingSection(section); + } + + function saveEdit(data) { + savedEdit.current = true; + setEditingSection(null); + handleCalculate(data, editingCountryId); + } + // Auto-calculate if URL has params on first load useEffect(() => { if (!mounted) return; if (decoded.current && !didAutoCalc.current) { didAutoCalc.current = true; - handleCalculate(decoded.current); + handleCalculate(decoded.current, decoded.current.countryId); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [mounted]); @@ -451,109 +457,74 @@ export default function MarriageApp({ initialCountry = null }) {

{valentine ? "Will tying the knot cost you? Find out this Valentine\u2019s Day." - : <>See how marriage would change your taxes and benefits. ♥ Press V} + : countryId === "uk" ? "See how living together would change your taxes and benefits." : "See how marriage would change your taxes and benefits."}

-
- - -
: !formData ? ( +
+ +
+ ) : ( +
+ +
+ {error &&
+

{error}

+ +
} + {loading &&
Calculating...
} + {results && - )} -
-
+ livingArrangement={formData.livingArrangement} + hasChildren={Boolean(formData.children?.length)} + />} + + + )} + + { if (!open) setEditingSection(null); }}> + { + event.preventDefault(); + if (savedEdit.current) resultsPanel.current?.focus({ preventScroll: true }); + else editTrigger.current?.focus(); + }}> + Edit your household + Save to update your comparison, or cancel to keep your current result. + {editingSection && setEditingSection(null)} + loading={false} + />} + +