Lompat ke konten
Home ยป Hitung Biaya Tiktok

Hitung Biaya Tiktok

import React, { useState } from 'react';
import { Calculator, DollarSign, Percent, Package, TrendingUp, AlertCircle, ShoppingBag, ArrowRight } from 'lucide-react';

const formatRp = (value) => {
  if (isNaN(value) || value === null) return 'Rp 0';
  return new Intl.NumberFormat('id-ID', {
    style: 'currency',
    currency: 'IDR',
    minimumFractionDigits: 0,
    maximumFractionDigits: 0
  }).format(value);
};

export default function App() {
  const [activeTab, setActiveTab] = useState('ideal'); // 'ideal' | 'simulasi'

  // Global Inputs
  const [modal, setModal] = useState(50000);
  const [packaging, setPackaging] = useState(2000);
  
  // Fees (Persentase & Flat)
  const [adminPercent, setAdminPercent] = useState(4.0); // Rata-rata biaya admin
  const [adminFlat, setAdminFlat] = useState(2000); // Biaya tetap per pesanan (contoh Rp2000)
  const [affiliatePercent, setAffiliatePercent] = useState(5.0); // Komisi kreator
  const [xtraPercent, setXtraPercent] = useState(3.0); // Gratis ongkir xtra

  // Tab 1 Specific: Hitung Harga Ideal
  const [targetProfit, setTargetProfit] = useState(20000);

  // Tab 2 Specific: Simulasi Keuntungan
  const [sellingPrice, setSellingPrice] = useState(100000);

  // --- CALCULATIONS FOR TAB 1 (Harga Ideal) ---
  const calculateIdealPrice = () => {
    const totalCost = Number(modal) + Number(packaging);
    const totalPercentFee = (Number(adminPercent) + Number(affiliatePercent) + Number(xtraPercent)) / 100;
    const targetGross = totalCost + Number(adminFlat) + Number(targetProfit);

    // Rumus: Harga Jual = (Modal + Biaya Tetap + Target Profit) / (1 - Total Persentase Potongan)
    let idealPrice = 0;
    if (totalPercentFee < 1) {
      idealPrice = targetGross / (1 - totalPercentFee);
    }
    
    const adminCut = idealPrice * (Number(adminPercent) / 100);
    const affiliateCut = idealPrice * (Number(affiliatePercent) / 100);
    const xtraCut = idealPrice * (Number(xtraPercent) / 100);
    const totalPotongan = adminCut + affiliateCut + xtraCut + Number(adminFlat);

    return { idealPrice, totalPotongan, adminCut, affiliateCut, xtraCut };
  };

  // --- CALCULATIONS FOR TAB 2 (Simulasi) ---
  const calculateSimulasi = () => {
    const price = Number(sellingPrice);
    const totalCost = Number(modal) + Number(packaging);
    
    const adminCut = price * (Number(adminPercent) / 100);
    const affiliateCut = price * (Number(affiliatePercent) / 100);
    const xtraCut = price * (Number(xtraPercent) / 100);
    
    const totalPotongan = adminCut + affiliateCut + xtraCut + Number(adminFlat);
    const netProfit = price - totalPotongan - totalCost;
    const profitMargin = price > 0 ? (netProfit / price) * 100 : 0;

    return { netProfit, totalPotongan, profitMargin, adminCut, affiliateCut, xtraCut };
  };

  const idealResult = calculateIdealPrice();
  const simResult = calculateSimulasi();

  const handleFocus = (e) => e.target.select();

  return (
    <div className="min-h-screen bg-slate-50 p-4 md:p-8 font-sans text-slate-800">
      <div className="max-w-5xl mx-auto space-y-6">
        
        {/* Header */}
        <div className="text-center space-y-2">
          <h1 className="text-3xl md:text-4xl font-extrabold flex items-center justify-center gap-3">
            <ShoppingBag className="text-pink-600" size={36} />
            <span className="bg-clip-text text-transparent bg-gradient-to-r from-pink-600 to-cyan-500">
              Kalkulator Harga TikTok Shop
            </span>
          </h1>
          <p className="text-slate-500 text-sm md:text-base max-w-2xl mx-auto">
            Hitung harga jual yang tepat agar tidak boncos. Sesuaikan persentase biaya layanan, komisi affiliate, dan biaya admin sesuai dengan kategori produk Anda.
          </p>
        </div>

        {/* Tabs */}
        <div className="flex justify-center mb-6">
          <div className="bg-white p-1 rounded-xl shadow-sm border border-slate-200 inline-flex">
            <button
              onClick={() => setActiveTab('ideal')}
              className={`px-6 py-2.5 rounded-lg text-sm font-semibold transition-all ${
                activeTab === 'ideal' 
                  ? 'bg-slate-800 text-white shadow-md' 
                  : 'text-slate-500 hover:text-slate-800 hover:bg-slate-100'
              }`}
            >
              Cari Harga Jual Ideal
            </button>
            <button
              onClick={() => setActiveTab('simulasi')}
              className={`px-6 py-2.5 rounded-lg text-sm font-semibold transition-all ${
                activeTab === 'simulasi' 
                  ? 'bg-slate-800 text-white shadow-md' 
                  : 'text-slate-500 hover:text-slate-800 hover:bg-slate-100'
              }`}
            >
              Simulasi Keuntungan
            </button>
          </div>
        </div>

        <div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
          
          {/* Kolom Kiri: Input Biaya Modal & Variabel */}
          <div className="lg:col-span-2 space-y-6">
            
            <div className="bg-white rounded-2xl shadow-sm border border-slate-200 overflow-hidden">
              <div className="bg-slate-800 px-6 py-4 border-b border-slate-200">
                <h2 className="text-lg font-semibold text-white flex items-center gap-2">
                  <Package size={20} className="text-cyan-400" />
                  Biaya Dasar Produk
                </h2>
              </div>
              <div className="p-6 grid grid-cols-1 md:grid-cols-2 gap-4">
                <div className="space-y-1">
                  <label className="text-sm font-medium text-slate-600">Harga Beli / Modal Produk (Rp)</label>
                  <input
                    type="number"
                    value={modal}
                    onChange={(e) => setModal(e.target.value)}
                    onFocus={handleFocus}
                    className="w-full px-4 py-2 border border-slate-300 rounded-lg focus:ring-2 focus:ring-cyan-500 focus:border-cyan-500 transition-all outline-none"
                  />
                </div>
                <div className="space-y-1">
                  <label className="text-sm font-medium text-slate-600">Biaya Packaging dll (Rp)</label>
                  <input
                    type="number"
                    value={packaging}
                    onChange={(e) => setPackaging(e.target.value)}
                    onFocus={handleFocus}
                    className="w-full px-4 py-2 border border-slate-300 rounded-lg focus:ring-2 focus:ring-cyan-500 focus:border-cyan-500 transition-all outline-none"
                  />
                </div>
              </div>
            </div>

            <div className="bg-white rounded-2xl shadow-sm border border-slate-200 overflow-hidden">
              <div className="bg-slate-800 px-6 py-4 border-b border-slate-200">
                <h2 className="text-lg font-semibold text-white flex items-center gap-2">
                  <Percent size={20} className="text-pink-400" />
                  Potongan TikTok Shop
                </h2>
              </div>
              <div className="p-6 grid grid-cols-1 md:grid-cols-2 gap-4">
                <div className="space-y-1">
                  <label className="text-sm font-medium text-slate-600">Biaya Admin (%)</label>
                  <input
                    type="number"
                    step="0.1"
                    value={adminPercent}
                    onChange={(e) => setAdminPercent(e.target.value)}
                    onFocus={handleFocus}
                    className="w-full px-4 py-2 border border-slate-300 rounded-lg focus:ring-2 focus:ring-pink-500 focus:border-pink-500 transition-all outline-none"
                  />
                </div>
                <div className="space-y-1">
                  <label className="text-sm font-medium text-slate-600">Biaya Tetap Admin (Rp)</label>
                  <input
                    type="number"
                    value={adminFlat}
                    onChange={(e) => setAdminFlat(e.target.value)}
                    onFocus={handleFocus}
                    className="w-full px-4 py-2 border border-slate-300 rounded-lg focus:ring-2 focus:ring-pink-500 focus:border-pink-500 transition-all outline-none"
                  />
                </div>
                <div className="space-y-1">
                  <label className="text-sm font-medium text-slate-600">Komisi Affiliate (%)</label>
                  <input
                    type="number"
                    step="0.1"
                    value={affiliatePercent}
                    onChange={(e) => setAffiliatePercent(e.target.value)}
                    onFocus={handleFocus}
                    className="w-full px-4 py-2 border border-slate-300 rounded-lg focus:ring-2 focus:ring-pink-500 focus:border-pink-500 transition-all outline-none"
                  />
                </div>
                <div className="space-y-1">
                  <label className="text-sm font-medium text-slate-600">Layanan Gratis Ongkir (%)</label>
                  <input
                    type="number"
                    step="0.1"
                    value={xtraPercent}
                    onChange={(e) => setXtraPercent(e.target.value)}
                    onFocus={handleFocus}
                    className="w-full px-4 py-2 border border-slate-300 rounded-lg focus:ring-2 focus:ring-pink-500 focus:border-pink-500 transition-all outline-none"
                  />
                </div>
              </div>
            </div>

            {/* Input khusus berdasarkan tab */}
            {activeTab === 'ideal' ? (
              <div className="bg-cyan-50 rounded-2xl shadow-sm border border-cyan-200 p-6">
                 <h3 className="text-lg font-bold text-cyan-900 mb-3 flex items-center gap-2">
                   <TrendingUp size={20} />
                   Target Keuntungan Bersih
                 </h3>
                 <p className="text-sm text-cyan-800 mb-4">Berapa uang bersih yang ingin Anda dapatkan dari penjualan 1 produk ini?</p>
                 <div className="space-y-1">
                  <input
                    type="number"
                    value={targetProfit}
                    onChange={(e) => setTargetProfit(e.target.value)}
                    onFocus={handleFocus}
                    className="w-full px-4 py-3 text-lg font-semibold border border-cyan-300 rounded-lg focus:ring-2 focus:ring-cyan-600 focus:border-cyan-600 transition-all outline-none"
                  />
                </div>
              </div>
            ) : (
               <div className="bg-indigo-50 rounded-2xl shadow-sm border border-indigo-200 p-6">
                 <h3 className="text-lg font-bold text-indigo-900 mb-3 flex items-center gap-2">
                   <DollarSign size={20} />
                   Rencana Harga Jual
                 </h3>
                 <p className="text-sm text-indigo-800 mb-4">Masukkan harga jual yang ingin Anda pasang di etalase toko.</p>
                 <div className="space-y-1">
                  <input
                    type="number"
                    value={sellingPrice}
                    onChange={(e) => setSellingPrice(e.target.value)}
                    onFocus={handleFocus}
                    className="w-full px-4 py-3 text-lg font-semibold border border-indigo-300 rounded-lg focus:ring-2 focus:ring-indigo-600 focus:border-indigo-600 transition-all outline-none"
                  />
                </div>
              </div>
            )}

          </div>

          {/* Kolom Kanan: Hasil & Ringkasan */}
          <div className="lg:col-span-1">
            <div className="bg-white rounded-2xl shadow-xl border border-slate-200 sticky top-6 overflow-hidden">
              
              {activeTab === 'ideal' ? (
                // RESULT: IDEAL PRICE
                <>
                  <div className="bg-gradient-to-br from-slate-800 to-slate-900 p-6 text-center text-white">
                    <p className="text-slate-300 text-sm font-medium mb-2 uppercase tracking-wider">Saran Harga Jual</p>
                    <h3 className="text-3xl font-extrabold text-cyan-400 mb-1">
                      {formatRp(idealResult.idealPrice)}
                    </h3>
                    <p className="text-slate-400 text-xs">Untuk mendapatkan untung bersih {formatRp(targetProfit)}</p>
                  </div>
                  
                  <div className="p-6 space-y-4">
                    <h4 className="font-semibold text-slate-800 border-b pb-2">Rincian Potongan</h4>
                    <div className="space-y-2 text-sm">
                      <div className="flex justify-between">
                        <span className="text-slate-600">Biaya Admin ({adminPercent}%)</span>
                        <span className="font-medium text-red-500">-{formatRp(idealResult.adminCut)}</span>
                      </div>
                      <div className="flex justify-between">
                        <span className="text-slate-600">Biaya Tetap Admin</span>
                        <span className="font-medium text-red-500">-{formatRp(adminFlat)}</span>
                      </div>
                      <div className="flex justify-between">
                        <span className="text-slate-600">Komisi Affiliate ({affiliatePercent}%)</span>
                        <span className="font-medium text-red-500">-{formatRp(idealResult.affiliateCut)}</span>
                      </div>
                      <div className="flex justify-between">
                        <span className="text-slate-600">Gratis Ongkir Xtra ({xtraPercent}%)</span>
                        <span className="font-medium text-red-500">-{formatRp(idealResult.xtraCut)}</span>
                      </div>
                    </div>
                    
                    <div className="pt-4 border-t border-slate-100">
                      <div className="flex justify-between items-center bg-red-50 p-3 rounded-lg border border-red-100">
                        <span className="font-semibold text-red-800 text-sm">Total Potongan</span>
                        <span className="font-bold text-red-600">{formatRp(idealResult.totalPotongan)}</span>
                      </div>
                    </div>

                    <div className="pt-2">
                       <div className="flex items-start gap-2 text-xs text-slate-500 bg-slate-50 p-3 rounded-lg">
                         <AlertCircle size={16} className="text-cyan-600 shrink-0 mt-0.5" />
                         <p>Rumus ini memasukkan potongan persentase dari harga jual akhir, sehingga Anda mendapatkan untung bulat sesuai target.</p>
                       </div>
                    </div>
                  </div>
                </>
              ) : (
                // RESULT: SIMULASI
                <>
                  <div className={`p-6 text-center text-white ${simResult.netProfit >= 0 ? 'bg-gradient-to-br from-green-600 to-emerald-700' : 'bg-gradient-to-br from-red-600 to-rose-700'}`}>
                    <p className="text-white/80 text-sm font-medium mb-2 uppercase tracking-wider">Keuntungan Bersih</p>
                    <h3 className="text-3xl font-extrabold mb-1">
                      {formatRp(simResult.netProfit)}
                    </h3>
                    <p className="text-white/90 text-sm bg-black/20 inline-block px-3 py-1 rounded-full mt-2">
                      Margin: {simResult.profitMargin.toFixed(1)}%
                    </p>
                  </div>
                  
                  <div className="p-6 space-y-4">
                    <h4 className="font-semibold text-slate-800 border-b pb-2">Rincian Perhitungan</h4>
                    <div className="space-y-2 text-sm">
                      <div className="flex justify-between">
                        <span className="text-slate-600">Harga Jual</span>
                        <span className="font-medium text-slate-800">{formatRp(sellingPrice)}</span>
                      </div>
                      <div className="flex justify-between">
                        <span className="text-slate-600">Total Modal (Produk + Pack)</span>
                        <span className="font-medium text-slate-800">-{formatRp(Number(modal) + Number(packaging))}</span>
                      </div>
                      
                      <div className="pt-2 pb-1 text-xs font-semibold text-slate-400 uppercase tracking-wider">Potongan Aplikasi</div>
                      
                      <div className="flex justify-between">
                        <span className="text-slate-600">Biaya Admin ({adminPercent}%) + Flat</span>
                        <span className="font-medium text-red-500">-{formatRp(simResult.adminCut + Number(adminFlat))}</span>
                      </div>
                      <div className="flex justify-between">
                        <span className="text-slate-600">Komisi Affiliate ({affiliatePercent}%)</span>
                        <span className="font-medium text-red-500">-{formatRp(simResult.affiliateCut)}</span>
                      </div>
                      <div className="flex justify-between">
                        <span className="text-slate-600">Gratis Ongkir Xtra ({xtraPercent}%)</span>
                        <span className="font-medium text-red-500">-{formatRp(simResult.xtraCut)}</span>
                      </div>
                    </div>
                    
                    <div className="pt-4 border-t border-slate-100">
                      <div className="flex justify-between items-center bg-red-50 p-3 rounded-lg border border-red-100">
                        <span className="font-semibold text-red-800 text-sm">Total Potongan TikTok</span>
                        <span className="font-bold text-red-600">{formatRp(simResult.totalPotongan)}</span>
                      </div>
                    </div>

                    {simResult.netProfit < 0 && (
                      <div className="pt-2">
                         <div className="flex items-start gap-2 text-sm text-red-700 bg-red-100 p-3 rounded-lg border border-red-200">
                           <AlertCircle size={18} className="shrink-0 mt-0.5" />
                           <p><strong>Peringatan!</strong> Anda mengalami kerugian. Silakan naikkan harga jual atau turunkan biaya operasional.</p>
                         </div>
                      </div>
                    )}
                  </div>
                </>
              )}

            </div>
          </div>

        </div>
      </div>
    </div>
  );
}