fmcg-orderflow-pro / index.html
emeraj24's picture
import React, { useState, useRef, useEffect } from 'react';
e35c4d4 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>RetailPro POS - Modern Retail Management System</title>
<link rel="icon" type="image/x-icon" href="/static/favicon.ico">
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/animejs/lib/anime.iife.min.js"></script>
<script src="https://unpkg.com/feather-icons"></script>
<style>
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap');
body {
font-family: 'Inter', sans-serif;
}
.glass-effect {
backdrop-filter: blur(10px);
background: rgba(255, 255, 255, 0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
}
.dark .glass-effect {
background: rgba(0, 0, 0, 0.3);
border: 1px solid rgba(255, 255, 255, 0.1);
}
.gradient-bg {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
.dark .gradient-bg {
background: linear-gradient(135deg, #4c51bf 0%, #553c9a 100%);
}
.hover-scale {
transition: transform 0.2s ease-in-out;
}
.hover-scale:hover {
transform: scale(1.02);
}
.animate-float {
animation: float 3s ease-in-out infinite;
}
@keyframes float {
0%, 100% { transform: translateY(0px); }
50% { transform: translateY(-10px); }
}
.custom-scrollbar::-webkit-scrollbar {
width: 6px;
}
.custom-scrollbar::-webkit-scrollbar-track {
background: rgba(0, 0, 0, 0.1);
border-radius: 3px;
}
.custom-scrollbar::-webkit-scrollbar-thumb {
background: rgba(0, 0, 0, 0.3);
border-radius: 3px;
}
.dark .custom-scrollbar::-webkit-scrollbar-track {
background: rgba(255, 255, 255, 0.1);
}
.dark .custom-scrollbar::-webkit-scrollbar-thumb {
background: rgba(255, 255, 255, 0.3);
}
.pulse-animation {
animation: pulse 2s infinite;
}
@keyframes pulse {
0% { opacity: 1; }
50% { opacity: 0.7; }
100% { opacity: 1; }
}
.slide-in {
animation: slideIn 0.3s ease-out;
}
@keyframes slideIn {
from { transform: translateY(-20px); opacity: 0; }
to { transform: translateY(0); opacity: 1; }
}
.fade-in {
animation: fadeIn 0.5s ease-out;
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
</style>
</head>
<body class="bg-gray-50 dark:bg-gray-900 transition-colors duration-300">
<div id="app">
<!-- Loading Screen -->
<div class="fixed inset-0 bg-gradient-to-br from-blue-600 to-purple-700 flex items-center justify-center z-50" id="loading-screen">
<div class="text-center text-white">
<div class="animate-float mb-4">
<i data-feather="shopping-cart" class="w-16 h-16 mx-auto"></i>
</div>
<h1 class="text-3xl font-bold mb-2">RetailPro POS</h1>
<p class="text-blue-100">Loading your retail management system...</p>
<div class="mt-4 flex justify-center">
<div class="w-2 h-2 bg-white rounded-full mx-1 pulse-animation"></div>
<div class="w-2 h-2 bg-white rounded-full mx-1 pulse-animation" style="animation-delay: 0.2s;"></div>
<div class="w-2 h-2 bg-white rounded-full mx-1 pulse-animation" style="animation-delay: 0.4s;"></div>
</div>
</div>
</div>
<!-- Main App Container -->
<div class="min-h-screen transition-colors duration-300" id="main-app" style="display: none;">
<!-- Header -->
<header class="bg-white/80 dark:bg-gray-800/80 backdrop-blur-md shadow-lg border-b border-white/20 dark:border-gray-700/20 sticky top-0 z-40">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex justify-between items-center py-4">
<div class="flex items-center space-x-4">
<div class="w-10 h-10 bg-gradient-to-br from-blue-500 to-purple-600 rounded-xl flex items-center justify-center shadow-lg hover-scale">
<i data-feather="shopping-bag" class="w-6 h-6 text-white"></i>
</div>
<div>
<h1 class="text-2xl font-bold bg-gradient-to-r from-blue-600 to-purple-600 bg-clip-text text-transparent">RetailPro POS</h1>
<p class="text-sm text-gray-500 dark:text-gray-400">Modern Retail Management</p>
</div>
</div>
<div class="flex items-center space-x-4">
<div class="hidden sm:flex items-center text-sm text-gray-600 dark:text-gray-300 bg-gray-100 dark:bg-gray-700 px-3 py-1 rounded-full">
<i data-feather="user" class="w-4 h-4 mr-2"></i>
<span id="owner-name">Rajesh Kumar</span>
</div>
<button id="theme-toggle" class="p-2 rounded-lg bg-gray-100 dark:bg-gray-700 hover:bg-gray-200 dark:hover:bg-gray-600 transition-colors">
<i data-feather="sun" class="w-5 h-5 text-yellow-500 dark:hidden"></i>
<i data-feather="moon" class="w-5 h-5 text-blue-400 hidden dark:block"></i>
</button>
</div>
</div>
</div>
</header>
<!-- Navigation -->
<nav class="bg-white/70 dark:bg-gray-800/70 backdrop-blur-md shadow-sm border-b border-white/30 dark:border-gray-700/30 sticky top-16 z-30">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex space-x-1 sm:space-x-4 overflow-x-auto py-2" id="nav-tabs">
<!-- Navigation tabs will be generated by JavaScript -->
</div>
</div>
</nav>
<!-- Main Content -->
<main class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
<div id="content-area">
<!-- Content will be dynamically loaded here -->
</div>
</main>
<!-- Modals -->
<div id="modal-container"></div>
</div>
</div>
<script>
// Global state management
class AppState {
constructor() {
this.state = {
activeTab: 'billing',
theme: 'light',
products: [
{ id: 1, name: 'Parle-G Biscuits', barcode: '8901234567890', price: 10, gst: 18, stock: 100, category: 'Snacks' },
{ id: 2, name: 'Dairy Milk Chocolate', barcode: '8901234567891', price: 20, gst: 12, stock: 50, category: 'Chocolates' },
{ id: 3, name: 'Nescafe Coffee', barcode: '8901234567892', price: 180, gst: 18, stock: 30, category: 'Beverages' },
{ id: 4, name: 'Amul Butter', barcode: '8901234567893', price: 45, gst: 5, stock: 40, category: 'Dairy' },
{ id: 5, name: 'Colgate Toothpaste', barcode: '8901234567894', price: 85, gst: 18, stock: 60, category: 'Personal Care' }
],
suppliers: [
{ id: 1, name: 'ABC Distributors', address: '123 Main Street, Mumbai', gstNo: '27AABCCDDEEFFG', openingBalance: 5000, balanceType: 'Credit' },
{ id: 2, name: 'XYZ Wholesalers', address: '456 Market Road, Delhi', gstNo: '07XYZPQRST1234Z', openingBalance: 2500, balanceType: 'Credit' }
],
categories: [
{ id: 1, name: 'Snacks' },
{ id: 2, name: 'Chocolates' },
{ id: 3, name: 'Beverages' },
{ id: 4, name: 'Dairy' },
{ id: 5, name: 'Personal Care' }
],
gstRates: [
{ id: 1, rate: 5, description: 'Dairy Products' },
{ id: 2, rate: 12, description: 'Chocolates & Confectionery' },
{ id: 3, rate: 18, description: 'General Goods' },
{ id: 4, rate: 28, description: 'Luxury Items' }
],
cart: [],
purchaseCart: [],
searchTerm: '',
purchaseSearchTerm: '',
invoiceNumber: 1001,
purchaseInvoiceNumber: 2001,
customerName: '',
supplierName: '',
customerPhone: '',
supplierPhone: '',
paymentMethod: 'cash',
purchasePaymentMethod: 'cash',
salesReport: [],
purchaseReport: [],
dayBook: [],
selectedDate: new Date().toISOString().split('T')[0],
shopProfile: {
shopName: 'SHREE GANESH TRADERS',
ownerName: 'Rajesh Kumar',
address: '123 Main Street, Mumbai, Maharashtra',
phone: '9876543210',
email: 'info@shreeganeshtraders.com',
gstin: '27AABCCDDEEFFG'
}
};
this.listeners = [];
}
getState() {
return this.state;
}
setState(newState) {
this.state = { ...this.state, ...newState };
this.notifyListeners();
}
subscribe(listener) {
this.listeners.push(listener);
}
notifyListeners() {
this.listeners.forEach(listener => listener(this.state));
}
}
// Initialize app state
const appState = new AppState();
// UI Components
class UIComponents {
static createProductCard(product, onAddToCart) {
return `
<div class="border border-gray-200 dark:border-gray-700 rounded-xl p-4 hover:shadow-lg transition-all duration-300 cursor-pointer bg-white dark:bg-gray-800 hover:bg-blue-50 dark:hover:bg-blue-900/20 hover-scale" onclick="${onAddToCart}">
<div class="flex justify-between items-start mb-2">
<h3 class="font-semibold text-gray-800 dark:text-white text-sm">${product.name}</h3>
<span class="text-xs bg-blue-100 dark:bg-blue-900 text-blue-600 dark:text-blue-400 px-2 py-1 rounded-full">${product.category}</span>
</div>
<p class="text-xs text-gray-500 dark:text-gray-400 mb-2">Barcode: ${product.barcode}</p>
<div class="flex justify-between items-center">
<span class="text-lg font-bold text-blue-600 dark:text-blue-400">₹${product.price}</span>
<span class="text-xs text-green-600 dark:text-green-400 bg-green-100 dark:bg-green-900 px-2 py-1 rounded-full">${product.gst}% GST</span>
</div>
<p class="text-xs text-gray-500 dark:text-gray-400 mt-2">Stock: ${product.stock}</p>
</div>
`;
}
static createCartItem(item, isPurchase = false) {
const updateFunction = isPurchase ? `updatePurchaseQuantity(${item.id}, ${item.quantity - 1})` : `updateQuantity(${item.id}, ${item.quantity - 1})`;
const removeFunction = isPurchase ? `removeFromPurchaseCart(${item.id})` : `removeFromCart(${item.id})`;
const price = isPurchase ? (item.purchasePrice || item.price) : item.price;
return `
<div class="flex items-center justify-between p-3 bg-gray-50 dark:bg-gray-700 rounded-lg slide-in">
<div class="flex-1">
<h4 class="font-medium text-sm text-gray-800 dark:text-white">${item.name}</h4>
<p class="text-xs text-gray-600 dark:text-gray-300">₹${price} × ${item.quantity}</p>
${isPurchase ? `<p class="text-xs text-blue-600 dark:text-blue-400">Purchase: ₹${(item.purchasePrice || item.price).toFixed(2)}</p>` : ''}
</div>
<div class="flex items-center space
</body>
</html>