From 9bd827a90dd23018141c8c1b01519cc3da5f3301 Mon Sep 17 00:00:00 2001 From: "Sven (AAMOS AI)" Date: Fri, 14 Aug 2026 20:00:49 +0700 Subject: [PATCH] =?UTF-8?q?fix(household):=20join=20tar=20bort=20tomt=20au?= =?UTF-8?q?to-sol-hush=C3=A5ll=20s=C3=A5=20delat=20hush=C3=A5ll=20blir=20a?= =?UTF-8?q?ktivt=20(MIKRO=2058)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/api/src/lib/helpers.ts | 31 +++++++++++++++++++++++++++++++ apps/api/src/routes/households.ts | 3 +++ apps/api/src/routes/onboarding.ts | 8 +++++++- 3 files changed, 41 insertions(+), 1 deletion(-) diff --git a/apps/api/src/lib/helpers.ts b/apps/api/src/lib/helpers.ts index b3ecac7..660adea 100644 --- a/apps/api/src/lib/helpers.ts +++ b/apps/api/src/lib/helpers.ts @@ -83,6 +83,37 @@ export async function createHouseholdWithDefaults( return { id: household!.id, name: household!.name }; } +/** När en användare går med i ett annat hushåll: ta bort deras auto-skapade + * sol-hushåll (enda ägaren, inget lager) så det delade blir aktivt. */ +export async function discardEmptySoloHouseholds( + db: Database, + userId: string, + keepHouseholdId: string, +): Promise { + const memberships = await db + .select({ + householdId: schema.householdMembers.householdId, + role: schema.householdMembers.role, + }) + .from(schema.householdMembers) + .where(eq(schema.householdMembers.userId, userId)); + for (const m of memberships) { + if (m.householdId === keepHouseholdId || m.role !== "owner") continue; + const members = await db + .select({ userId: schema.householdMembers.userId }) + .from(schema.householdMembers) + .where(eq(schema.householdMembers.householdId, m.householdId)); + if (members.length !== 1) continue; // inte ensam medlem → rör inte + const [inv] = await db + .select({ id: schema.inventoryItems.id }) + .from(schema.inventoryItems) + .where(eq(schema.inventoryItems.householdId, m.householdId)) + .limit(1); + if (inv) continue; // har lager → rör inte + await db.delete(schema.households).where(eq(schema.households.id, m.householdId)); // cascade städar medlem + platser + } +} + /** Hämta användarens aktiva hushåll (första medlemskapet) eller null. */ export async function getActiveHouseholdId(db: Database, userId: string): Promise { const [member] = await db diff --git a/apps/api/src/routes/households.ts b/apps/api/src/routes/households.ts index f572c34..b349fe2 100644 --- a/apps/api/src/routes/households.ts +++ b/apps/api/src/routes/households.ts @@ -16,6 +16,7 @@ import { errors, parse } from "../lib/errors.js"; import { audit, createHouseholdWithDefaults, + discardEmptySoloHouseholds, emitEvent, generateInviteCode, requireMembership, @@ -142,6 +143,8 @@ export async function householdRoutes(app: FastifyInstance) { .values({ householdId: household.id, userId: req.userId, role: "adult" }) .onConflictDoNothing(); + await discardEmptySoloHouseholds(app.db, req.userId, household.id); + await emitEvent(app.db, { type: "HOUSEHOLD_MEMBER_ADDED", payload: { householdId: household.id, newUserId: req.userId, role: "adult" }, diff --git a/apps/api/src/routes/onboarding.ts b/apps/api/src/routes/onboarding.ts index 3920453..96f7825 100644 --- a/apps/api/src/routes/onboarding.ts +++ b/apps/api/src/routes/onboarding.ts @@ -4,7 +4,12 @@ import { z } from "zod"; import { schema } from "@app/database"; import { quickStartInputSchema, onboardingInputSchema } from "@app/validation"; import { errors, parse } from "../lib/errors.js"; -import { audit, createHouseholdWithDefaults, getActiveHouseholdId } from "../lib/helpers.js"; +import { + audit, + createHouseholdWithDefaults, + discardEmptySoloHouseholds, + getActiveHouseholdId, +} from "../lib/helpers.js"; import { t } from "../lib/i18n.js"; import { KNOWN_FLAGS } from "@app/feature-flags"; @@ -171,6 +176,7 @@ export async function onboardingRoutes(app: FastifyInstance) { .insert(schema.householdMembers) .values({ householdId: household.id, userId: req.userId, role: "adult" }) .onConflictDoNothing(); + await discardEmptySoloHouseholds(app.db, req.userId, household.id); householdId = household.id; }