This commit is contained in:
Your Name committed 2026-08-09 01:49:11 -04:00
1 parent a6661f946f
commit 85a0f984eb
4 files changed
+546 -447

No files matched your search

+2
View File
@@ -45,6 +45,7 @@ import MediaLibraryPage from './pages/MediaLibraryPage'
import ContactMessagesPage from './pages/ContactMessagesPage' import ContactMessagesPage from './pages/ContactMessagesPage'
import ProductAttributesPage from './pages/ProductAttributesPage' import ProductAttributesPage from './pages/ProductAttributesPage'
import TiktokPriceSimulatorPage from './pages/TiktokPriceSimulatorPage' import TiktokPriceSimulatorPage from './pages/TiktokPriceSimulatorPage'
import TiktokShopCasePage from './pages/TiktokShopCasePage'
function App() { function App() {
return ( return (
@@ -90,6 +91,7 @@ function App() {
<Route path="/tiktok" element={<TiktokPage />} /> <Route path="/tiktok" element={<TiktokPage />} />
<Route path="/tiktok-analysis" element={<TiktokAnalysisPage />} /> <Route path="/tiktok-analysis" element={<TiktokAnalysisPage />} />
<Route path="/tiktok-price-simulator" element={<TiktokPriceSimulatorPage />} /> <Route path="/tiktok-price-simulator" element={<TiktokPriceSimulatorPage />} />
<Route path="/tiktok-shop-case" element={<TiktokShopCasePage />} />
<Route path="/shopee" element={<ShopeePage />} /> <Route path="/shopee" element={<ShopeePage />} />
<Route path="/shopee/:orderId" element={<ShopeeOrderDetailPage />} /> <Route path="/shopee/:orderId" element={<ShopeeOrderDetailPage />} />
<Route path="/shopee-analytics" element={<ShopeeAnalyticsPage />} /> <Route path="/shopee-analytics" element={<ShopeeAnalyticsPage />} />
+2
View File
@@ -28,6 +28,7 @@ import {
ChevronDown, ChevronDown,
Sparkles, Sparkles,
Calculator, Calculator,
Info,
} from 'lucide-react' } from 'lucide-react'
const MAIN_MENU = [ const MAIN_MENU = [
@@ -53,6 +54,7 @@ const MAIN_MENU = [
{ icon: BarChart3, label: 'TikTok Analytics', to: '/tiktok-analytics' }, { icon: BarChart3, label: 'TikTok Analytics', to: '/tiktok-analytics' },
{ icon: Layers, label: 'TikTok ทุกร้าน', to: '/tiktok-overview' }, { icon: Layers, label: 'TikTok ทุกร้าน', to: '/tiktok-overview' },
{ icon: Calculator, label: 'TikTok Price Simulator', to: '/tiktok-price-simulator' }, { icon: Calculator, label: 'TikTok Price Simulator', to: '/tiktok-price-simulator' },
{ icon: Info, label: 'TikTok Shop Case', to: '/tiktok-shop-case' },
{ icon: ShoppingCart, label: 'Lazada Orders', to: '/lazada-order' }, { icon: ShoppingCart, label: 'Lazada Orders', to: '/lazada-order' },
{ icon: BarChart3, label: 'Lazada Analytics', to: '/lazada-analytics' }, { icon: BarChart3, label: 'Lazada Analytics', to: '/lazada-analytics' },
{ icon: Layers, label: 'Lazada ทุกร้าน', to: '/lazada-overview' }, { icon: Layers, label: 'Lazada ทุกร้าน', to: '/lazada-overview' },
@@ -837,97 +837,6 @@ function BreakEvenAlert() {
export default function TiktokPriceSimulatorPage() { export default function TiktokPriceSimulatorPage() {
const [resetKey, setResetKey] = useState(0) const [resetKey, setResetKey] = useState(0)
const [selectedCase, setSelectedCase] = useState<'case1' | 'case2' | 'case3'>('case1')
const [simBeforeDiscount, setSimBeforeDiscount] = useState(79.00)
const [simDiscountType, setSimDiscountType] = useState<'pct' | 'amount'>('amount')
const [simDiscountVal, setSimDiscountVal] = useState(17.90)
const [simCost, setSimCost] = useState(30.00)
const [simTransPct, setSimTransPct] = useState(3.21)
const [simCommPct, setSimCommPct] = useState(10.70)
const [simGrowthPct, setSimGrowthPct] = useState(7.50)
const [simAffiliatePct, setSimAffiliatePct] = useState(0)
const caseData = {
case1: {
beforeDiscount: 79.00,
shopDiscount: -17.90,
baseAmt: 61.10,
origTrans: -1.96,
origComm: -6.54,
origGrowth: -4.58,
origAffiliate: 0,
origTotalFees: -13.08,
originalPayout: 48.02,
defaultCost: 30.00,
label: 'เคสที่ 1: บิลสินค้า ฿79 (สุทธิ ฿48.02)',
},
case2: {
beforeDiscount: 190.00,
shopDiscount: -20.90,
baseAmt: 169.10,
origTrans: -5.43,
origComm: -18.09,
origGrowth: -12.67,
origAffiliate: 0,
origTotalFees: -36.19,
originalPayout: 132.91,
defaultCost: 80.00,
label: 'เคสที่ 2: บิลสินค้า ฿190 (สุทธิ ฿132.91)',
},
case3: {
beforeDiscount: 190.00,
shopDiscount: -37.81,
baseAmt: 152.19,
origTrans: -4.89,
origComm: -16.28,
origGrowth: -11.40,
origAffiliate: -7.61,
origTotalFees: -40.18,
originalPayout: 112.01,
defaultCost: 70.00,
label: 'เคสที่ 3: บิลสินค้า ฿190 + Affiliate (สุทธิ ฿112.01)',
}
}
const activeCase = caseData[selectedCase]
useEffect(() => {
setSimBeforeDiscount(activeCase.beforeDiscount)
setSimDiscountType('amount')
setSimDiscountVal(Math.abs(activeCase.shopDiscount))
setSimCost(activeCase.defaultCost)
setSimTransPct(3.21)
setSimCommPct(10.70)
setSimGrowthPct(7.50)
setSimAffiliatePct(selectedCase === 'case3' ? 5.00 : 0)
}, [selectedCase])
// Simulated calculations
const simDiscountAmount = simDiscountType === 'pct' ? simBeforeDiscount * (simDiscountVal / 100) : simDiscountVal
const baseAmt = Math.max(0, simBeforeDiscount - simDiscountAmount)
const simTransAmt = baseAmt * (simTransPct / 100)
const simCommAmt = baseAmt * (simCommPct / 100)
const simGrowthAmt = baseAmt * (simGrowthPct / 100)
const simAffiliateAmt = baseAmt * (simAffiliatePct / 100)
const simTotalAmt = simTransAmt + simCommAmt + simGrowthAmt + simAffiliateAmt
const simTotalPct = simTransPct + simCommPct + simGrowthPct + simAffiliatePct
const simPayout = baseAmt - simTotalAmt
const originalPayout = activeCase.originalPayout
const diffVal = simPayout - originalPayout
const diffPct = originalPayout > 0 ? (diffVal / originalPayout) * 100 : 0
// Profit/Margin/ROI Calculations
const origProfit = originalPayout - simCost
const origProfitMargin = activeCase.baseAmt > 0 ? (origProfit / activeCase.baseAmt) * 100 : 0
const origROI = simCost > 0 ? (origProfit / simCost) * 100 : 0
const simProfit = simPayout - simCost
const simProfitMargin = baseAmt > 0 ? (simProfit / baseAmt) * 100 : 0
const simROI = simCost > 0 ? (simProfit / simCost) * 100 : 0
return ( return (
<div className="min-h-screen p-6 md:p-8 max-w-5xl mx-auto animate-fade-in" key={resetKey}> <div className="min-h-screen p-6 md:p-8 max-w-5xl mx-auto animate-fade-in" key={resetKey}>
@@ -948,10 +857,6 @@ export default function TiktokPriceSimulatorPage() {
<button <button
onClick={() => { onClick={() => {
setResetKey(k => k + 1) setResetKey(k => k + 1)
setSimTransPct(3.21)
setSimCommPct(10.70)
setSimGrowthPct(7.50)
setSimAffiliatePct(selectedCase === 'case3' ? 5.00 : 0)
}} }}
className="btn-ghost flex items-center gap-2 text-xs shrink-0" className="btn-ghost flex items-center gap-2 text-xs shrink-0"
title="รีเซ็ตทุกค่า" title="รีเซ็ตทุกค่า"
@@ -1030,358 +935,6 @@ export default function TiktokPriceSimulatorPage() {
ถ้าแคมเปญไหนบังคับให้ขาดทุน → อย่าเข้า หรือส่งเฉพาะ SKU ที่มี Buffer สูงพอเท่านั้น ถ้าแคมเปญไหนบังคับให้ขาดทุน → อย่าเข้า หรือส่งเฉพาะ SKU ที่มี Buffer สูงพอเท่านั้น
</p> </p>
</div> </div>
{/* Real Payout Case Study Example */}
<div className="admin-card border-white/10 mt-6 animate-fade-in">
<div className="flex items-center justify-between mb-4 flex-wrap gap-4 border-b border-white/5 pb-4">
<div className="flex items-center gap-3">
<Info className="w-5 h-5 text-cyan-glow" />
<h2 className="text-lg font-bold text-white">กรณีศึกษา & เครื่องมือจำลองค่าธรรมเนียมจริง (TikTok Shop)</h2>
</div>
<div className="flex items-center gap-2">
<div className="flex p-1 bg-night-900 border border-white/10 rounded-lg">
<button
type="button"
className={`px-3 py-1.5 text-xs font-medium rounded-md transition-all ${selectedCase === 'case1' ? 'bg-cyan-glow/20 text-cyan-glow' : 'text-slate-400 hover:text-white'}`}
onClick={() => setSelectedCase('case1')}
>
ตัวอย่างที่ 1 (ยอด ฿79)
</button>
<button
type="button"
className={`px-3 py-1.5 text-xs font-medium rounded-md transition-all ${selectedCase === 'case2' ? 'bg-cyan-glow/20 text-cyan-glow' : 'text-slate-400 hover:text-white'}`}
onClick={() => setSelectedCase('case2')}
>
ตัวอย่างที่ 2 (ยอด ฿190)
</button>
<button
type="button"
className={`px-3 py-1.5 text-xs font-medium rounded-md transition-all ${selectedCase === 'case3' ? 'bg-cyan-glow/20 text-cyan-glow' : 'text-slate-400 hover:text-white'}`}
onClick={() => setSelectedCase('case3')}
>
ตัวอย่างที่ 3 (ยอด ฿190 + Affiliate)
</button>
</div>
<button
onClick={() => {
setSimTransPct(3.21)
setSimCommPct(10.70)
setSimGrowthPct(7.50)
setSimAffiliatePct(selectedCase === 'case3' ? 5.00 : 0)
}}
className="btn-ghost text-xs py-1.5 px-3 rounded border border-white/10"
>
ใช้ค่าตั้งต้นตัวอย่าง
</button>
</div>
</div>
<p className="text-xs text-slate-400 mb-2 font-medium">
รายละเอียดบิลจริงดั้งเดิมของ {selectedCase === 'case1' ? 'ตัวอย่างที่ 1' : selectedCase === 'case2' ? 'ตัวอย่างที่ 2' : 'ตัวอย่างที่ 3'}:
</p>
<div className="grid grid-cols-3 gap-4 p-3 rounded-lg bg-night-800/40 border border-white/5 text-xs mb-6 opacity-80">
<div>
<span className="text-slate-500 block">ยอดรวมสินค้าก่อนลด</span>
<span className="font-bold text-white font-mono">{fmt(activeCase.beforeDiscount)}</span>
</div>
<div>
<span className="text-slate-500 block">ส่วนลดจากร้านค้า (ลดไป %)</span>
<span className="font-bold text-rose-400 font-mono">
{fmt(activeCase.shopDiscount)} (-{((Math.abs(activeCase.shopDiscount) / activeCase.beforeDiscount) * 100).toFixed(1)}%)
</span>
</div>
<div>
<span className="text-slate-500 block">ยอดรวมหลังหักส่วนลด (ฐานคิดค่าคอม)</span>
<span className="font-bold text-cyan-glow font-mono">{fmt(activeCase.baseAmt)}</span>
</div>
</div>
{/* Simulator controls - Price & Discounts */}
<p className="text-xs text-slate-400 mb-2 font-medium">1. จำลองการตั้งราคา ส่วนลด และต้นทุนสินค้า (ปรับแต่งเองได้):</p>
<div className="mb-4 grid grid-cols-1 sm:grid-cols-3 gap-4 p-4 rounded-xl bg-night-800/40 border border-white/5">
<div>
<label className="block text-xs text-slate-400 font-medium mb-1.5">ราคาขายก่อนลด (List Price)</label>
<div className="flex items-center gap-2">
<input
type="number"
step="1"
min="0"
value={simBeforeDiscount}
onChange={e => setSimBeforeDiscount(parseFloat(e.target.value) || 0)}
className="admin-input w-full text-xs"
/>
<span className="text-xs text-slate-500">฿</span>
</div>
</div>
<div>
<label className="block text-xs text-slate-400 font-medium mb-1.5">ส่วนลดจากร้านค้า (คูปองร้าน)</label>
<div className="flex items-center gap-3">
<div className="flex p-1 bg-night-900 border border-white/10 rounded-lg shrink-0">
<button
type="button"
className={`px-2.5 py-1 text-[10px] font-medium rounded transition-all ${simDiscountType === 'pct' ? 'bg-cyan-glow/20 text-cyan-glow' : 'text-slate-400 hover:text-white'}`}
onClick={() => setSimDiscountType('pct')}
>
%
</button>
<button
type="button"
className={`px-2.5 py-1 text-[10px] font-medium rounded transition-all ${simDiscountType === 'amount' ? 'bg-cyan-glow/20 text-cyan-glow' : 'text-slate-400 hover:text-white'}`}
onClick={() => setSimDiscountType('amount')}
>
฿
</button>
</div>
<input
type="number"
step="0.1"
min="0"
value={simDiscountVal}
onChange={e => setSimDiscountVal(parseFloat(e.target.value) || 0)}
className="admin-input w-full text-xs"
/>
<span className="text-xs text-slate-500">{simDiscountType === 'pct' ? '%' : '฿'}</span>
</div>
</div>
<div>
<label className="block text-xs text-slate-400 font-medium mb-1.5">ต้นทุนสินค้า (Cost)</label>
<div className="flex items-center gap-2">
<input
type="number"
step="1"
min="0"
value={simCost}
onChange={e => setSimCost(parseFloat(e.target.value) || 0)}
className="admin-input w-full text-xs"
/>
<span className="text-xs text-slate-500">฿</span>
</div>
</div>
</div>
{/* Simulator controls - Fees */}
<p className="text-xs text-slate-400 mb-2 font-medium">2. จำลองการปรับเปลี่ยนอัตราค่าธรรมเนียม (%):</p>
<div className="mb-6 grid grid-cols-2 sm:grid-cols-4 gap-4 p-4 rounded-xl bg-night-800/40 border border-white/5">
<div>
<label className="block text-xs text-slate-400 font-medium mb-1.5">Transaction (%)</label>
<div className="flex items-center gap-2">
<input
type="number"
step="0.01"
min="0"
max="100"
value={simTransPct}
onChange={e => setSimTransPct(parseFloat(e.target.value) || 0)}
className="admin-input w-full text-xs"
/>
<span className="text-xs text-slate-500">%</span>
</div>
</div>
<div>
<label className="block text-xs text-slate-400 font-medium mb-1.5">ค่าคอม TikTok (%)</label>
<div className="flex items-center gap-2">
<input
type="number"
step="0.01"
min="0"
max="100"
value={simCommPct}
onChange={e => setSimCommPct(parseFloat(e.target.value) || 0)}
className="admin-input w-full text-xs"
/>
<span className="text-xs text-slate-500">%</span>
</div>
</div>
<div>
<label className="block text-xs text-slate-400 font-medium mb-1.5">สนับสนุนเติบโต (%)</label>
<div className="flex items-center gap-2">
<input
type="number"
step="0.01"
min="0"
max="100"
value={simGrowthPct}
onChange={e => setSimGrowthPct(parseFloat(e.target.value) || 0)}
className="admin-input w-full text-xs"
/>
<span className="text-xs text-slate-500">%</span>
</div>
</div>
<div>
<label className="block text-xs text-slate-400 font-medium mb-1.5">ค่าคอมแอฟฟิลิเอต (%)</label>
<div className="flex items-center gap-2">
<input
type="number"
step="0.01"
min="0"
max="100"
value={simAffiliatePct}
onChange={e => setSimAffiliatePct(parseFloat(e.target.value) || 0)}
className="admin-input w-full text-xs"
/>
<span className="text-xs text-slate-500">%</span>
</div>
</div>
</div>
{/* Side-by-side comparison tables */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
{/* ก่อนปรับ (ค่าธรรมเนียมจากบิลตัวอย่างจริง) */}
<div className="rounded-xl bg-night-800/30 border border-white/5 p-4 space-y-4">
<h3 className="text-xs font-bold text-slate-400 uppercase tracking-wider border-b border-white/5 pb-2 flex justify-between">
<span>ก่อนปรับ (บิลดั้งเดิม)</span>
<span className="text-slate-500">รวม {((Math.abs(activeCase.origTotalFees) / activeCase.baseAmt) * 100).toFixed(2)}%</span>
</h3>
<div className="space-y-2 text-xs">
<div className="flex justify-between text-slate-400">
<span>ยอดรวมสินค้าก่อนลด</span>
<span className="font-mono">{fmt(activeCase.beforeDiscount)}</span>
</div>
<div className="flex justify-between text-slate-400">
<span>ส่วนลดจากร้านค้า</span>
<span className="font-mono text-rose-400">{fmt(activeCase.shopDiscount)}</span>
</div>
<div className="flex justify-between border-t border-white/5 pt-1.5 font-medium text-slate-300">
<span>ยอดสินค้าสุทธิ (ฐานคิดคอม)</span>
<span>{fmt(activeCase.baseAmt)}</span>
</div>
<div className="flex justify-between pl-3 text-slate-500">
<span>- ค่าคำสั่งซื้อ (Transaction 3.21%)</span>
<span className="font-mono text-rose-400">{fmt(activeCase.origTrans)}</span>
</div>
<div className="flex justify-between pl-3 text-slate-500">
<span>- ค่าคอม TikTok Shop (10.70%)</span>
<span className="font-mono text-rose-400">{fmt(activeCase.origComm)}</span>
</div>
<div className="flex justify-between pl-3 text-slate-500">
<span>- ค่าสนับสนุนการเติบโต (7.50%)</span>
<span className="font-mono text-rose-400">{fmt(activeCase.origGrowth)}</span>
</div>
{activeCase.origAffiliate !== 0 && (
<div className="flex justify-between pl-3 text-slate-500">
<span>- ค่าคอมแอฟฟิลิเอต (5.00%)</span>
<span className="font-mono text-rose-400">{fmt(activeCase.origAffiliate)}</span>
</div>
)}
<div className="flex justify-between border-t border-white/5 pt-1.5 font-medium text-slate-300">
<span>รวมค่าธรรมเนียมโดนหัก</span>
<span className="font-mono text-rose-400">{fmt(activeCase.origTotalFees)}</span>
</div>
<div className="flex justify-between border-t border-white/5 pt-2 font-bold text-white text-sm">
<span>ยอดเงินโอนเข้าบัญชีสุทธิ</span>
<span className="font-mono text-cyan-glow">{fmt(activeCase.originalPayout)}</span>
</div>
<div className="flex justify-between border-t border-white/5 pt-1.5 text-slate-400">
<span>- ต้นทุนสินค้า (Cost)</span>
<span className="font-mono text-rose-400">฿-{simCost.toFixed(2)}</span>
</div>
<div className="flex justify-between border-t border-white/5 pt-2 font-bold text-white text-sm">
<span>กำไรสุทธิ (Net Profit)</span>
<span className={`font-mono ${origProfit >= 0 ? 'text-green-400' : 'text-rose-400'}`}>
{origProfit >= 0 ? '' : '-'}฿{Math.abs(origProfit).toFixed(2)}
</span>
</div>
<div className="flex justify-between text-slate-400 pl-3">
<span>กำไรต่อยอดขาย (Margin %)</span>
<span className={`font-mono ${origProfit >= 0 ? 'text-green-400' : 'text-rose-400'}`}>
{origProfitMargin.toFixed(1)}%
</span>
</div>
<div className="flex justify-between text-slate-400 pl-3">
<span>กำไรต่อทุน (ROI %)</span>
<span className={`font-mono ${origProfit >= 0 ? 'text-green-400' : 'text-rose-400'}`}>
{origROI.toFixed(1)}%
</span>
</div>
</div>
</div>
{/* หลังปรับ (จำลองการปรับค่าธรรมเนียม) */}
<div className="rounded-xl bg-cyan-glow/5 border border-cyan-glow/20 p-4 space-y-4">
<h3 className="text-xs font-bold text-cyan-glow uppercase tracking-wider border-b border-cyan-glow/10 pb-2 flex justify-between">
<span>หลังปรับ (ผลการจำลองใหม่)</span>
<span>รวม {simTotalPct.toFixed(2)}%</span>
</h3>
<div className="space-y-2 text-xs">
<div className="flex justify-between text-slate-400">
<span>ยอดรวมสินค้าก่อนลด</span>
<span className="font-mono">{fmt(simBeforeDiscount)}</span>
</div>
<div className="flex justify-between text-slate-400">
<span>ส่วนลดจากร้านค้า</span>
<span className="font-mono text-rose-400">
-{fmt(simDiscountAmount)} {simDiscountType === 'pct' && `(${simDiscountVal}%)`}
</span>
</div>
<div className="flex justify-between border-t border-cyan-glow/10 pt-1.5 font-medium text-slate-300">
<span>ยอดสินค้าสุทธิ (ฐานคิดคอม)</span>
<span className="font-mono text-cyan-glow">{fmt(baseAmt)}</span>
</div>
<div className="flex justify-between pl-3 text-slate-500">
<span>- ค่าคำสั่งซื้อ ({simTransPct.toFixed(2)}%)</span>
<span className="font-mono text-rose-400">฿-{simTransAmt.toFixed(2)}</span>
</div>
<div className="flex justify-between pl-3 text-slate-500">
<span>- ค่าคอม TikTok Shop ({simCommPct.toFixed(2)}%)</span>
<span className="font-mono text-rose-400">฿-{simCommAmt.toFixed(2)}</span>
</div>
<div className="flex justify-between pl-3 text-slate-500">
<span>- ค่าสนับสนุนการเติบโต ({simGrowthPct.toFixed(2)}%)</span>
<span className="font-mono text-rose-400">฿-{simGrowthAmt.toFixed(2)}</span>
</div>
{simAffiliatePct > 0 && (
<div className="flex justify-between pl-3 text-slate-500">
<span>- ค่าคอมคอมแอฟฟิลิเอต ({simAffiliatePct.toFixed(2)}%)</span>
<span className="font-mono text-rose-400">฿-{simAffiliateAmt.toFixed(2)}</span>
</div>
)}
<div className="flex justify-between border-t border-cyan-glow/10 pt-1.5 font-medium text-slate-300">
<span>รวมค่าธรรมเนียมโดนหัก</span>
<span className="font-mono text-rose-400">฿-{simTotalAmt.toFixed(2)}</span>
</div>
<div className="flex justify-between border-t border-cyan-glow/10 pt-2 font-bold text-white text-sm">
<span>ยอดเงินโอนเข้าบัญชีสุทธิ</span>
<span className="font-mono text-cyan-glow">฿{simPayout.toFixed(2)}</span>
</div>
<div className="flex justify-between border-t border-cyan-glow/10 pt-1.5 text-slate-400">
<span>- ต้นทุนสินค้า (Cost)</span>
<span className="font-mono text-rose-400">฿-{simCost.toFixed(2)}</span>
</div>
<div className="flex justify-between border-t border-cyan-glow/10 pt-2 font-bold text-white text-sm">
<span>กำไรสุทธิ (Net Profit)</span>
<span className={`font-mono ${simProfit >= 0 ? 'text-green-400' : 'text-rose-400'}`}>
{simProfit >= 0 ? '' : '-'}฿{Math.abs(simProfit).toFixed(2)}
</span>
</div>
<div className="flex justify-between text-slate-400 pl-3">
<span>กำไรต่อยอดขาย (Margin %)</span>
<span className={`font-mono ${simProfit >= 0 ? 'text-green-400' : 'text-rose-400'}`}>
{simProfitMargin.toFixed(1)}%
</span>
</div>
<div className="flex justify-between text-slate-400 pl-3">
<span>กำไรต่อทุน (ROI %)</span>
<span className={`font-mono ${simProfit >= 0 ? 'text-green-400' : 'text-rose-400'}`}>
{simROI.toFixed(1)}%
</span>
</div>
</div>
</div>
</div>
{/* Difference comparison status card */}
<div className={`mt-6 rounded-xl p-4 flex items-center justify-between text-xs border ${diffVal >= 0 ? 'bg-green-500/10 border-green-500/30 text-green-400' : 'bg-rose-500/10 border-rose-500/30 text-rose-400'}`}>
<div className="flex items-center gap-2">
<Info className="w-4 h-4" />
<span className="font-medium">
{diffVal >= 0
? `ยอดรับเงินเพิ่มขึ้น ฿${diffVal.toFixed(2)} จากโครงสร้างธรรมเนียมใหม่`
: `ยอดเงินโอนเข้าบัญชีสุทธิจะต่างไป ฿${diffVal.toFixed(2)} (${diffVal >= 0 ? '+' : ''}${diffPct.toFixed(1)}%) เมื่อเทียบกับบิลจริงดั้งเดิม`}
</span>
</div>
<span className="font-bold font-mono text-sm">{diffVal >= 0 ? '+' : ''}฿{diffVal.toFixed(2)}</span>
</div>
</div>
</div> </div>
) )
} }
+542
View File
@@ -0,0 +1,542 @@
import { useState, useEffect } from 'react'
import {
Calculator,
Info,
RefreshCw
} from 'lucide-react'
function fmt(val: number) {
return '฿' + val.toLocaleString('th-TH', { minimumFractionDigits: 2, maximumFractionDigits: 2 })
}
export default function TiktokShopCasePage() {
const [resetKey, setResetKey] = useState(0)
const [selectedCase, setSelectedCase] = useState<'case1' | 'case2' | 'case3'>('case1')
const [simBeforeDiscount, setSimBeforeDiscount] = useState(79.00)
const [discounts, setDiscounts] = useState<Array<{ type: 'pct' | 'amount'; value: number }>>([
{ type: 'amount', value: 17.90 },
{ type: 'amount', value: 0 },
{ type: 'amount', value: 0 },
])
const [simCost, setSimCost] = useState(30.00)
const [simTransPct, setSimTransPct] = useState(3.21)
const [simCommPct, setSimCommPct] = useState(10.70)
const [simGrowthPct, setSimGrowthPct] = useState(7.50)
const [simAffiliatePct, setSimAffiliatePct] = useState(0)
const caseData = {
case1: {
beforeDiscount: 79.00,
shopDiscount: -17.90,
baseAmt: 61.10,
origTrans: -1.96,
origComm: -6.54,
origGrowth: -4.58,
origAffiliate: 0,
origTotalFees: -13.08,
originalPayout: 48.02,
defaultCost: 30.00,
label: 'เคสที่ 1: บิลสินค้า ฿79 (สุทธิ ฿48.02)',
},
case2: {
beforeDiscount: 190.00,
shopDiscount: -20.90,
baseAmt: 169.10,
origTrans: -5.43,
origComm: -18.09,
origGrowth: -12.67,
origAffiliate: 0,
origTotalFees: -36.19,
originalPayout: 132.91,
defaultCost: 80.00,
label: 'เคสที่ 2: บิลสินค้า ฿190 (สุทธิ ฿132.91)',
},
case3: {
beforeDiscount: 190.00,
shopDiscount: -37.81,
baseAmt: 152.19,
origTrans: -4.89,
origComm: -16.28,
origGrowth: -11.40,
origAffiliate: -7.61,
origTotalFees: -40.18,
originalPayout: 112.01,
defaultCost: 70.00,
label: 'เคสที่ 3: บิลสินค้า ฿190 + Affiliate (สุทธิ ฿112.01)',
}
}
const activeCase = caseData[selectedCase]
useEffect(() => {
setSimBeforeDiscount(activeCase.beforeDiscount)
setDiscounts([
{ type: 'amount', value: Math.abs(activeCase.shopDiscount) },
{ type: 'amount', value: 0 },
{ type: 'amount', value: 0 },
])
setSimCost(activeCase.defaultCost)
setSimTransPct(3.21)
setSimCommPct(10.70)
setSimGrowthPct(7.50)
setSimAffiliatePct(selectedCase === 'case3' ? 5.00 : 0)
}, [selectedCase])
// Simulated calculations
// Deduct discounts. Let's make it cumulative based on the original list price:
const simDiscountAmount = discounts.reduce((sum, d) => {
const amt = d.type === 'pct' ? simBeforeDiscount * (d.value / 100) : d.value
return sum + amt
}, 0)
const baseAmt = Math.max(0, simBeforeDiscount - simDiscountAmount)
const simTransAmt = baseAmt * (simTransPct / 100)
const simCommAmt = baseAmt * (simCommPct / 100)
const simGrowthAmt = baseAmt * (simGrowthPct / 100)
const simAffiliateAmt = baseAmt * (simAffiliatePct / 100)
const simTotalAmt = simTransAmt + simCommAmt + simGrowthAmt + simAffiliateAmt
const simTotalPct = simTransPct + simCommPct + simGrowthPct + simAffiliatePct
const simPayout = baseAmt - simTotalAmt
const originalPayout = activeCase.originalPayout
const diffVal = simPayout - originalPayout
const diffPct = originalPayout > 0 ? (diffVal / originalPayout) * 100 : 0
// Profit/Margin/ROI Calculations
const origProfit = originalPayout - simCost
const origProfitMargin = activeCase.baseAmt > 0 ? (origProfit / activeCase.baseAmt) * 100 : 0
const origROI = simCost > 0 ? (origProfit / simCost) * 100 : 0
const simProfit = simPayout - simCost
const simProfitMargin = baseAmt > 0 ? (simProfit / baseAmt) * 100 : 0
const simROI = simCost > 0 ? (simProfit / simCost) * 100 : 0
return (
<div className="min-h-screen p-6 md:p-8 max-w-5xl mx-auto animate-fade-in" key={resetKey}>
{/* Page header */}
<div className="flex items-start justify-between mb-8 gap-4">
<div>
<div className="flex items-center gap-3 mb-2">
<div className="w-10 h-10 rounded-xl bg-cyan-glow/10 border border-cyan-glow/20 flex items-center justify-center">
<Calculator className="w-5 h-5 text-cyan-glow" />
</div>
<h1 className="text-2xl font-bold text-white tracking-tight">TikTok Shop Case</h1>
</div>
<p className="text-sm text-slate-500 max-w-2xl">
ศึกษาโครงสร้างบิลรับเงินจริงจากระบบ TikTok Shop พร้อมทั้งจำลองคำนวณราคาขาย, คูปองส่วนลดร้านค้า, ต้นทุน และประเมินสถิติกำไร & ROI ก่อนขายจริง
</p>
</div>
<button
onClick={() => {
setResetKey(k => k + 1)
setSimTransPct(3.21)
setSimCommPct(10.70)
setSimGrowthPct(7.50)
setSimAffiliatePct(selectedCase === 'case3' ? 5.00 : 0)
}}
className="btn-ghost flex items-center gap-2 text-xs shrink-0"
title="รีเซ็ตทุกค่า"
>
<RefreshCw className="w-4 h-4" />
Reset
</button>
</div>
{/* Real Payout Case Study Example */}
<div className="admin-card border-white/10 animate-fade-in">
<div className="flex items-center justify-between mb-4 flex-wrap gap-4 border-b border-white/5 pb-4">
<div className="flex items-center gap-3">
<Info className="w-5 h-5 text-cyan-glow" />
<h2 className="text-lg font-bold text-white">กรณีศึกษา & เครื่องมือจำลองค่าธรรมเนียมจริง</h2>
</div>
<div className="flex items-center gap-2">
<div className="flex p-1 bg-night-900 border border-white/10 rounded-lg">
<button
type="button"
className={`px-3 py-1.5 text-xs font-medium rounded-md transition-all ${selectedCase === 'case1' ? 'bg-cyan-glow/20 text-cyan-glow' : 'text-slate-400 hover:text-white'}`}
onClick={() => setSelectedCase('case1')}
>
ตัวอย่างที่ 1 (ยอด ฿79)
</button>
<button
type="button"
className={`px-3 py-1.5 text-xs font-medium rounded-md transition-all ${selectedCase === 'case2' ? 'bg-cyan-glow/20 text-cyan-glow' : 'text-slate-400 hover:text-white'}`}
onClick={() => setSelectedCase('case2')}
>
ตัวอย่างที่ 2 (ยอด ฿190)
</button>
<button
type="button"
className={`px-3 py-1.5 text-xs font-medium rounded-md transition-all ${selectedCase === 'case3' ? 'bg-cyan-glow/20 text-cyan-glow' : 'text-slate-400 hover:text-white'}`}
onClick={() => setSelectedCase('case3')}
>
ตัวอย่างที่ 3 (ยอด ฿190 + Affiliate)
</button>
</div>
<button
onClick={() => {
setSimTransPct(3.21)
setSimCommPct(10.70)
setSimGrowthPct(7.50)
setSimAffiliatePct(selectedCase === 'case3' ? 5.00 : 0)
}}
className="btn-ghost text-xs py-1.5 px-3 rounded border border-white/10"
>
ใช้ค่าตั้งต้นตัวอย่าง
</button>
</div>
</div>
<p className="text-xs text-slate-400 mb-2 font-medium">
รายละเอียดบิลจริงดั้งเดิมของ {selectedCase === 'case1' ? 'ตัวอย่างที่ 1' : selectedCase === 'case2' ? 'ตัวอย่างที่ 2' : 'ตัวอย่างที่ 3'}:
</p>
<div className="grid grid-cols-3 gap-4 p-3 rounded-lg bg-night-800/40 border border-white/5 text-xs mb-6 opacity-80">
<div>
<span className="text-slate-500 block">ยอดรวมสินค้าก่อนลด</span>
<span className="font-bold text-white font-mono">{fmt(activeCase.beforeDiscount)}</span>
</div>
<div>
<span className="text-slate-500 block">ส่วนลดจากร้านค้า (ลดไป %)</span>
<span className="font-bold text-rose-400 font-mono">
{fmt(activeCase.shopDiscount)} (-{((Math.abs(activeCase.shopDiscount) / activeCase.beforeDiscount) * 100).toFixed(1)}%)
</span>
</div>
<div>
<span className="text-slate-500 block">ยอดรวมหลังหักส่วนลด (ฐานคิดค่าคอม)</span>
<span className="font-bold text-cyan-glow font-mono">{fmt(activeCase.baseAmt)}</span>
</div>
</div>
{/* Simulator controls - Price & Discounts */}
<p className="text-xs text-slate-400 mb-2 font-medium">1. จำลองการตั้งราคา ส่วนลด และต้นทุนสินค้า (ปรับแต่งเองได้):</p>
<div className="mb-4 grid grid-cols-1 sm:grid-cols-3 gap-4 p-4 rounded-xl bg-night-800/40 border border-white/5">
<div className="space-y-4">
<div>
<label className="block text-xs text-slate-400 font-medium mb-1.5">ราคาขายก่อนลด (List Price)</label>
<div className="flex items-center gap-2">
<input
type="number"
step="1"
min="0"
value={simBeforeDiscount}
onChange={e => setSimBeforeDiscount(parseFloat(e.target.value) || 0)}
className="admin-input w-full text-xs"
/>
<span className="text-xs text-slate-500">฿</span>
</div>
</div>
<div>
<label className="block text-xs text-slate-400 font-medium mb-1.5">ต้นทุนสินค้า (Cost)</label>
<div className="flex items-center gap-2 mb-2">
<input
type="number"
step="1"
min="0"
value={simCost}
onChange={e => setSimCost(parseFloat(e.target.value) || 0)}
className="admin-input w-full text-xs"
/>
<span className="text-xs text-slate-500">฿</span>
</div>
<div className="flex gap-2">
{[20, 45, 50].map(val => (
<button
key={val}
type="button"
onClick={() => setSimCost(val)}
className={`px-2.5 py-1 text-[10px] font-medium rounded border transition-all ${simCost === val ? 'bg-cyan-glow/20 text-cyan-glow border-cyan-glow/30' : 'bg-night-900 text-slate-400 border-white/10 hover:text-white hover:border-white/20'}`}
>
฿{val}
</button>
))}
</div>
</div>
</div>
<div className="space-y-3 sm:col-span-2">
<label className="block text-xs text-slate-400 font-medium">ส่วนลดจากร้านค้า (คูปองร้านค้า 1-3)</label>
<div className="grid grid-cols-1 md:grid-cols-3 gap-3">
{discounts.map((discount, index) => (
<div key={index} className="flex flex-col gap-2 p-2.5 rounded-lg bg-night-900/60 border border-white/5">
<span className="text-[10px] text-slate-500 font-bold">คูปองที่ #{index + 1}</span>
<div className="flex items-center gap-2">
<div className="flex p-0.5 bg-night-950 border border-white/10 rounded-md shrink-0">
<button
type="button"
className={`px-1.5 py-0.5 text-[9px] font-medium rounded transition-all ${discount.type === 'pct' ? 'bg-cyan-glow/20 text-cyan-glow' : 'text-slate-400 hover:text-white'}`}
onClick={() => {
const updated = [...discounts]
updated[index] = { ...updated[index], type: 'pct' }
setDiscounts(updated)
}}
>
%
</button>
<button
type="button"
className={`px-1.5 py-0.5 text-[9px] font-medium rounded transition-all ${discount.type === 'amount' ? 'bg-cyan-glow/20 text-cyan-glow' : 'text-slate-400 hover:text-white'}`}
onClick={() => {
const updated = [...discounts]
updated[index] = { ...updated[index], type: 'amount' }
setDiscounts(updated)
}}
>
฿
</button>
</div>
<input
type="number"
step="0.1"
min="0"
value={discount.value || ''}
onChange={e => {
const updated = [...discounts]
updated[index] = { ...updated[index], value: parseFloat(e.target.value) || 0 }
setDiscounts(updated)
}}
placeholder="0"
className="admin-input w-full text-xs p-1"
/>
</div>
</div>
))}
</div>
</div>
</div>
{/* Simulator controls - Fees */}
<p className="text-xs text-slate-400 mb-2 font-medium">2. จำลองการปรับเปลี่ยนอัตราค่าธรรมเนียม (%):</p>
<div className="mb-6 grid grid-cols-2 sm:grid-cols-4 gap-4 p-4 rounded-xl bg-night-800/40 border border-white/5">
<div>
<label className="block text-xs text-slate-400 font-medium mb-1.5">Transaction (%)</label>
<div className="flex items-center gap-2">
<input
type="number"
step="0.01"
min="0"
max="100"
value={simTransPct}
onChange={e => setSimTransPct(parseFloat(e.target.value) || 0)}
className="admin-input w-full text-xs"
/>
<span className="text-xs text-slate-500">%</span>
</div>
</div>
<div>
<label className="block text-xs text-slate-400 font-medium mb-1.5">ค่าคอม TikTok (%)</label>
<div className="flex items-center gap-2">
<input
type="number"
step="0.01"
min="0"
max="100"
value={simCommPct}
onChange={e => setSimCommPct(parseFloat(e.target.value) || 0)}
className="admin-input w-full text-xs"
/>
<span className="text-xs text-slate-500">%</span>
</div>
</div>
<div>
<label className="block text-xs text-slate-400 font-medium mb-1.5">สนับสนุนเติบโต (%)</label>
<div className="flex items-center gap-2">
<input
type="number"
step="0.01"
min="0"
max="100"
value={simGrowthPct}
onChange={e => setSimGrowthPct(parseFloat(e.target.value) || 0)}
className="admin-input w-full text-xs"
/>
<span className="text-xs text-slate-500">%</span>
</div>
</div>
<div>
<label className="block text-xs text-slate-400 font-medium mb-1.5">ค่าคอมแอฟฟิลิเอต (%)</label>
<div className="flex items-center gap-2">
<input
type="number"
step="0.01"
min="0"
max="100"
value={simAffiliatePct}
onChange={e => setSimAffiliatePct(parseFloat(e.target.value) || 0)}
className="admin-input w-full text-xs"
/>
<span className="text-xs text-slate-500">%</span>
</div>
</div>
</div>
{/* Side-by-side comparison tables */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
{/* ก่อนปรับ (ค่าธรรมเนียมจากบิลตัวอย่างจริง) */}
<div className="rounded-xl bg-night-800/30 border border-white/5 p-4 space-y-4">
<h3 className="text-xs font-bold text-slate-400 uppercase tracking-wider border-b border-white/5 pb-2 flex justify-between">
<span>ก่อนปรับ (บิลดั้งเดิม)</span>
<span className="text-slate-500">รวม {((Math.abs(activeCase.origTotalFees) / activeCase.baseAmt) * 100).toFixed(2)}%</span>
</h3>
<div className="space-y-2 text-xs">
<div className="flex justify-between text-slate-400">
<span>ยอดรวมสินค้าก่อนลด</span>
<span className="font-mono">{fmt(activeCase.beforeDiscount)}</span>
</div>
<div className="flex justify-between text-slate-400">
<span>ส่วนลดจากร้านค้า</span>
<span className="font-mono text-rose-400">{fmt(activeCase.shopDiscount)}</span>
</div>
<div className="flex justify-between border-t border-white/5 pt-1.5 font-medium text-slate-300">
<span>ยอดสินค้าสุทธิ (ฐานคิดคอม)</span>
<span>{fmt(activeCase.baseAmt)}</span>
</div>
<div className="flex justify-between pl-3 text-slate-500">
<span>- ค่าคำสั่งซื้อ (Transaction 3.21%)</span>
<span className="font-mono text-rose-400">{fmt(activeCase.origTrans)}</span>
</div>
<div className="flex justify-between pl-3 text-slate-500">
<span>- ค่าคอม TikTok Shop (10.70%)</span>
<span className="font-mono text-rose-400">{fmt(activeCase.origComm)}</span>
</div>
<div className="flex justify-between pl-3 text-slate-500">
<span>- ค่าสนับสนุนการเติบโต (7.50%)</span>
<span className="font-mono text-rose-400">{fmt(activeCase.origGrowth)}</span>
</div>
{activeCase.origAffiliate !== 0 && (
<div className="flex justify-between pl-3 text-slate-500">
<span>- ค่าคอมแอฟฟิลิเอต (5.00%)</span>
<span className="font-mono text-rose-400">{fmt(activeCase.origAffiliate)}</span>
</div>
)}
<div className="flex justify-between border-t border-white/5 pt-1.5 font-medium text-slate-300">
<span>รวมค่าธรรมเนียมโดนหัก</span>
<span className="font-mono text-rose-400">{fmt(activeCase.origTotalFees)}</span>
</div>
<div className="flex justify-between border-t border-white/5 pt-2 font-bold text-white text-sm">
<span>ยอดเงินโอนเข้าบัญชีสุทธิ</span>
<span className="font-mono text-cyan-glow">{fmt(activeCase.originalPayout)}</span>
</div>
<div className="flex justify-between border-t border-white/5 pt-1.5 text-slate-400">
<span>- ต้นทุนสินค้า (Cost)</span>
<span className="font-mono text-rose-400">฿-{simCost.toFixed(2)}</span>
</div>
<div className="flex justify-between border-t border-white/5 pt-2 font-bold text-white text-sm">
<span>กำไรสุทธิ (Net Profit)</span>
<span className={`font-mono ${origProfit >= 0 ? 'text-green-400' : 'text-rose-400'}`}>
{origProfit >= 0 ? '' : '-'}฿{Math.abs(origProfit).toFixed(2)}
</span>
</div>
<div className="flex justify-between text-slate-400 pl-3">
<span>กำไรต่อยอดขาย (Margin %)</span>
<span className={`font-mono ${origProfit >= 0 ? 'text-green-400' : 'text-rose-400'}`}>
{origProfitMargin.toFixed(1)}%
</span>
</div>
<div className="flex justify-between text-slate-400 pl-3">
<span>กำไรต่อทุน (ROI %)</span>
<span className={`font-mono ${origProfit >= 0 ? 'text-green-400' : 'text-rose-400'}`}>
{origROI.toFixed(1)}%
</span>
</div>
</div>
</div>
{/* หลังปรับ (จำลองการปรับค่าธรรมเนียม) */}
<div className="rounded-xl bg-cyan-glow/5 border border-cyan-glow/20 p-4 space-y-4">
<h3 className="text-xs font-bold text-cyan-glow uppercase tracking-wider border-b border-cyan-glow/10 pb-2 flex justify-between">
<span>หลังปรับ (ผลการจำลองใหม่)</span>
<span>รวม {simTotalPct.toFixed(2)}%</span>
</h3>
<div className="space-y-2 text-xs">
<div className="flex justify-between text-slate-400">
<span>ยอดรวมสินค้าก่อนลด</span>
<span className="font-mono">{fmt(simBeforeDiscount)}</span>
</div>
<div className="flex justify-between text-slate-400">
<span>ส่วนลดจากร้านค้า (รวม)</span>
<span className="font-mono text-rose-400">
-{fmt(simDiscountAmount)}
</span>
</div>
{discounts.map((d, i) => d.value > 0 ? (
<div key={i} className="flex justify-between text-[10px] text-slate-500 pl-3">
<span>- คูปอง #{i + 1} ({d.type === 'pct' ? `${d.value}%` : `฿${d.value}`})</span>
<span className="font-mono text-rose-400">
-{fmt(d.type === 'pct' ? simBeforeDiscount * (d.value / 100) : d.value)}
</span>
</div>
) : null)}
<div className="flex justify-between border-t border-cyan-glow/10 pt-1.5 font-medium text-slate-300">
<span>ยอดสินค้าสุทธิ (ฐานคิดคอม)</span>
<span className="font-mono text-cyan-glow">{fmt(baseAmt)}</span>
</div>
<div className="flex justify-between pl-3 text-slate-500">
<span>- ค่าคำสั่งซื้อ ({simTransPct.toFixed(2)}%)</span>
<span className="font-mono text-rose-400">฿-{simTransAmt.toFixed(2)}</span>
</div>
<div className="flex justify-between pl-3 text-slate-500">
<span>- ค่าคอม TikTok Shop ({simCommPct.toFixed(2)}%)</span>
<span className="font-mono text-rose-400">฿-{simCommAmt.toFixed(2)}</span>
</div>
<div className="flex justify-between pl-3 text-slate-500">
<span>- ค่าสนับสนุนการเติบโต ({simGrowthPct.toFixed(2)}%)</span>
<span className="font-mono text-rose-400">฿-{simGrowthAmt.toFixed(2)}</span>
</div>
{simAffiliatePct > 0 && (
<div className="flex justify-between pl-3 text-slate-500">
<span>- ค่าคอมคอมแอฟฟิลิเอต ({simAffiliatePct.toFixed(2)}%)</span>
<span className="font-mono text-rose-400">฿-{simAffiliateAmt.toFixed(2)}</span>
</div>
)}
<div className="flex justify-between border-t border-cyan-glow/10 pt-1.5 font-medium text-slate-300">
<span>รวมค่าธรรมเนียมโดนหัก</span>
<span className="font-mono text-rose-400">฿-{simTotalAmt.toFixed(2)}</span>
</div>
<div className="flex justify-between border-t border-cyan-glow/10 pt-2 font-bold text-white text-sm">
<span>ยอดเงินโอนเข้าบัญชีสุทธิ</span>
<span className="font-mono text-cyan-glow">฿{simPayout.toFixed(2)}</span>
</div>
<div className="flex justify-between border-t border-cyan-glow/10 pt-1.5 text-slate-400">
<span>- ต้นทุนสินค้า (Cost)</span>
<span className="font-mono text-rose-400">฿-{simCost.toFixed(2)}</span>
</div>
<div className="flex justify-between border-t border-cyan-glow/10 pt-2 font-bold text-white text-sm">
<span>กำไรสุทธิ (Net Profit)</span>
<span className={`font-mono ${simProfit >= 0 ? 'text-green-400' : 'text-rose-400'}`}>
{simProfit >= 0 ? '' : '-'}฿{Math.abs(simProfit).toFixed(2)}
</span>
</div>
<div className="flex justify-between text-slate-400 pl-3">
<span>กำไรต่อยอดขาย (Margin %)</span>
<span className={`font-mono ${simProfit >= 0 ? 'text-green-400' : 'text-rose-400'}`}>
{simProfitMargin.toFixed(1)}%
</span>
</div>
<div className="flex justify-between text-slate-400 pl-3">
<span>กำไรต่อทุน (ROI %)</span>
<span className={`font-mono ${simProfit >= 0 ? 'text-green-400' : 'text-rose-400'}`}>
{simROI.toFixed(1)}%
</span>
</div>
</div>
</div>
</div>
{/* Difference comparison status card */}
<div className={`mt-6 rounded-xl p-4 flex items-center justify-between text-xs border ${diffVal >= 0 ? 'bg-green-500/10 border-green-500/30 text-green-400' : 'bg-rose-500/10 border-rose-500/30 text-rose-400'}`}>
<div className="flex items-center gap-2">
<Info className="w-4 h-4" />
<span className="font-medium">
{diffVal >= 0
? `ยอดรับเงินเพิ่มขึ้น ฿${diffVal.toFixed(2)} จากโครงสร้างธรรมเนียมใหม่`
: `ยอดเงินโอนเข้าบัญชีสุทธิจะต่างไป ฿${diffVal.toFixed(2)} (${diffVal >= 0 ? '+' : ''}${diffPct.toFixed(1)}%) เมื่อเทียบกับบิลจริงดั้งเดิม`}
</span>
</div>
<span className="font-bold font-mono text-sm">{diffVal >= 0 ? '+' : ''}฿{diffVal.toFixed(2)}</span>
</div>
</div>
</div>
)
}