fix: persist selected household across refresh
This commit is contained in:
parent
af0d95432f
commit
12b514262e
@ -2,6 +2,8 @@ import { createContext, useCallback, useContext, useEffect, useState } from 'rea
|
|||||||
import { createHousehold as createHouseholdApi, getUserHouseholds } from '../api/households';
|
import { createHousehold as createHouseholdApi, getUserHouseholds } from '../api/households';
|
||||||
import { AuthContext } from './AuthContext';
|
import { AuthContext } from './AuthContext';
|
||||||
|
|
||||||
|
const ACTIVE_HOUSEHOLD_STORAGE_KEY = 'activeHouseholdId';
|
||||||
|
|
||||||
export const HouseholdContext = createContext({
|
export const HouseholdContext = createContext({
|
||||||
households: [],
|
households: [],
|
||||||
activeHousehold: null,
|
activeHousehold: null,
|
||||||
@ -23,7 +25,7 @@ export const HouseholdProvider = ({ children }) => {
|
|||||||
|
|
||||||
const clearActiveHousehold = useCallback(() => {
|
const clearActiveHousehold = useCallback(() => {
|
||||||
setActiveHouseholdState(null);
|
setActiveHouseholdState(null);
|
||||||
localStorage.removeItem('activeHouseholdId');
|
localStorage.removeItem(ACTIVE_HOUSEHOLD_STORAGE_KEY);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const loadHouseholds = useCallback(async () => {
|
const loadHouseholds = useCallback(async () => {
|
||||||
@ -32,10 +34,8 @@ export const HouseholdProvider = ({ children }) => {
|
|||||||
setLoading(true);
|
setLoading(true);
|
||||||
setError(null);
|
setError(null);
|
||||||
try {
|
try {
|
||||||
console.log('[HouseholdContext] Loading households...');
|
|
||||||
const response = await getUserHouseholds();
|
const response = await getUserHouseholds();
|
||||||
const nextHouseholds = Array.isArray(response.data) ? response.data : [];
|
const nextHouseholds = Array.isArray(response.data) ? response.data : [];
|
||||||
console.log('[HouseholdContext] Loaded households:', nextHouseholds);
|
|
||||||
setHouseholds(nextHouseholds);
|
setHouseholds(nextHouseholds);
|
||||||
|
|
||||||
if (nextHouseholds.length === 0) {
|
if (nextHouseholds.length === 0) {
|
||||||
@ -69,33 +69,30 @@ export const HouseholdProvider = ({ children }) => {
|
|||||||
// Load active household from localStorage on mount
|
// Load active household from localStorage on mount
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (households.length === 0) {
|
if (households.length === 0) {
|
||||||
clearActiveHousehold();
|
setActiveHouseholdState(null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('[HouseholdContext] Setting active household from:', households);
|
const savedHouseholdId = localStorage.getItem(ACTIVE_HOUSEHOLD_STORAGE_KEY);
|
||||||
const savedHouseholdId = localStorage.getItem('activeHouseholdId');
|
|
||||||
if (savedHouseholdId) {
|
if (savedHouseholdId) {
|
||||||
const household = households.find(h => h.id === parseInt(savedHouseholdId, 10));
|
const household = households.find((candidate) => String(candidate.id) === savedHouseholdId);
|
||||||
if (household) {
|
if (household) {
|
||||||
console.log('[HouseholdContext] Found saved household:', household);
|
|
||||||
setActiveHouseholdState(household);
|
setActiveHouseholdState(household);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// No saved household or not found, use first one
|
// No saved household or not found, use first one
|
||||||
console.log('[HouseholdContext] Using first household:', households[0]);
|
|
||||||
setActiveHouseholdState(households[0]);
|
setActiveHouseholdState(households[0]);
|
||||||
localStorage.setItem('activeHouseholdId', households[0].id);
|
localStorage.setItem(ACTIVE_HOUSEHOLD_STORAGE_KEY, String(households[0].id));
|
||||||
}, [clearActiveHousehold, households]);
|
}, [households]);
|
||||||
|
|
||||||
const setActiveHousehold = (household) => {
|
const setActiveHousehold = (household) => {
|
||||||
setActiveHouseholdState(household);
|
setActiveHouseholdState(household);
|
||||||
if (household) {
|
if (household) {
|
||||||
localStorage.setItem('activeHouseholdId', household.id);
|
localStorage.setItem(ACTIVE_HOUSEHOLD_STORAGE_KEY, String(household.id));
|
||||||
} else {
|
} else {
|
||||||
localStorage.removeItem('activeHouseholdId');
|
localStorage.removeItem(ACTIVE_HOUSEHOLD_STORAGE_KEY);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
103
frontend/tests/household-selection-persistence.spec.ts
Normal file
103
frontend/tests/household-selection-persistence.spec.ts
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
import { expect, test } from "@playwright/test";
|
||||||
|
|
||||||
|
function seedAuthStorage(page: import("@playwright/test").Page) {
|
||||||
|
return page.addInitScript(() => {
|
||||||
|
localStorage.setItem("token", "test-token");
|
||||||
|
localStorage.setItem("userId", "1");
|
||||||
|
localStorage.setItem("role", "admin");
|
||||||
|
localStorage.setItem("username", "persistent-user");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function mockConfig(page: import("@playwright/test").Page) {
|
||||||
|
await page.route("**/config", async (route) => {
|
||||||
|
await route.fulfill({
|
||||||
|
status: 200,
|
||||||
|
contentType: "application/json",
|
||||||
|
body: JSON.stringify({
|
||||||
|
maxFileSizeMB: 20,
|
||||||
|
maxImageDimension: 800,
|
||||||
|
imageQuality: 85,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
test("selected household stays active after refreshing on settings and home pages", async ({ page }) => {
|
||||||
|
await seedAuthStorage(page);
|
||||||
|
await mockConfig(page);
|
||||||
|
|
||||||
|
const households = [
|
||||||
|
{ id: 1, name: "Alpha Home", role: "owner" },
|
||||||
|
{ id: 2, name: "Bravo Home", role: "admin" },
|
||||||
|
];
|
||||||
|
|
||||||
|
const storesByHousehold = {
|
||||||
|
1: [{ id: 101, name: "Costco", is_default: true }],
|
||||||
|
2: [{ id: 201, name: "Trader Joe's", is_default: true }],
|
||||||
|
};
|
||||||
|
|
||||||
|
await page.route("**/households", async (route) => {
|
||||||
|
await route.fulfill({
|
||||||
|
status: 200,
|
||||||
|
contentType: "application/json",
|
||||||
|
body: JSON.stringify(households),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
await page.route("**/stores/household/*", async (route) => {
|
||||||
|
const householdId = Number(route.request().url().split("/").pop());
|
||||||
|
await route.fulfill({
|
||||||
|
status: 200,
|
||||||
|
contentType: "application/json",
|
||||||
|
body: JSON.stringify(
|
||||||
|
storesByHousehold[householdId as keyof typeof storesByHousehold] ?? []
|
||||||
|
),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
await page.route("**/households/*/stores/*/list/recent", async (route) => {
|
||||||
|
await route.fulfill({
|
||||||
|
status: 200,
|
||||||
|
contentType: "application/json",
|
||||||
|
body: JSON.stringify([]),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
await page.route("**/households/*/stores/*/list", async (route) => {
|
||||||
|
await route.fulfill({
|
||||||
|
status: 200,
|
||||||
|
contentType: "application/json",
|
||||||
|
body: JSON.stringify({ items: [] }),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
await page.route("**/households/*/members", async (route) => {
|
||||||
|
await route.fulfill({
|
||||||
|
status: 200,
|
||||||
|
contentType: "application/json",
|
||||||
|
body: JSON.stringify([{ id: 1, username: "persistent-user", role: "owner" }]),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
await page.goto("/");
|
||||||
|
|
||||||
|
await expect(page.getByRole("button", { name: "Alpha Home" })).toBeVisible();
|
||||||
|
|
||||||
|
await page.getByRole("button", { name: "Alpha Home" }).click();
|
||||||
|
await page.getByRole("button", { name: "Bravo Home" }).click();
|
||||||
|
|
||||||
|
await expect(page.getByRole("button", { name: "Bravo Home" })).toBeVisible();
|
||||||
|
await expect.poll(() => page.evaluate(() => localStorage.getItem("activeHouseholdId"))).toBe("2");
|
||||||
|
|
||||||
|
await page.goto("/settings");
|
||||||
|
await expect(page.getByRole("button", { name: "Bravo Home" })).toBeVisible();
|
||||||
|
|
||||||
|
await page.reload();
|
||||||
|
await expect(page.getByRole("button", { name: "Bravo Home" })).toBeVisible();
|
||||||
|
await expect.poll(() => page.evaluate(() => localStorage.getItem("activeHouseholdId"))).toBe("2");
|
||||||
|
|
||||||
|
await page.goto("/");
|
||||||
|
await expect(page.getByRole("button", { name: "Bravo Home" })).toBeVisible();
|
||||||
|
await expect(page.getByRole("button", { name: "Trader Joe's" })).toBeVisible();
|
||||||
|
});
|
||||||
Loading…
Reference in New Issue
Block a user