160 lines
5.0 KiB
TypeScript
160 lines
5.0 KiB
TypeScript
import { useEffect, useState } from 'react';
|
|
import { Link } from 'react-router-dom';
|
|
import { request } from '../lib/api';
|
|
import ProductCarousel from '../components/ProductCarousel';
|
|
import TabMainHeader from '../components/TabMainHeader';
|
|
import AppToast from '../components/AppToast';
|
|
import { getProductImages } from '../lib/product-images';
|
|
import { track } from '../lib/analytics';
|
|
import {
|
|
CITY_STORAGE_KEY,
|
|
FALLBACK_CITY_CODE,
|
|
resolveUserCity,
|
|
} from '../lib/wechat-location';
|
|
import { formatRegionCity } from '../lib/region-data';
|
|
import CouponBadge from '@dukang/shared-ui/CouponBadge';
|
|
|
|
type Product = {
|
|
id: string;
|
|
name: string;
|
|
subtitle: string;
|
|
price: number;
|
|
benefitDisplay: number;
|
|
mainImageUrl?: string | null;
|
|
carouselUrls?: string[] | null;
|
|
detailImageUrls?: string[] | null;
|
|
aromaType: string;
|
|
status: string;
|
|
};
|
|
|
|
type City = {
|
|
id: string;
|
|
code: string;
|
|
name: string;
|
|
status: string;
|
|
};
|
|
|
|
const AROMA_TABS = [
|
|
{ key: 'QINGXIANG', label: '清香型', open: true },
|
|
{ key: 'JIANGXIANG', label: '酱香型', open: false },
|
|
{ key: 'NONGXIANG', label: '浓香型', open: false },
|
|
];
|
|
|
|
export default function HomePage() {
|
|
const [tab, setTab] = useState('QINGXIANG');
|
|
const [products, setProducts] = useState<Product[]>([]);
|
|
const [cities, setCities] = useState<City[]>([]);
|
|
const [cityCode, setCityCode] = useState(() => localStorage.getItem(CITY_STORAGE_KEY) || FALLBACK_CITY_CODE);
|
|
const [locationLabel, setLocationLabel] = useState('定位中...');
|
|
const [toast, setToast] = useState('');
|
|
|
|
useEffect(() => {
|
|
track('home_view', { pagePath: '/', cityCode });
|
|
}, [cityCode]);
|
|
|
|
useEffect(() => {
|
|
request<City[]>('USER_H5', '/catalog/cities').then((list) => {
|
|
setCities(list);
|
|
if (!list.some((c) => c.code === cityCode) && list[0]) {
|
|
setCityCode(list[0].code);
|
|
}
|
|
});
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
resolveUserCity().then((resolved) => {
|
|
if (!resolved) {
|
|
setLocationLabel('郑州市');
|
|
setCityCode(FALLBACK_CITY_CODE);
|
|
return;
|
|
}
|
|
setLocationLabel(formatRegionCity(resolved.province, resolved.city));
|
|
if (resolved.openCity && resolved.cityCode) {
|
|
setCityCode(resolved.cityCode);
|
|
} else {
|
|
setCityCode(FALLBACK_CITY_CODE);
|
|
setToast('当前城市暂未开城,已展示郑州商品');
|
|
window.setTimeout(() => setToast(''), 2200);
|
|
}
|
|
});
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
if (!cityCode) return;
|
|
localStorage.setItem(CITY_STORAGE_KEY, cityCode);
|
|
request<Product[]>('USER_H5', `/catalog/products?cityCode=${encodeURIComponent(cityCode)}`).then(setProducts);
|
|
}, [cityCode]);
|
|
|
|
function showToast(message: string) {
|
|
setToast(message);
|
|
window.setTimeout(() => setToast(''), 2200);
|
|
}
|
|
|
|
function onAromaTabClick(key: string, open: boolean) {
|
|
if (!open) {
|
|
showToast('暂未开放');
|
|
return;
|
|
}
|
|
setTab(key);
|
|
}
|
|
|
|
const filtered = products.filter((p) => p.aromaType === tab);
|
|
const onSale = tab === 'QINGXIANG';
|
|
|
|
return (
|
|
<div className="page home-page">
|
|
<TabMainHeader
|
|
title="杜康好客"
|
|
extra={(
|
|
<div className="tab-main-city tab-main-city--readonly" aria-label={`当前位置 ${locationLabel}`}>
|
|
<span className="material-symbols-outlined" aria-hidden>location_on</span>
|
|
<span className="tab-main-city-label">{locationLabel}</span>
|
|
</div>
|
|
)}
|
|
/>
|
|
|
|
<nav className="home-aroma-nav">
|
|
{AROMA_TABS.map((t) => (
|
|
<button
|
|
key={t.key}
|
|
type="button"
|
|
className={`home-aroma-tab${tab === t.key ? ' active' : ''}${!t.open ? ' muted' : ''}`}
|
|
onClick={() => onAromaTabClick(t.key, t.open)}
|
|
>
|
|
{t.label}
|
|
</button>
|
|
))}
|
|
</nav>
|
|
|
|
<section className="home-product-list">
|
|
{!onSale && <div className="home-empty">该香型暂未上线,敬请期待</div>}
|
|
{onSale &&
|
|
filtered.map((p) => (
|
|
<article key={p.id} className="home-product-card">
|
|
<Link to={`/product/${p.id}`} className="home-product-link">
|
|
<ProductCarousel images={getProductImages(p)} alt={p.name} />
|
|
<div className="home-product-body">
|
|
<div className="home-product-row">
|
|
<h3 className="home-product-name">{p.name}</h3>
|
|
<span className="home-product-price">¥{p.price}</span>
|
|
</div>
|
|
<p className="home-product-sub">{p.subtitle}</p>
|
|
<div className="home-product-footer">
|
|
<CouponBadge amount={p.benefitDisplay} label="好客权益" />
|
|
</div>
|
|
</div>
|
|
</Link>
|
|
<div className="home-product-actions">
|
|
<Link to={`/product/${p.id}`} className="home-buy-btn">
|
|
立即购买
|
|
</Link>
|
|
</div>
|
|
</article>
|
|
))}
|
|
</section>
|
|
|
|
<AppToast message={toast} />
|
|
</div>
|
|
);
|
|
}
|