import React, { useState, useEffect, useMemo } from 'react';
import { initializeApp } from 'firebase/app';
import {
getAuth, signInAnonymously, onAuthStateChanged, signOut
} from 'firebase/auth';
import {
getFirestore, collection, doc, setDoc, addDoc, updateDoc,
deleteDoc, onSnapshot, query, where, getDoc
} from 'firebase/firestore';
import {
ShoppingBag, ShoppingCart, Users, Receipt, PieChart, Settings,
Plus, Edit2, Trash2, Search, LogOut, Globe, CheckCircle, AlertTriangle
} from 'lucide-react';
// --- Firebase Configuration ---
const firebaseConfig = {
apiKey: "AIzaSyAPX6tpGF093l8EH7Q0N1ehzJ6uJGVRpmo",
authDomain: "nunungai.firebaseapp.com",
databaseURL: "https://nunungai-default-rtdb.asia-southeast1.firebasedatabase.app",
projectId: "nunungai",
storageBucket: "nunungai.firebasestorage.app",
messagingSenderId: "952019927017",
appId: "1:952019927017:web:67a9793d96beabbf6c1578",
measurementId: "G-DC0JX638XJ"
};
const app = initializeApp(firebaseConfig);
const auth = getAuth(app);
const db = getFirestore(app);
const appId = typeof __app_id !== 'undefined' ? __app_id : 'nay-n-nay-pos-001';
// --- Translations ---
const translations = {
en: {
appTitle: "Nay N Nay POS",
purchase: "Purchase",
sale: "Sale",
customer: "Customer",
expense: "Expense",
report: "Report",
system: "System",
add: "Add",
edit: "Edit",
delete: "Delete",
save: "Save",
search: "Search...",
product: "Product",
cost: "Cost",
price: "Sell Price",
qty: "Qty",
expiry: "Expiry",
total: "Total",
netTotal: "Net Total",
service: "Service Fee",
pay: "Paid Amount",
status: "Status",
unpaid: "Unpaid",
paid: "Paid",
bestSellers: "Top 10 Products",
profit: "Net Profit",
asset: "Inventory Asset",
diagnosis: "Diagnosis"
},
mm: {
appTitle: "နေနဲ့နေ POS",
purchase: "အဝယ်",
sale: "အရောင်း",
customer: "ဖောက်သည်",
expense: "အသုံးစရိတ်",
report: "မှတ်တမ်း",
system: "စနစ်",
add: "အသစ်ထည့်",
edit: "ပြင်ဆင်",
delete: "ဖျက်မည်",
save: "သိမ်းမည်",
search: "ရှာဖွေရန်...",
product: "ပစ္စည်းအမည်",
cost: "ရင်းနှီးစျေး",
price: "ရောင်းစျေး",
qty: "အရေအတွက်",
expiry: "သက်တမ်းကုန်ရက်",
total: "စုစုပေါင်း",
netTotal: "အားလုံးပေါင်း",
service: "ဝန်ဆောင်ခ",
pay: "ပေးချေငွေ",
status: "အခြေအနေ",
unpaid: "မပေးရသေး",
paid: "ပေးပြီး",
bestSellers: "အရောင်းရဆုံး ၁၀ မျိုး",
profit: "အသားတင်အမြတ်",
asset: "လက်ကျန်ပစ္စည်းတန်ဖိုး",
diagnosis: "ရောဂါရာဇဝင်"
}
};
export default function App() {
const [user, setUser] = useState(null);
const [lang, setLang] = useState('mm');
const [activeTab, setActiveTab] = useState('sale');
// Data States
const [inventory, setInventory] = useState([]);
const [sales, setSales] = useState([]);
const [customers, setCustomers] = useState([]);
const [expenses, setExpenses] = useState([]);
const t = translations[lang];
// --- Auth & Initialization ---
useEffect(() => {
const initAuth = async () => {
try {
await signInAnonymously(auth);
} catch (err) {
console.error("Auth failed", err);
}
};
initAuth();
const unsub = onAuthStateChanged(auth, (u) => setUser(u));
return () => unsub();
}, []);
// --- Data Listeners ---
useEffect(() => {
if (!user) return;
const collections = ['purchase', 'sales', 'customers', 'expenses'];
const unsubs = collections.map(col => {
return onSnapshot(
collection(db, 'artifacts', appId, 'public', 'data', col),
(snap) => {
const docs = snap.docs.map(d => ({ id: d.id, ...d.data() }));
if (col === 'purchase') setInventory(docs);
if (col === 'sales') setSales(docs);
if (col === 'customers') setCustomers(docs);
if (col === 'expenses') setExpenses(docs);
},
(err) => console.error(`Error loading ${col}`, err)
);
});
return () => unsubs.forEach(u => u());
}, [user]);
// --- Theme Helpers ---
const glassEffect = "bg-white/20 backdrop-blur-md border border-white/30";
const neuInner = "shadow-[inset_4px_4px_8px_#b8b9be,inset_-4px_-4px_8px_#ffffff]";
const neuOuter = "shadow-[6px_6px_12px_#c5c5c5,-6px_-6px_12px_#ffffff]";
const premiumBtn = "active:shadow-inner transition-all duration-200 rounded-2xl flex items-center justify-center font-bold";
// --- Logic Helpers ---
const getInventoryStatus = (item) => {
const today = new Date();
const expiry = new Date(item.expiryDate);
const monthsToExpiry = (expiry - today) / (1000 * 60 * 60 * 24 * 30);
const isLowStock = item.quantity < 10;
const isNearExpiry = monthsToExpiry < 3;
if (isLowStock && isNearExpiry) return "bg-gradient-to-r from-red-500 to-yellow-500";
if (isLowStock) return "bg-red-500 text-white";
if (isNearExpiry) return "bg-yellow-400 text-black";
return "bg-white text-gray-800";
};
// --- Components ---
const PurchaseSection = () => {
const [search, setSearch] = useState('');
const [form, setForm] = useState({ name: '', cost: 0, price: 0, quantity: 0, expiryDate: '' });
const [editingId, setEditingId] = useState(null);
const filtered = inventory
.filter(i => i.name.toLowerCase().includes(search.toLowerCase()))
.sort((a, b) => a.name.localeCompare(b.name));
const handleSubmit = async () => {
const data = { ...form, cost: Number(form.cost), price: Number(form.price), quantity: Number(form.quantity) };
const colRef = collection(db, 'artifacts', appId, 'public', 'data', 'purchase');
if (editingId) {
await updateDoc(doc(colRef, editingId), data);
setEditingId(null);
} else {
await addDoc(colRef, data);
}
setForm({ name: '', cost: 0, price: 0, quantity: 0, expiryDate: '' });
};
return (
setSearch(e.target.value)} />
{filtered.map(item => (
{item.name}
{t.qty}: {item.quantity} | {t.expiry}: {item.expiryDate}
{item.price.toLocaleString()} Ks
Cost: {item.cost}
))}
);
};
const SaleSection = () => {
const [cart, setCart] = useState([]);
const [selectedCustomer, setSelectedCustomer] = useState('');
const [serviceFee, setServiceFee] = useState(0);
const [payAmount, setPayAmount] = useState(0);
const [search, setSearch] = useState('');
const subTotal = cart.reduce((sum, item) => sum + (item.price * item.quantity), 0);
const totalWithService = subTotal + Number(serviceFee);
const balance = totalWithService - Number(payAmount);
const addToCart = (product) => {
const existing = cart.find(c => c.id === product.id);
if (existing) {
setCart(cart.map(c => c.id === product.id ? { ...c, quantity: c.quantity + 1 } : c));
} else {
setCart([...cart, { ...product, quantity: 1 }]);
}
};
const processSale = async () => {
if (cart.length === 0 || !selectedCustomer) return;
const saleData = {
customerId: selectedCustomer,
customerName: customers.find(c => c.id === selectedCustomer)?.name || "Unknown",
items: cart,
subTotal,
serviceFee: Number(serviceFee),
total: totalWithService,
paid: Number(payAmount),
balance: balance,
status: balance <= 0 ? 'paid' : 'unpaid',
date: new Date().toISOString()
};
// 1. Add Sale Record
await addDoc(collection(db, 'artifacts', appId, 'public', 'data', 'sales'), saleData);
// 2. Update Inventory (Minus Stock)
for (const item of cart) {
const invItem = inventory.find(i => i.id === item.id);
if (invItem) {
await updateDoc(doc(db, 'artifacts', appId, 'public', 'data', 'purchase', item.id), {
quantity: invItem.quantity - item.quantity
});
}
}
// 3. Update Customer Balance
const cust = customers.find(c => c.id === selectedCustomer);
if (cust) {
await updateDoc(doc(db, 'artifacts', appId, 'public', 'data', 'customers', selectedCustomer), {
totalDebt: (cust.totalDebt || 0) + balance
});
}
setCart([]);
setPayAmount(0);
setServiceFee(0);
alert("Sale Completed!");
};
return (
{/* Inventory Search for Cart */}
setSearch(e.target.value)} />
{inventory.filter(i => i.name.toLowerCase().includes(search.toLowerCase())).map(item => (
))}
{/* Cart Details */}
Cart
{cart.map(item => (
{item.name}
{item.quantity} x {item.price}
{(item.quantity * item.price).toLocaleString()}
))}
{t.total}:
{subTotal.toLocaleString()}
{t.netTotal}:
{totalWithService.toLocaleString()}
{/* Customer & Payment */}
);
};
const CustomerSection = () => {
const [search, setSearch] = useState('');
const [sort, setSort] = useState('name');
const [form, setForm] = useState({ name: '', age: '', gender: 'Male', phone1: '', phone2: '', phone3: '', diagnosis: '', totalDebt: 0 });
const [showModal, setShowModal] = useState(false);
const filtered = customers
.filter(c => c.name.toLowerCase().includes(search.toLowerCase()))
.sort((a, b) => {
if (sort === 'debt') return (b.totalDebt || 0) - (a.totalDebt || 0);
return a.name.localeCompare(b.name);
});
const handleAdd = async () => {
await addDoc(collection(db, 'artifacts', appId, 'public', 'data', 'customers'), form);
setShowModal(false);
setForm({ name: '', age: '', gender: 'Male', phone1: '', phone2: '', phone3: '', diagnosis: '', totalDebt: 0 });
};
const clearDebt = async (cId) => {
await updateDoc(doc(db, 'artifacts', appId, 'public', 'data', 'customers', cId), { totalDebt: 0 });
// Update linked sales as paid in a real app logic
};
return (
{filtered.map(cust => (
{cust.name}
{cust.gender}, {cust.age} yrs
📞 {cust.phone1} | {cust.phone2}
0 ? 'text-red-500' : 'text-green-500'}`}>
{cust.totalDebt?.toLocaleString()} Ks
{cust.totalDebt > 0 && (
)}
Diagnosis: {cust.diagnosis || 'None'}
))}
{showModal && (
New Customer
)}
);
};
const ExpenseSection = () => {
const [form, setForm] = useState({ title: '', amount: 0, deductProfit: true });
const handleSubmit = async () => {
await addDoc(collection(db, 'artifacts', appId, 'public', 'data', 'expenses'), {
...form,
amount: Number(form.amount),
date: new Date().toISOString()
});
setForm({ title: '', amount: 0, deductProfit: true });
};
return (
{expenses.map(exp => (
{exp.title}
{new Date(exp.date).toLocaleDateString()}
-{exp.amount.toLocaleString()} Ks
))}
);
};
const ReportSection = () => {
// --- Complex Calculations ---
const reports = useMemo(() => {
let totalSales = 0;
let totalProfit = 0;
let serviceIncome = 0;
const productStats = {};
sales.forEach(sale => {
totalSales += sale.total;
serviceIncome += sale.serviceFee;
sale.items.forEach(item => {
// Calculate profit: sell price - original cost
const invItem = inventory.find(i => i.id === item.id);
const itemCost = invItem ? invItem.cost : item.price * 0.7; // fallback
totalProfit += (item.price - itemCost) * item.quantity;
// Best selling stats
productStats[item.name] = (productStats[item.name] || 0) + item.quantity;
});
});
const totalExpenses = expenses.filter(e => e.deductProfit).reduce((sum, e) => sum + e.amount, 0);
const inventoryAsset = inventory.reduce((sum, i) => sum + (i.cost * i.quantity), 0);
const bestSelling = Object.entries(productStats)
.sort(([,a], [,b]) => b - a)
.slice(0, 10);
return { totalSales, totalProfit: totalProfit + serviceIncome - totalExpenses, serviceIncome, inventoryAsset, bestSelling };
}, [sales, inventory, expenses]);
return (
{/* Grand Totals */}
Total Sales
{reports.totalSales.toLocaleString()} Ks
{t.profit}
{reports.totalProfit.toLocaleString()} Ks
{/* Inventory Asset */}
{reports.inventoryAsset.toLocaleString()} Ks
{/* Best Sellers */}
{t.bestSellers}
{reports.bestSelling.map(([name, qty], idx) => (
))}
);
};
const SystemSection = () => {
return (
Nay N Nay POS v1.0
Premium Neumorphic Design
);
};
// --- Main Render ---
return (
{/* Top Header */}
Nay N Nay
Premium POS System
setActiveTab('system')}>
{/* Main Content Area */}
{activeTab === 'purchase' &&
}
{activeTab === 'sale' &&
}
{activeTab === 'customer' &&
}
{activeTab === 'expense' &&
}
{activeTab === 'report' &&
}
{activeTab === 'system' &&
}
{/* Bottom Navigation */}
{/* Style Overrides */}
);
}