- Backend: Add GET /api/orders/:id, PUT /api/orders/:id/cancel, GET /api/orders/:id/tracking with mock Yamato data - Frontend: Zustand cart store with localStorage persistence (key 'cart') - Frontend: CartPage (/cart) with quantity controls, item removal, JPY totals - Frontend: CheckoutPage (/checkout) with shipping address form, auth guard, POST to /api/orders - Frontend: OrderHistoryPage (/account/orders) with Japanese status labels, auth guard - Frontend: OrderDetailPage (/account/orders/:id) with cancel button, tracking section, auth guard - Updated App.tsx with all four new routes - Updated ProductDetail.tsx to use cart store with View Cart link after adding - Updated Navbar.tsx with cart icon badge (item count) and 注文履歴 order history link
71 lines
1.8 KiB
TypeScript
71 lines
1.8 KiB
TypeScript
import { create } from 'zustand'
|
|
import { persist } from 'zustand/middleware'
|
|
|
|
export interface CartItem {
|
|
product_id: string
|
|
name: string
|
|
price: number
|
|
quantity: number
|
|
image?: string
|
|
}
|
|
|
|
interface CartState {
|
|
items: CartItem[]
|
|
total: number
|
|
addItem: (item: CartItem) => void
|
|
removeItem: (product_id: string) => void
|
|
updateQuantity: (product_id: string, qty: number) => void
|
|
clearCart: () => void
|
|
}
|
|
|
|
function calcTotal(items: CartItem[]): number {
|
|
return items.reduce((sum, item) => sum + item.price * item.quantity, 0)
|
|
}
|
|
|
|
export const useCartStore = create<CartState>()(
|
|
persist(
|
|
(set, get) => ({
|
|
items: [],
|
|
total: 0,
|
|
|
|
addItem: (item: CartItem) => {
|
|
const existing = get().items.find(i => i.product_id === item.product_id)
|
|
let newItems: CartItem[]
|
|
if (existing) {
|
|
newItems = get().items.map(i =>
|
|
i.product_id === item.product_id
|
|
? { ...i, quantity: i.quantity + item.quantity }
|
|
: i
|
|
)
|
|
} else {
|
|
newItems = [...get().items, item]
|
|
}
|
|
set({ items: newItems, total: calcTotal(newItems) })
|
|
},
|
|
|
|
removeItem: (product_id: string) => {
|
|
const newItems = get().items.filter(i => i.product_id !== product_id)
|
|
set({ items: newItems, total: calcTotal(newItems) })
|
|
},
|
|
|
|
updateQuantity: (product_id: string, qty: number) => {
|
|
if (qty <= 0) {
|
|
get().removeItem(product_id)
|
|
return
|
|
}
|
|
const newItems = get().items.map(i =>
|
|
i.product_id === product_id ? { ...i, quantity: qty } : i
|
|
)
|
|
set({ items: newItems, total: calcTotal(newItems) })
|
|
},
|
|
|
|
clearCart: () => {
|
|
set({ items: [], total: 0 })
|
|
},
|
|
}),
|
|
{
|
|
name: 'cart',
|
|
}
|
|
)
|
|
)
|