diff --git a/apps/api/src/routes/shopping.ts b/apps/api/src/routes/shopping.ts index f909576..e3d9834 100644 --- a/apps/api/src/routes/shopping.ts +++ b/apps/api/src/routes/shopping.ts @@ -77,7 +77,14 @@ export async function shoppingRoutes(app: FastifyInstance) { .select() .from(schema.shoppingListItems) .where(eq(schema.shoppingListItems.shoppingListId, id)) - .orderBy(schema.shoppingListItems.storeSection, schema.shoppingListItems.sortOrder); + // Stabil ordning: sektion, sortOrder och SIST id som tie-breaker. Utan id + // hamnar rader med samma sortOrder (t.ex. alla 0) i odefinierad ordning som + // kastas om när en rad uppdateras (bockas av) – varorna "hoppade" då runt. + .orderBy( + schema.shoppingListItems.storeSection, + schema.shoppingListItems.sortOrder, + schema.shoppingListItems.id, + ); const estimatedTotal = items.reduce((sum, i) => sum + (i.estimatedPriceMinor ?? 0), 0); // Prisuppskattningar härleds ur katalogens baspriser (SEK) tills per-marknads-priser (M8). return { list, items, estimatedTotalMinor: Math.round(estimatedTotal), currency: "SEK" }; @@ -139,6 +146,12 @@ export async function shoppingRoutes(app: FastifyInstance) { } } + // Nästa sortOrder = sist i listan, så nya varor läggs till på slutet i stället + // för att dela sortOrder 0 med alla andra (vilket gav ostabil ordning). + const [{ maxOrder } = { maxOrder: null }] = await app.db + .select({ maxOrder: sql`max(${schema.shoppingListItems.sortOrder})` }) + .from(schema.shoppingListItems) + .where(eq(schema.shoppingListItems.shoppingListId, id)); const [item] = await app.db .insert(schema.shoppingListItems) .values({ @@ -151,6 +164,7 @@ export async function shoppingRoutes(app: FastifyInstance) { estimatedPriceMinor: estimatedPrice ?? null, addedByUserId: req.userId, origin: "manual", + sortOrder: (maxOrder ?? -1) + 1, }) .returning(); return reply.status(201).send({ item, merged: false });