fix: investment scenario detail blank screen and auto-renew refresh
Move useMemo hook above early returns to satisfy React Rules of Hooks, fixing blank screen when navigating to scenario detail. Also re-fetch scenario after projection updates so auto-renew renewal records appear automatically without requiring manual navigation. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
4
backend/package-lock.json
generated
4
backend/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "hoa-ledgeriq-backend",
|
||||
"version": "2026.3.17",
|
||||
"version": "2026.3.19",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "hoa-ledgeriq-backend",
|
||||
"version": "2026.3.17",
|
||||
"version": "2026.3.19",
|
||||
"dependencies": {
|
||||
"@nestjs/common": "^10.4.15",
|
||||
"@nestjs/config": "^3.3.0",
|
||||
|
||||
4
frontend/package-lock.json
generated
4
frontend/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "hoa-ledgeriq-frontend",
|
||||
"version": "2026.3.17",
|
||||
"version": "2026.3.19",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "hoa-ledgeriq-frontend",
|
||||
"version": "2026.3.17",
|
||||
"version": "2026.3.19",
|
||||
"dependencies": {
|
||||
"@mantine/core": "^7.15.3",
|
||||
"@mantine/dates": "^7.15.3",
|
||||
|
||||
@@ -40,7 +40,7 @@ export function InvestmentScenarioDetailPage() {
|
||||
},
|
||||
});
|
||||
|
||||
const { data: projection, isLoading: projLoading } = useQuery({
|
||||
const { data: projection, isLoading: projLoading, dataUpdatedAt: projUpdatedAt } = useQuery({
|
||||
queryKey: ['board-planning-projection', id],
|
||||
queryFn: async () => {
|
||||
const { data } = await api.get(`/board-planning/scenarios/${id}/projection`);
|
||||
@@ -49,6 +49,17 @@ export function InvestmentScenarioDetailPage() {
|
||||
enabled: !!id,
|
||||
});
|
||||
|
||||
// When projection refreshes (which may create auto-renew records on the backend),
|
||||
// re-fetch the scenario so the investments list picks up any new renewal records.
|
||||
const [lastProjUpdate, setLastProjUpdate] = useState(0);
|
||||
if (projUpdatedAt && projUpdatedAt !== lastProjUpdate) {
|
||||
setLastProjUpdate(projUpdatedAt);
|
||||
if (lastProjUpdate > 0) {
|
||||
// Only re-fetch after a real update (not the initial load)
|
||||
queryClient.invalidateQueries({ queryKey: ['board-planning-scenario', id] });
|
||||
}
|
||||
}
|
||||
|
||||
const addMutation = useMutation({
|
||||
mutationFn: (dto: any) => api.post(`/board-planning/scenarios/${id}/investments`, dto),
|
||||
onSuccess: () => {
|
||||
@@ -100,13 +111,10 @@ export function InvestmentScenarioDetailPage() {
|
||||
},
|
||||
});
|
||||
|
||||
if (isLoading) return <Center h={400}><Loader size="lg" /></Center>;
|
||||
if (!scenario) return <Center h={400}><Text>Scenario not found</Text></Center>;
|
||||
|
||||
const investments = scenario.investments || [];
|
||||
// Compute shared time range for aligned charts (must be above early returns to satisfy Rules of Hooks)
|
||||
const investments = scenario?.investments || [];
|
||||
const summary = projection?.summary;
|
||||
|
||||
// Compute shared time range for aligned charts
|
||||
const { sharedStartDate, sharedEndDate } = useMemo(() => {
|
||||
const allDates: Date[] = [];
|
||||
|
||||
@@ -134,6 +142,9 @@ export function InvestmentScenarioDetailPage() {
|
||||
};
|
||||
}, [investments, projection]);
|
||||
|
||||
if (isLoading) return <Center h={400}><Loader size="lg" /></Center>;
|
||||
if (!scenario) return <Center h={400}><Text>Scenario not found</Text></Center>;
|
||||
|
||||
// Build a lookup of per-investment interest from the projection
|
||||
const interestDetailMap: Record<string, { interest: number; principal: number }> = {};
|
||||
if (summary?.investment_interest_details) {
|
||||
|
||||
Reference in New Issue
Block a user