diff --git a/apps/admin/src/components/CategoryBulkJsonModal.tsx b/apps/admin/src/components/CategoryBulkJsonModal.tsx index 2be3beb..0ef0f17 100644 --- a/apps/admin/src/components/CategoryBulkJsonModal.tsx +++ b/apps/admin/src/components/CategoryBulkJsonModal.tsx @@ -15,6 +15,7 @@ import { Package } from 'lucide-react'; import { API_BASE, type Category } from '@homaroma/types'; +import { getAuthHeaders } from '../utils/auth'; interface CategoryBulkJsonModalProps { isOpen: boolean; @@ -256,7 +257,7 @@ ${JSON.stringify( try { const res = await fetch(`${API_BASE}/categories/bulk-import`, { method: 'POST', - headers: { 'Content-Type': 'application/json' }, + headers: getAuthHeaders(), body: JSON.stringify(parsedImportData), }); diff --git a/apps/admin/src/components/ProductAttributeBulkJsonModal.tsx b/apps/admin/src/components/ProductAttributeBulkJsonModal.tsx index 11173ee..3325299 100644 --- a/apps/admin/src/components/ProductAttributeBulkJsonModal.tsx +++ b/apps/admin/src/components/ProductAttributeBulkJsonModal.tsx @@ -16,6 +16,7 @@ import { Filter } from 'lucide-react'; import { API_BASE, type AttributeDefinition, type Category } from '@homaroma/types'; +import { getAuthHeaders } from '../utils/auth'; interface ProductAttributeBulkJsonModalProps { isOpen: boolean; @@ -370,7 +371,7 @@ Please output ONLY the valid JSON Array without surrounding markdown or explanat try { const res = await fetch(`${API_BASE}/product-attributes/definitions/bulk-import`, { method: 'POST', - headers: { 'Content-Type': 'application/json' }, + headers: getAuthHeaders(), body: JSON.stringify(parsedImportData), }); diff --git a/apps/admin/src/components/RawMaterialBulkJsonModal.tsx b/apps/admin/src/components/RawMaterialBulkJsonModal.tsx index e4f4731..0e3be69 100644 --- a/apps/admin/src/components/RawMaterialBulkJsonModal.tsx +++ b/apps/admin/src/components/RawMaterialBulkJsonModal.tsx @@ -12,6 +12,7 @@ import { Sparkles, } from 'lucide-react'; import { API_BASE, type RawMaterial } from '@homaroma/types'; +import { getAuthHeaders } from '../utils/auth'; interface RawMaterialBulkJsonModalProps { isOpen: boolean; @@ -143,7 +144,7 @@ export default function RawMaterialBulkJsonModal({ try { const res = await fetch(`${API_BASE}/raw-materials/bulk`, { method: 'POST', - headers: { 'Content-Type': 'application/json' }, + headers: getAuthHeaders(), body: JSON.stringify(parsedPreview.items), }); diff --git a/apps/admin/src/pages/ArticleEditPage.tsx b/apps/admin/src/pages/ArticleEditPage.tsx index 0124655..5581bbe 100644 --- a/apps/admin/src/pages/ArticleEditPage.tsx +++ b/apps/admin/src/pages/ArticleEditPage.tsx @@ -2,6 +2,7 @@ import { useState, useEffect, useMemo, useRef } from 'react' import { useParams, useNavigate, Link } from 'react-router-dom' import { useTranslation } from 'react-i18next' import { API_BASE } from '@homaroma/types' +import { getAuthHeaders } from '../utils/auth' import { ArrowLeft, Save, Loader2, Image as ImageIcon } from 'lucide-react' import ReactQuill from 'react-quill-new' import 'react-quill-new/dist/quill.snow.css' @@ -59,7 +60,7 @@ export default function ArticleEditPage() { const payload = { title, slug, coverImage, content, isPublished } const res = await fetch(`${API_BASE}/articles${isNew ? '' : `/${id}`}`, { method: isNew ? 'POST' : 'PUT', - headers: { 'Content-Type': 'application/json' }, + headers: getAuthHeaders(), body: JSON.stringify(payload) }) if (!res.ok) throw new Error(await res.text()) diff --git a/apps/admin/src/pages/ArticlesPage.tsx b/apps/admin/src/pages/ArticlesPage.tsx index 92f2f62..2623428 100644 --- a/apps/admin/src/pages/ArticlesPage.tsx +++ b/apps/admin/src/pages/ArticlesPage.tsx @@ -1,6 +1,7 @@ import { useState, useEffect } from 'react' import { Link } from 'react-router-dom' import { API_BASE, type Article } from '@homaroma/types' +import { getAuthHeaders } from '../utils/auth' import { Plus, Edit, Trash2, Eye, EyeOff } from 'lucide-react' export default function ArticlesPage() { @@ -26,7 +27,10 @@ export default function ArticlesPage() { const handleDelete = async (id: number) => { if (!confirm('Are you sure you want to delete this article?')) return try { - const res = await fetch(`${API_BASE}/articles/${id}`, { method: 'DELETE' }) + const res = await fetch(`${API_BASE}/articles/${id}`, { + method: 'DELETE', + headers: getAuthHeaders(), + }) if (res.ok) { setArticles(prev => prev.filter(a => a.id !== id)) } diff --git a/apps/admin/src/pages/BrandsPage.tsx b/apps/admin/src/pages/BrandsPage.tsx index b6b80dd..1692b8a 100644 --- a/apps/admin/src/pages/BrandsPage.tsx +++ b/apps/admin/src/pages/BrandsPage.tsx @@ -2,6 +2,7 @@ import { useState, useEffect, useMemo } from 'react' import { Link } from 'react-router-dom' import { useTranslation } from 'react-i18next' import { API_BASE, type Brand } from '@homaroma/types' +import { getAuthHeaders } from '../utils/auth' import { Award, Plus, @@ -105,7 +106,7 @@ export default function BrandsPage() { try { const res = await fetch(`${API_BASE}/products/brands`, { method: 'POST', - headers: { 'Content-Type': 'application/json' }, + headers: getAuthHeaders(), body: JSON.stringify({ name: newBrandName.trim() }) }) const data = await res.json() @@ -133,7 +134,7 @@ export default function BrandsPage() { try { const res = await fetch(`${API_BASE}/products/brands/${editingBrand.id}`, { method: 'PUT', - headers: { 'Content-Type': 'application/json' }, + headers: getAuthHeaders(), body: JSON.stringify({ name: editBrandName.trim() }) }) const data = await res.json() @@ -163,7 +164,8 @@ export default function BrandsPage() { try { const res = await fetch(`${API_BASE}/products/brands/${brand.id}`, { - method: 'DELETE' + method: 'DELETE', + headers: getAuthHeaders(), }) const data = await res.json() if (res.ok && data.success) { @@ -200,7 +202,7 @@ export default function BrandsPage() { try { const res = await fetch(`${API_BASE}/products/brands/${translatingBrand.id}/translations`, { method: 'PATCH', - headers: { 'Content-Type': 'application/json' }, + headers: getAuthHeaders(), body: JSON.stringify({ name: translationsMap }) }) const data = await res.json() diff --git a/apps/admin/src/pages/CategoriesPage.tsx b/apps/admin/src/pages/CategoriesPage.tsx index 4907039..7ed3c12 100644 --- a/apps/admin/src/pages/CategoriesPage.tsx +++ b/apps/admin/src/pages/CategoriesPage.tsx @@ -2,6 +2,7 @@ import { useState, useEffect, useMemo } from 'react' import { useNavigate, Link } from 'react-router-dom' import { useTranslation } from 'react-i18next' import { API_BASE, getCategoryImage, resolveCategoryMediaUrl, type Category } from '@homaroma/types' +import { getAuthHeaders } from '../utils/auth' import { Edit3, Package, @@ -75,7 +76,8 @@ export default function CategoriesPage() { if (!confirm(t('categories.confirmDelete', `Are you sure you want to delete category "${catName}"?`))) return try { const res = await fetch(`${API_BASE}/categories/${id}`, { - method: 'DELETE' + method: 'DELETE', + headers: getAuthHeaders(), }) if (res.ok) { fetchData() diff --git a/apps/admin/src/pages/CategoryEditPage.tsx b/apps/admin/src/pages/CategoryEditPage.tsx index 7e1fc0a..3a066d9 100644 --- a/apps/admin/src/pages/CategoryEditPage.tsx +++ b/apps/admin/src/pages/CategoryEditPage.tsx @@ -2,6 +2,7 @@ import { useState, useEffect } from 'react' import { useParams, useNavigate, Link } from 'react-router-dom' import { useTranslation } from 'react-i18next' import { API_BASE, type Category, type CategoryMedia, type CategoryMediaRole, type CategoryFeaturedSeries, type CategoryUspBenefit, type CategoryFilterConfig } from '@homaroma/types' +import { getAuthHeaders } from '../utils/auth' import { ArrowLeft, Save, @@ -335,7 +336,7 @@ export default function CategoryEditPage() { // Step 1: Save base category const res = await fetch(url, { method, - headers: { 'Content-Type': 'application/json' }, + headers: getAuthHeaders(), body: JSON.stringify({ name: masterName, imageUrl: thumbnail.url, @@ -367,7 +368,7 @@ export default function CategoryEditPage() { if (targetId) { await fetch(`${API_BASE}/categories/${targetId}/translations`, { method: 'PATCH', - headers: { 'Content-Type': 'application/json' }, + headers: getAuthHeaders(), body: JSON.stringify({ name }) }) } @@ -396,7 +397,8 @@ export default function CategoryEditPage() { try { const res = await fetch(`${API_BASE}/categories/${id}`, { - method: 'DELETE' + method: 'DELETE', + headers: getAuthHeaders(), }) if (res.ok) { navigate('/categories') diff --git a/apps/admin/src/pages/CouponsPage.tsx b/apps/admin/src/pages/CouponsPage.tsx index ec47eaa..ed0af4e 100644 --- a/apps/admin/src/pages/CouponsPage.tsx +++ b/apps/admin/src/pages/CouponsPage.tsx @@ -1,5 +1,6 @@ import { useState, useEffect } from 'react' import { API_BASE } from '@homaroma/types' +import { getAuthHeaders } from '../utils/auth' import { Edit3, Ticket, Trash2, Plus, X, Power, PowerOff } from 'lucide-react' interface Coupon { @@ -50,7 +51,7 @@ export default function CouponsPage() { const res = await fetch(url, { method, - headers: { 'Content-Type': 'application/json' }, + headers: getAuthHeaders(), body: JSON.stringify({ code: editingCoupon.code, type: editingCoupon.type, @@ -80,7 +81,8 @@ export default function CouponsPage() { if (!confirm('Are you sure you want to delete this coupon?')) return try { const res = await fetch(`${API_BASE}/coupons/${id}`, { - method: 'DELETE' + method: 'DELETE', + headers: getAuthHeaders(), }) if (res.ok) { fetchData() diff --git a/apps/admin/src/pages/CustomersPage.tsx b/apps/admin/src/pages/CustomersPage.tsx index 488f166..90a798a 100644 --- a/apps/admin/src/pages/CustomersPage.tsx +++ b/apps/admin/src/pages/CustomersPage.tsx @@ -1,5 +1,6 @@ import { useState, useEffect } from 'react' import { API_BASE } from '@homaroma/types' +import { getAuthHeaders } from '../utils/auth' interface Customer { id: number @@ -25,7 +26,9 @@ export default function CustomersPage() { const fetchCustomers = async () => { try { - const res = await fetch(`${API_BASE}/customers`) + const res = await fetch(`${API_BASE}/customers`, { + headers: getAuthHeaders(), + }) const data = await res.json() setCustomers(data) } catch (err) { diff --git a/apps/admin/src/pages/DashboardPage.tsx b/apps/admin/src/pages/DashboardPage.tsx index 18e85b8..41b3ce1 100644 --- a/apps/admin/src/pages/DashboardPage.tsx +++ b/apps/admin/src/pages/DashboardPage.tsx @@ -2,6 +2,7 @@ import { useState, useEffect } from 'react' import { useTranslation } from 'react-i18next' import { Package, Tag, Layers, TrendingUp } from 'lucide-react' import { API_BASE, type Category, type Product } from '@homaroma/types' +import { getAuthHeaders } from '../utils/auth' import { useStoreSettings } from '../contexts/StoreSettingsContext' export default function DashboardPage() { @@ -22,10 +23,10 @@ export default function DashboardPage() { const fetchData = async () => { try { const [catRes, prodRes, orderRes, customerRes] = await Promise.all([ - fetch(`${API_BASE}/categories`), - fetch(`${API_BASE}/products`), - fetch(`${API_BASE}/orders`), - fetch(`${API_BASE}/customers`) + fetch(`${API_BASE}/categories`, { headers: getAuthHeaders() }), + fetch(`${API_BASE}/products`, { headers: getAuthHeaders() }), + fetch(`${API_BASE}/orders`, { headers: getAuthHeaders() }), + fetch(`${API_BASE}/customers`, { headers: getAuthHeaders() }) ]) const cats: Category[] = await catRes.json() const prods: Product[] = await prodRes.json() diff --git a/apps/admin/src/pages/MediaLibraryPage.tsx b/apps/admin/src/pages/MediaLibraryPage.tsx index 07f05b1..40eb15c 100644 --- a/apps/admin/src/pages/MediaLibraryPage.tsx +++ b/apps/admin/src/pages/MediaLibraryPage.tsx @@ -1,6 +1,7 @@ import React, { useState, useEffect, useCallback, useRef } from 'react'; import { useTranslation } from 'react-i18next'; import { API_BASE } from '@homaroma/types'; +import { getAuthHeaders } from '../utils/auth'; import { Upload, Loader2, Image as ImageIcon, Trash2, ClipboardPaste } from 'lucide-react'; interface MediaItem { @@ -21,7 +22,9 @@ export default function MediaLibraryPage() { const fetchMedia = async () => { try { setLoading(true); - const res = await fetch(`${API_BASE}/media`); + const res = await fetch(`${API_BASE}/media`, { + headers: getAuthHeaders(), + }); if (res.ok) { const data = await res.json(); setMedia(data); @@ -113,6 +116,7 @@ export default function MediaLibraryPage() { setDeletingId(id); const res = await fetch(`${API_BASE}/media/${id}`, { method: 'DELETE', + headers: getAuthHeaders(), }); if (res.ok) { await fetchMedia(); diff --git a/apps/admin/src/pages/NewsletterSubscribersPage.tsx b/apps/admin/src/pages/NewsletterSubscribersPage.tsx index ea3431a..f832b8b 100644 --- a/apps/admin/src/pages/NewsletterSubscribersPage.tsx +++ b/apps/admin/src/pages/NewsletterSubscribersPage.tsx @@ -1,5 +1,6 @@ import { useState, useEffect } from 'react' import { API_BASE } from '@homaroma/types' +import { getAuthHeaders } from '../utils/auth' import { Download, Loader2, Mail } from 'lucide-react' interface Subscriber { @@ -14,7 +15,9 @@ export default function NewsletterSubscribersPage() { const [loading, setLoading] = useState(true) useEffect(() => { - fetch(`${API_BASE}/newsletter/subscribers`) + fetch(`${API_BASE}/newsletter/subscribers`, { + headers: getAuthHeaders(), + }) .then(res => res.json()) .then(data => { if (Array.isArray(data)) { diff --git a/apps/admin/src/pages/OrderDetailPage.tsx b/apps/admin/src/pages/OrderDetailPage.tsx index f7e99c6..f22d341 100644 --- a/apps/admin/src/pages/OrderDetailPage.tsx +++ b/apps/admin/src/pages/OrderDetailPage.tsx @@ -2,6 +2,7 @@ import { useState, useEffect } from 'react' import { useParams, Link } from 'react-router-dom' import { useTranslation } from 'react-i18next' import { API_BASE, formatPrice, type Order } from '@homaroma/types' +import { getAuthHeaders } from '../utils/auth' import { ArrowLeft, CheckCircle2, ExternalLink, Loader2, Truck, XCircle, FileImage } from 'lucide-react' export default function OrderDetailPage() { @@ -13,7 +14,9 @@ export default function OrderDetailPage() { const fetchOrder = async () => { try { - const res = await fetch(`${API_BASE}/orders/${id}`) + const res = await fetch(`${API_BASE}/orders/${id}`, { + headers: getAuthHeaders(), + }) const data = await res.json() setOrder(data) } catch (err) { @@ -32,7 +35,7 @@ export default function OrderDetailPage() { try { await fetch(`${API_BASE}/orders/${id}/status`, { method: 'PATCH', - headers: { 'Content-Type': 'application/json' }, + headers: getAuthHeaders(), body: JSON.stringify({ status }) }) await fetchOrder() diff --git a/apps/admin/src/pages/OrdersPage.tsx b/apps/admin/src/pages/OrdersPage.tsx index e2a8004..9738f3b 100644 --- a/apps/admin/src/pages/OrdersPage.tsx +++ b/apps/admin/src/pages/OrdersPage.tsx @@ -2,6 +2,7 @@ import { useState, useEffect } from 'react' import { Link } from 'react-router-dom' import { useTranslation } from 'react-i18next' import { API_BASE, formatPrice, type Order } from '@homaroma/types' +import { getAuthHeaders } from '../utils/auth' import { Search, ChevronRight, Clock, CheckCircle2, Truck, XCircle } from 'lucide-react' export default function OrdersPage() { @@ -14,7 +15,9 @@ export default function OrdersPage() { const fetchData = async () => { setLoading(true) try { - const res = await fetch(`${API_BASE}/orders`) + const res = await fetch(`${API_BASE}/orders`, { + headers: getAuthHeaders(), + }) const data = await res.json() setOrders(Array.isArray(data) ? data : []) } catch (err) { diff --git a/apps/admin/src/pages/PaymentSettingsPage.tsx b/apps/admin/src/pages/PaymentSettingsPage.tsx index 78c1873..e0d3c48 100644 --- a/apps/admin/src/pages/PaymentSettingsPage.tsx +++ b/apps/admin/src/pages/PaymentSettingsPage.tsx @@ -1,5 +1,6 @@ import { useState, useEffect } from 'react' import { API_BASE, type StoreSettings } from '@homaroma/types' +import { getAuthHeaders } from '../utils/auth' import { Save, Loader2, Landmark, Truck } from 'lucide-react' export default function PaymentSettingsPage() { @@ -32,7 +33,7 @@ export default function PaymentSettingsPage() { try { const res = await fetch(`${API_BASE}/settings`, { method: 'PUT', - headers: { 'Content-Type': 'application/json' }, + headers: getAuthHeaders(), body: JSON.stringify({ shippingFee: parseFloat(shippingFee) || 0, bankName, bankAccountName, bankAccountNumber, diff --git a/apps/admin/src/pages/ProductAttributeEditPage.tsx b/apps/admin/src/pages/ProductAttributeEditPage.tsx index 34f1297..96f1152 100644 --- a/apps/admin/src/pages/ProductAttributeEditPage.tsx +++ b/apps/admin/src/pages/ProductAttributeEditPage.tsx @@ -2,6 +2,7 @@ import { useState, useEffect, useMemo } from 'react' import { useParams, useNavigate, Link } from 'react-router-dom' import { useTranslation } from 'react-i18next' import { API_BASE, type AttributeDefinition, type Category } from '@homaroma/types' +import { getAuthHeaders } from '../utils/auth' import { ArrowLeft, Save, @@ -488,7 +489,7 @@ export default function ProductAttributeEditPage() { const res = await fetch(url, { method, - headers: { 'Content-Type': 'application/json' }, + headers: getAuthHeaders(), body: JSON.stringify(payload), }) @@ -517,7 +518,10 @@ export default function ProductAttributeEditPage() { try { setSaving(true) - const res = await fetch(`${API_BASE}/product-attributes/definitions/${id}`, { method: 'DELETE' }) + const res = await fetch(`${API_BASE}/product-attributes/definitions/${id}`, { + method: 'DELETE', + headers: getAuthHeaders(), + }) if (!res.ok) { const errData = await res.json().catch(() => null) throw new Error(errData?.message || 'Failed to delete attribute definition') diff --git a/apps/admin/src/pages/ProductAttributesPage.tsx b/apps/admin/src/pages/ProductAttributesPage.tsx index a0c3b12..4971326 100644 --- a/apps/admin/src/pages/ProductAttributesPage.tsx +++ b/apps/admin/src/pages/ProductAttributesPage.tsx @@ -2,6 +2,7 @@ import { useEffect, useMemo, useState } from 'react' import { useNavigate, Link } from 'react-router-dom' import { useTranslation } from 'react-i18next' import { API_BASE, type AttributeDefinition, type Category } from '@homaroma/types' +import { getAuthHeaders } from '../utils/auth' import { Edit3, FileJson, @@ -53,7 +54,10 @@ export default function ProductAttributesPage() { const handleDelete = async (id: number, label: string) => { if (!confirm(t('common.confirmDelete', `Are you sure you want to delete attribute "${label}"?`))) return try { - const res = await fetch(`${API_BASE}/product-attributes/definitions/${id}`, { method: 'DELETE' }) + const res = await fetch(`${API_BASE}/product-attributes/definitions/${id}`, { + method: 'DELETE', + headers: getAuthHeaders(), + }) if (!res.ok) { const errData = await res.json().catch(() => null) throw new Error(errData?.message || 'Failed to delete attribute definition') diff --git a/apps/admin/src/pages/ProductBomPage.tsx b/apps/admin/src/pages/ProductBomPage.tsx index 4cc93be..5660540 100644 --- a/apps/admin/src/pages/ProductBomPage.tsx +++ b/apps/admin/src/pages/ProductBomPage.tsx @@ -16,6 +16,7 @@ import { FileJson } from 'lucide-react' import { API_BASE, type Product } from '@homaroma/types' +import { getAuthHeaders } from '../utils/auth' import ProductBomPromptModal from '../components/ProductBomPromptModal' import ProductBomImportModal from '../components/ProductBomImportModal' @@ -54,7 +55,9 @@ export default function ProductBomPage() { useEffect(() => { const fetchData = async () => { try { - const rmRes = await fetch(`${API_BASE}/raw-materials`) + const rmRes = await fetch(`${API_BASE}/raw-materials`, { + headers: getAuthHeaders(), + }) if (rmRes.ok) { const rmData = await rmRes.json() setRawMaterials(rmData) @@ -126,7 +129,7 @@ export default function ProductBomPage() { const response = await fetch(`${API_BASE}/products/${id}`, { method: 'PUT', - headers: { 'Content-Type': 'application/json' }, + headers: getAuthHeaders(), body: JSON.stringify(payload), }) diff --git a/apps/admin/src/pages/ProductEditPage.tsx b/apps/admin/src/pages/ProductEditPage.tsx index 41da517..f0256f3 100644 --- a/apps/admin/src/pages/ProductEditPage.tsx +++ b/apps/admin/src/pages/ProductEditPage.tsx @@ -24,6 +24,7 @@ import { Upload } from 'lucide-react' import { API_BASE, type AttributeDefinition, type Brand, type Category, type Product, type ProductAttribute, type ProductImage, type Variant } from '@homaroma/types' +import { getAuthHeaders } from '../utils/auth' import MDEditor from '@uiw/react-md-editor' import MediaLibraryModal from '../components/MediaLibraryModal' import ContentLanguageTabs from '../components/ContentLanguageTabs' @@ -408,7 +409,7 @@ export default function ProductEditPage() { const response = await fetch(url, { method, - headers: { 'Content-Type': 'application/json' }, + headers: getAuthHeaders(), body: JSON.stringify({ categoryId, brandId: brandId ? Number(brandId) : undefined, @@ -444,7 +445,7 @@ export default function ProductEditPage() { const attributeResponse = await fetch(`${API_BASE}/products/${savedProductId}/attributes`, { method: 'PUT', - headers: { 'Content-Type': 'application/json' }, + headers: getAuthHeaders(), body: JSON.stringify({ attributes: attributes.map(buildAttributePayload), }), diff --git a/apps/admin/src/pages/ProductsPage.tsx b/apps/admin/src/pages/ProductsPage.tsx index cb3a9df..40d5a72 100644 --- a/apps/admin/src/pages/ProductsPage.tsx +++ b/apps/admin/src/pages/ProductsPage.tsx @@ -22,6 +22,7 @@ import { import { useNavigate, useSearchParams } from 'react-router-dom' import { useTranslation } from 'react-i18next' import { API_BASE, getCategoryImage, formatPrice, type Category, type Product } from '@homaroma/types' +import { getAuthHeaders } from '../utils/auth' import ProductJsonGuideModal from '../components/ProductJsonGuideModal' import ProductOptionUxModal from '../components/products/ProductOptionUxModal' @@ -175,7 +176,7 @@ export default function ProductsPage() { try { const res = await fetch(`${API_BASE}/products/bulk`, { method: 'POST', - headers: { 'Content-Type': 'application/json' }, + headers: getAuthHeaders(), body: JSON.stringify(payloadArray) }) @@ -237,7 +238,7 @@ export default function ProductsPage() { const updatedImages = [...(selectedProduct.images || []), ...newImages] const updateRes = await fetch(`${API_BASE}/products/${selectedProduct.id}`, { method: 'PUT', - headers: { 'Content-Type': 'application/json' }, + headers: getAuthHeaders(), body: JSON.stringify({ categoryId: selectedProduct.categoryId, options: selectedProduct.options, @@ -302,7 +303,7 @@ export default function ProductsPage() { const updatedImages = (selectedProduct.images || []).filter(img => img.url !== imgUrl) const updateRes = await fetch(`${API_BASE}/products/${selectedProduct.id}`, { method: 'PUT', - headers: { 'Content-Type': 'application/json' }, + headers: getAuthHeaders(), body: JSON.stringify({ categoryId: selectedProduct.categoryId, options: selectedProduct.options, @@ -367,7 +368,10 @@ export default function ProductsPage() { const handleDelete = async (id: number) => { if (!confirm(t('common.confirmDelete', 'Are you sure you want to delete this product?'))) return try { - const res = await fetch(`${API_BASE}/products/${id}`, { method: 'DELETE' }) + const res = await fetch(`${API_BASE}/products/${id}`, { + method: 'DELETE', + headers: getAuthHeaders(), + }) if (res.ok) { setSelectedIds(prev => prev.filter(item => item !== id)) fetchData() @@ -389,7 +393,7 @@ export default function ProductsPage() { try { const res = await fetch(`${API_BASE}/products/bulk-delete`, { method: 'POST', - headers: { 'Content-Type': 'application/json' }, + headers: getAuthHeaders(), body: JSON.stringify({ ids: selectedIds }) }) diff --git a/apps/admin/src/pages/PromotionsPage.tsx b/apps/admin/src/pages/PromotionsPage.tsx index d5e3b7f..83a8f34 100644 --- a/apps/admin/src/pages/PromotionsPage.tsx +++ b/apps/admin/src/pages/PromotionsPage.tsx @@ -1,5 +1,6 @@ import { useState, useEffect } from 'react' import { API_BASE } from '@homaroma/types' +import { getAuthHeaders } from '../utils/auth' import { Plus, Edit2, Trash2, X } from 'lucide-react' interface Promotion { @@ -94,7 +95,7 @@ export default function PromotionsPage() { const method = editingId ? 'PUT' : 'POST' await fetch(url, { method, - headers: { 'Content-Type': 'application/json' }, + headers: getAuthHeaders(), body: JSON.stringify(payload) }) setIsModalOpen(false) @@ -107,7 +108,10 @@ export default function PromotionsPage() { const handleDelete = async (id: number) => { if (!confirm('Are you sure you want to delete this promotion?')) return try { - await fetch(`${API_BASE}/promotions/${id}`, { method: 'DELETE' }) + await fetch(`${API_BASE}/promotions/${id}`, { + method: 'DELETE', + headers: getAuthHeaders(), + }) fetchPromotions() } catch (err) { console.error(err) diff --git a/apps/admin/src/pages/RawMaterialDetailPage.tsx b/apps/admin/src/pages/RawMaterialDetailPage.tsx index 4a4c2d9..f8602eb 100644 --- a/apps/admin/src/pages/RawMaterialDetailPage.tsx +++ b/apps/admin/src/pages/RawMaterialDetailPage.tsx @@ -14,6 +14,7 @@ import { AlertCircle } from 'lucide-react'; import { API_BASE } from '@homaroma/types'; +import { getAuthHeaders } from '../utils/auth'; const COMMON_UNITS = [ { label: 'ชิ้น (piece)', value: 'piece' }, @@ -46,7 +47,9 @@ export default function RawMaterialDetailPage() { if (isNew) return; setLoading(true); - fetch(`${API_BASE}/raw-materials/${id}`) + fetch(`${API_BASE}/raw-materials/${id}`, { + headers: getAuthHeaders(), + }) .then(async (res) => { if (!res.ok) throw new Error('ไม่พบข้อมูลวัตถุดิบ'); return await res.json(); @@ -97,7 +100,7 @@ export default function RawMaterialDetailPage() { const res = await fetch(url, { method, - headers: { 'Content-Type': 'application/json' }, + headers: getAuthHeaders(), body: JSON.stringify(payload), }); @@ -127,6 +130,7 @@ export default function RawMaterialDetailPage() { try { const res = await fetch(`${API_BASE}/raw-materials/${id}`, { method: 'DELETE', + headers: getAuthHeaders(), }); if (!res.ok) { const data = await res.json(); diff --git a/apps/admin/src/pages/RawMaterialsPage.tsx b/apps/admin/src/pages/RawMaterialsPage.tsx index 7fe3247..b97fa26 100644 --- a/apps/admin/src/pages/RawMaterialsPage.tsx +++ b/apps/admin/src/pages/RawMaterialsPage.tsx @@ -16,6 +16,7 @@ import { Pencil, } from 'lucide-react'; import { API_BASE, type RawMaterial } from '@homaroma/types'; +import { getAuthHeaders } from '../utils/auth'; import RawMaterialBulkJsonModal from '../components/RawMaterialBulkJsonModal'; export default function RawMaterialsPage() { @@ -51,7 +52,7 @@ export default function RawMaterialsPage() { try { const res = await fetch(`${API_BASE}/raw-materials/${item.id}`, { method: 'PUT', - headers: { 'Content-Type': 'application/json' }, + headers: getAuthHeaders(), body: JSON.stringify({ pricePerUnit: val, }), @@ -78,7 +79,9 @@ export default function RawMaterialsPage() { const fetchMaterials = async () => { setLoading(true); try { - const res = await fetch(`${API_BASE}/raw-materials`); + const res = await fetch(`${API_BASE}/raw-materials`, { + headers: getAuthHeaders(), + }); if (res.ok) { setMaterials(await res.json()); } @@ -97,7 +100,10 @@ export default function RawMaterialsPage() { if (!confirm(`คุณแน่ใจหรือไม่ว่าต้องการลบวัตถุดิบ "${name}"?`)) return; try { - const res = await fetch(`${API_BASE}/raw-materials/${id}`, { method: 'DELETE' }); + const res = await fetch(`${API_BASE}/raw-materials/${id}`, { + method: 'DELETE', + headers: getAuthHeaders(), + }); if (res.ok) { fetchMaterials(); } else { diff --git a/apps/admin/src/pages/StoreSettingsPage.tsx b/apps/admin/src/pages/StoreSettingsPage.tsx index 1d74f81..3e01c4e 100644 --- a/apps/admin/src/pages/StoreSettingsPage.tsx +++ b/apps/admin/src/pages/StoreSettingsPage.tsx @@ -1,5 +1,6 @@ import { useState, useEffect } from 'react'; import { API_BASE, type StoreSettings, type StoreSettingsTranslation } from '@homaroma/types'; +import { getAuthHeaders } from '../utils/auth'; import { Save, Loader2, @@ -257,7 +258,7 @@ export default function StoreSettingsPage() { const res = await fetch(`${API_BASE}/settings`, { method: 'PUT', - headers: { 'Content-Type': 'application/json' }, + headers: getAuthHeaders(), body: JSON.stringify(payload), }); diff --git a/apps/admin/src/pages/ThemeSettingsPage.tsx b/apps/admin/src/pages/ThemeSettingsPage.tsx index 522c035..b4c7e19 100644 --- a/apps/admin/src/pages/ThemeSettingsPage.tsx +++ b/apps/admin/src/pages/ThemeSettingsPage.tsx @@ -1,5 +1,6 @@ import { useState, useEffect, useRef } from 'react' import { API_BASE, type StoreSettings } from '@homaroma/types' +import { getAuthHeaders } from '../utils/auth' import ThemeLivePreview from '../components/ThemeLivePreview' import { Save, @@ -492,7 +493,7 @@ export default function ThemeSettingsPage() { try { const res = await fetch(`${API_BASE}/settings`, { method: 'PUT', - headers: { 'Content-Type': 'application/json' }, + headers: getAuthHeaders(), body: JSON.stringify({ themeTokens: { ...themeTokens, diff --git a/apps/admin/src/pages/profitability/CostProfitabilityMatrixPage.tsx b/apps/admin/src/pages/profitability/CostProfitabilityMatrixPage.tsx index a8257eb..3de02f8 100644 --- a/apps/admin/src/pages/profitability/CostProfitabilityMatrixPage.tsx +++ b/apps/admin/src/pages/profitability/CostProfitabilityMatrixPage.tsx @@ -13,6 +13,7 @@ import { SlidersHorizontal, } from 'lucide-react'; import { API_BASE } from '@homaroma/types'; +import { getAuthHeaders } from '../../utils/auth'; import ProfitabilityHeaderTabs from './ProfitabilityHeaderTabs'; function fmtMoney(val: number | null | undefined): string { @@ -110,7 +111,9 @@ export default function CostProfitabilityMatrixPage() { sortBy, }); - const res = await fetch(`${API_BASE}/profitability/matrix?${params.toString()}`); + const res = await fetch(`${API_BASE}/profitability/matrix?${params.toString()}`, { + headers: getAuthHeaders(), + }); if (!res.ok) throw new Error(`HTTP error ${res.status}`); const json = await res.json(); setData(json); diff --git a/apps/admin/src/pages/profitability/MrpPlanningPage.tsx b/apps/admin/src/pages/profitability/MrpPlanningPage.tsx index 2123110..027791b 100644 --- a/apps/admin/src/pages/profitability/MrpPlanningPage.tsx +++ b/apps/admin/src/pages/profitability/MrpPlanningPage.tsx @@ -10,6 +10,7 @@ import { TrendingUp, } from 'lucide-react'; import { API_BASE } from '@homaroma/types'; +import { getAuthHeaders } from '../../utils/auth'; import ProfitabilityHeaderTabs from './ProfitabilityHeaderTabs'; import DateRangeSelector, { type DateFilterState } from './DateRangeSelector'; @@ -92,7 +93,9 @@ export default function MrpPlanningPage() { ...(dateFilter.endDate ? { endDate: dateFilter.endDate } : {}), }); - const res = await fetch(`${API_BASE}/profitability/mrp?${params.toString()}`); + const res = await fetch(`${API_BASE}/profitability/mrp?${params.toString()}`, { + headers: getAuthHeaders(), + }); if (!res.ok) throw new Error(`HTTP error ${res.status}`); const json = await res.json(); setData(json); diff --git a/apps/admin/src/pages/profitability/OmnichannelMarginPage.tsx b/apps/admin/src/pages/profitability/OmnichannelMarginPage.tsx index 608795a..b0f7ba7 100644 --- a/apps/admin/src/pages/profitability/OmnichannelMarginPage.tsx +++ b/apps/admin/src/pages/profitability/OmnichannelMarginPage.tsx @@ -12,6 +12,7 @@ import { ShieldCheck, } from 'lucide-react'; import { API_BASE } from '@homaroma/types'; +import { getAuthHeaders } from '../../utils/auth'; import ProfitabilityHeaderTabs from './ProfitabilityHeaderTabs'; import DateRangeSelector, { type DateFilterState } from './DateRangeSelector'; @@ -121,7 +122,9 @@ export default function OmnichannelMarginPage() { ...(dateFilter.endDate ? { endDate: dateFilter.endDate } : {}), }); - const res = await fetch(`${API_BASE}/profitability/omnichannel?${params.toString()}`); + const res = await fetch(`${API_BASE}/profitability/omnichannel?${params.toString()}`, { + headers: getAuthHeaders(), + }); if (!res.ok) throw new Error(`HTTP error ${res.status}`); const json = await res.json(); setData(json);