Rename ssr to website, website to spa, add spa nginx config

This commit is contained in:
Your Name committed 2026-06-03 09:38:15 +07:00
1 parent fc6bf0218e
commit 8514342c2f
103 files changed
+801 -768

No files matched your search

+37
View File
@@ -0,0 +1,37 @@
import { create } from "zustand";
import { persist } from "zustand/middleware";
export interface Customer {
id: number;
lineUserId: string;
displayName: string | null;
pictureUrl: string | null;
email: string | null;
phone: string | null;
}
interface AuthState {
token: string | null;
customer: Customer | null;
isLiffInitialized: boolean;
setAuth: (token: string, customer: Customer) => void;
setLiffInitialized: (status: boolean) => void;
logout: () => void;
}
export const useAuthStore = create<AuthState>()(
persist(
(set) => ({
token: null,
customer: null,
isLiffInitialized: false,
setAuth: (token, customer) => set({ token, customer }),
setLiffInitialized: (isLiffInitialized) => set({ isLiffInitialized }),
logout: () => set({ token: null, customer: null }),
}),
{
name: "irelax-auth-storage",
partialize: (state) => ({ token: state.token, customer: state.customer }), // don't persist isLiffInitialized
}
)
);
+78
View File
@@ -0,0 +1,78 @@
import { create } from 'zustand';
import { persist } from 'zustand/middleware';
import type { CartItem } from '@homaroma/types';
interface CartState {
items: CartItem[];
isCartOpen: boolean;
addToCart: (item: Omit<CartItem, 'cartItemId'>) => void;
removeFromCart: (cartItemId: string) => void;
updateQuantity: (cartItemId: string, quantity: number) => void;
clearCart: () => void;
toggleCart: (isOpen?: boolean) => void;
getCartTotal: () => number;
getCartCount: () => number;
}
export const useCartStore = create<CartState>()(
persist(
(set, get) => ({
items: [],
isCartOpen: false,
addToCart: (item) => set((state) => {
// Build a unique ID for the item. If variantId exists, use it. Otherwise, use productId.
const exactIdMatch = state.items.find(i =>
i.productId === item.productId && i.variantId === item.variantId
);
if (exactIdMatch) {
// Increment quantity if exact match exists
return {
items: state.items.map(i =>
i.cartItemId === exactIdMatch.cartItemId
? { ...i, quantity: i.quantity + item.quantity }
: i
),
isCartOpen: true
};
}
// Add new item with a generated cartItemId
const cartItemId = crypto.randomUUID();
return {
items: [...state.items, { ...item, cartItemId }],
isCartOpen: true
};
}),
removeFromCart: (cartItemId) => set((state) => ({
items: state.items.filter(i => i.cartItemId !== cartItemId)
})),
updateQuantity: (cartItemId, quantity) => set((state) => ({
items: state.items.map(i =>
i.cartItemId === cartItemId ? { ...i, quantity: Math.max(1, quantity) } : i
)
})),
clearCart: () => set({ items: [] }),
toggleCart: (isOpen) => set((state) => ({
isCartOpen: isOpen !== undefined ? isOpen : !state.isCartOpen
})),
getCartTotal: () => {
return get().items.reduce((total, item) => total + (item.price * item.quantity), 0);
},
getCartCount: () => {
return get().items.reduce((count, item) => count + item.quantity, 0);
}
}),
{
name: 'irelax-cart-storage',
partialize: (state) => ({ items: state.items }), // Only persist items, not UI state
}
)
);