Files
hedena_gold/apps/user-app/src/stores/configStore.ts
T
s.esmaeiliandClaude Opus 5 89e2d7937e feat(apps): tell a guest why they were bounced to the login page (D3)
A guest tapping a personal page — orders, transactions, profile,
favourites, complete-profile — was redirected in silence, so they landed
on the login box with nothing explaining what happened. Legacy showed
«ابتدا وارد شوید» (henza_pwa/src/router/index.ts:259).

The message is now shown in both apps. The destination deliberately
stays the target's /login?redirect=…, which legacy did not have: legacy
sent the guest to home and lost where they were going, while here
signing in returns them to the page they asked for. The owner chose that
trade-off, so it is logged as «عمداً تکرار نشد — D3/الف» rather than
quietly left as a divergence. The guard also keys off meta.requiresAuth
instead of legacy's hand-kept list of five route names, so the two
sales-expert pages are covered too.

Legacy's isLoaded router guard is NOT ported, and the reasoning is
written into both apps' configStore beside the line that says so: it
guarded legacy's one big bootstrap request, which this target does not
have, so it would guard nothing and only add a bounce — a shared product
link would open home instead of the product. That is porting the
breakage, not the behaviour (D4).

Route analytics is deferred at the owner's request; its design is parked
in docs/PHASE2-D3-PLAN.md so it need not be re-derived, along with the
two reference defects not to copy (log/create was unauthenticated and
accepted any title; log/update was a GET that wrote) and the open
retention and IP questions.

Seven of D3's ten items turned out to be built already — all five
screens in both apps, the sts_verify_step_two guard, v2's cart ceiling —
verified in the code rather than from the checkmarks.

Neither app has a test runner: verified with vue-tsc -b on both (clean)
plus confirming the toast can actually appear, not merely compile —
toast.info exists and <ToastHost /> is mounted in each App.vue.

اپ: وقتی بدون ورود صفحه شخصی را باز کنید، پیام «ابتدا وارد شوید» نشان داده می‌شود.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-12 10:40:22 +03:30

95 lines
3.6 KiB
TypeScript

// Scoped port of legacy henza_pwa/src/store/store.ts.
//
// Legacy fetched one curated payload (POST /front + GET /config) that carried
// the home banner slider, the category grid, promotions, the ignore-list and
// the gold price ticker. The new API exposes none of that as a single config
// endpoint, so this store restores the two pieces that drive visible home-page
// UI and are actually derivable today:
//
// - `cats` — REAL data: distinct categories derived from GET /catalog/products
// (the response already includes each product's category).
// Legacy's per-category `icon.image` was a remote URL from the old
// Laravel host and has no equivalent, so a local brand mark stands
// in until category artwork exists.
// - `config.main_slider` — legacy's banner slides were remote URLs too. These
// are placeholder slides built from legacy's own local artwork,
// using legacy's exact slide shape ({text, type, src, link}) so
// HomeSlider's popup/link/discount click handling works unchanged.
//
// Not ported (no backend): promotionList, ignoreList, priceList, isLoaded.
//
// `isLoaded` — «عمداً تکرار نشد — D3/ب» (owner, 2026-10-12). Legacy used it as a
// router guard: a signed-in user whose one big bootstrap request had not landed
// was sent to `home` from any route lacking `meta.skipLoadedCheck`
// (henza_pwa/src/router/index.ts:263-266). The target has no such bootstrap —
// every page fetches its own data — so the flag would guard nothing and only
// add a bounce: opening a shared product link would land on home instead of the
// product. Replicating it would port the breakage, not the behaviour (D4).
import { defineStore } from 'pinia'
import { useCatalogStore } from './catalogStore'
import shippingArt from '../assets/img/shipping-and-delivery.png'
import competitionArt from '../assets/img/sports-and-competition.png'
import brandArt from '../assets/img/montzar-logo.png'
export interface Slide {
text: string | undefined
type: string | undefined
src: string | undefined
link: string | undefined
}
export interface HomeCategory {
id: string
title: string
icon?: { image: string }
}
const PLACEHOLDER_SLIDES: Slide[] = [
{
type: 'popup',
src: shippingArt,
text: 'ارسال سریع و مطمئن سفارش‌های شما به سراسر کشور.',
link: undefined,
},
{
type: 'popup',
src: competitionArt,
text: 'جدیدترین محصولات منتزر را در بخش محصولات جدید ببینید.',
link: undefined,
},
{
type: 'popup',
src: brandArt,
text: 'منتزر، همراه شما در خرید و فروش طلا.',
link: undefined,
},
]
export const useConfigStore = defineStore('config', {
state: () => ({
config: { main_slider: PLACEHOLDER_SLIDES as Slide[] },
cats: [] as HomeCategory[],
loaded: false,
}),
actions: {
setCats(cats: HomeCategory[]) {
this.cats = cats
},
// Legacy's store.init() fanned out to /config, /promotion, /ignore, /price.
// Here the only live source is the product catalogue, from which the real
// category list is derived.
// The catalogue comes from catalogStore, so calling this next to another
// catalogue read costs no second request.
async init(force = false) {
try {
const catalog = useCatalogStore()
await catalog.load(force)
this.cats = catalog.categories.map((c) => ({ ...c, icon: { image: brandArt } }))
this.loaded = true
} catch (e) {
console.log(e)
}
},
},
})