feat(favorites): keep customer favourites on the server, as legacy did (FAV-01)
Both apps kept favourites in memory only, and the API had no route, so the 874 favourites imported from legacy major_favorites never showed. - GET customer/me/favorites, POST customer/me/favorites/toggle - apps load them on sign-in, clear on sign-out, toggle optimistically and roll back on failure Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
5480398a93
commit
5d386bf752
@@ -336,6 +336,14 @@ export const api = {
|
||||
getAccountingBalance: () => request<AccountingBalance>('/customer/me/accounting-balance'),
|
||||
getMyOrders: () => request<OrderDetail[]>('/customer/me/orders'),
|
||||
getMyLedgerEntries: () => request<LedgerEntrySummary[]>('/customer/me/ledger-entries'),
|
||||
/** Favourite product ids, newest first — legacy get-favorites (FAV-01). */
|
||||
getFavorites: () => request<{ ids: string[] }>('/customer/me/favorites'),
|
||||
/** Legacy add-to-fav: adds or removes; answers the new state. */
|
||||
toggleFavorite: (productId: string) =>
|
||||
request<{ favorite: boolean }>('/customer/me/favorites/toggle', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ productId }),
|
||||
}),
|
||||
|
||||
createOrder: (dto: CreateOrderDto) => request<OrderSummary>('/orders', { method: 'POST', body: JSON.stringify(dto) }),
|
||||
getLatestGoldPrice: (karatPerMille = 750) => request<GoldPriceQuote>(`/pricing/latest?karatPerMille=${karatPerMille}`),
|
||||
|
||||
@@ -1,22 +1,55 @@
|
||||
// Adapted from legacy henza_pwa/src/Mixins/favorite.ts + the `favorits` slice of
|
||||
// myDataStore. Legacy persisted favorites server-side via POST /add-to-fav; the
|
||||
// new API has no favorites endpoint yet, so this is local-only (Pinia state,
|
||||
// not persisted) until that backend support exists. Flagged — not a silent
|
||||
// behavior match, a deliberate stand-in.
|
||||
// myDataStore. Legacy kept favourites on the server (POST add-to-fav /
|
||||
// get-favorites, table major_favorites); so does this, through
|
||||
// /customer/me/favorites (FAV-01). It used to be memory-only, so favourites
|
||||
// vanished on reload and the ones imported from legacy were never shown.
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref, watch } from 'vue'
|
||||
import { api } from '../api/client'
|
||||
import { useSessionStore } from './session'
|
||||
|
||||
export const useFavoritesStore = defineStore('favorites', {
|
||||
state: () => ({
|
||||
ids: [] as string[],
|
||||
}),
|
||||
actions: {
|
||||
toggle(id: string) {
|
||||
const index = this.ids.indexOf(id)
|
||||
if (index === -1) this.ids.push(id)
|
||||
else this.ids.splice(index, 1)
|
||||
export const useFavoritesStore = defineStore('favorites', () => {
|
||||
const ids = ref<string[]>([])
|
||||
const session = useSessionStore()
|
||||
|
||||
async function load() {
|
||||
try {
|
||||
ids.value = (await api.getFavorites()).ids
|
||||
} catch (e) {
|
||||
// Offline or a dead session (the client already handles 401): keep what we have.
|
||||
console.warn('favorites: load failed', e)
|
||||
}
|
||||
}
|
||||
|
||||
// Loaded for whoever is signed in, cleared on logout — never another user's list.
|
||||
watch(
|
||||
() => session.token,
|
||||
(token) => {
|
||||
ids.value = []
|
||||
if (token) void load()
|
||||
},
|
||||
isFavorite(id: string) {
|
||||
return this.ids.includes(id)
|
||||
},
|
||||
},
|
||||
{ immediate: true },
|
||||
)
|
||||
|
||||
/** Flips at once on screen, then confirms with the server (legacy toggled the same way). */
|
||||
async function toggle(id: string) {
|
||||
const was = ids.value.includes(id)
|
||||
ids.value = was ? ids.value.filter((x) => x !== id) : [id, ...ids.value]
|
||||
try {
|
||||
const { favorite } = await api.toggleFavorite(id)
|
||||
const has = ids.value.includes(id)
|
||||
if (favorite && !has) ids.value = [id, ...ids.value]
|
||||
if (!favorite && has) ids.value = ids.value.filter((x) => x !== id)
|
||||
} catch (e) {
|
||||
// Put it back so the heart never shows a state the server does not hold.
|
||||
ids.value = was ? [id, ...ids.value.filter((x) => x !== id)] : ids.value.filter((x) => x !== id)
|
||||
console.warn('favorites: toggle failed', e)
|
||||
}
|
||||
}
|
||||
|
||||
function isFavorite(id: string) {
|
||||
return ids.value.includes(id)
|
||||
}
|
||||
|
||||
return { ids, load, toggle, isFavorite }
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user