stock request

This commit is contained in:
2026-07-04 17:46:30 +05:30
parent c6a3ea51da
commit 7cd0ae85ef
23 changed files with 1293 additions and 570 deletions

View File

@@ -4,6 +4,7 @@
*/
import React, { useState, useEffect } from 'react';
import { Routes, Route, Navigate, useLocation, useNavigate } from 'react-router-dom';
import {
Network,
Truck,
@@ -29,7 +30,8 @@ import {
Layers,
Store,
Settings,
LayoutDashboard
LayoutDashboard,
Users
} from 'lucide-react';
import { MainSection } from './types';
@@ -37,9 +39,10 @@ import {
useFiestaTenantLocations,
useFiestaLocationSummary,
useFiestaUpdateLocation,
useFiestaCreateLocation,
useFiestaOrderSummary,
} from './services/fiestaQueries';
import { FIESTA_TENANT_ID, str as fstr } from './services/fiestaApi';
import { FIESTA_TENANT_ID, str as fstr, num as fnum } from './services/fiestaApi';
import Sidebar from './components/Sidebar';
import Header from './components/Header';
import DashboardView from './components/DashboardView';
@@ -97,13 +100,14 @@ export default function App() {
};
// Navigation indicators states
const [currentSection, setCurrentSection] = useState<MainSection>('dashboard');
const [selectedStore, setSelectedStore] = useState<{ locationid?: number; name: string; zone: string; deliveries: number; sales: string; orders?: number; staff: string; color: string; status: string } | null>(null);
const location = useLocation();
const navigate = useNavigate();
const handleSetSection = (sec: MainSection) => {
setCurrentSection(sec);
setSelectedStore(null);
};
// Derive current section from URL path, default to 'dashboard'
const pathParts = location.pathname.split('/');
const currentSection = (pathParts.includes('admin') ? pathParts[pathParts.length - 1] : 'dashboard') as MainSection;
const [selectedStore, setSelectedStore] = useState<{ locationid?: number; name: string; zone: string; deliveries: number; sales: string; orders?: number; staff: string; color: string; status: string } | null>(null);
const [isCoimbatoreView, setIsCoimbatoreView] = useState(false);
const [searchQuery, setSearchQuery] = useState('');
@@ -474,31 +478,7 @@ export default function App() {
</div>
</div>
{/* Live Sparkline Trend Histogram */}
<div className="mt-4 pt-3.5 border-t border-zinc-100">
<div className="flex justify-between items-center text-[8px] text-zinc-400 font-bold uppercase tracking-widest mb-1.5">
<span>Speed Index (Live Feed)</span>
<span className="text-[#662582] flex items-center gap-0.5 text-[8px] font-bold">
<Activity className="w-2.5 h-2.5 animate-pulse" /> Live
</span>
</div>
<div className="h-6 flex items-end gap-1">
{[30, 48, 25, 62, 54, 75, 42, 80, Math.min(95, Math.max(15, st.deliveries * 1.8))].map((val, idx) => (
<div key={idx} className="flex-1 bg-zinc-100 rounded-t-sm h-full relative overflow-hidden group/bar">
<div
style={{ height: `${val}%` }}
className={`absolute bottom-0 left-0 right-0 rounded-t-sm transition-all duration-500 ${
st.status.toLowerCase() === 'active'
? st.deliveries > 40
? 'bg-rose-500/80 group-hover/bar:bg-rose-500'
: 'bg-[#662582]/70 group-hover/bar:bg-[#662582]'
: 'bg-amber-500/70 group-hover/bar:bg-amber-500'
}`}
/>
</div>
))}
</div>
</div>
{/* Lead Manager Profile block */}
<div className="flex justify-between items-center text-xs text-zinc-650 bg-zinc-50/80 rounded-xl p-2.5 border border-zinc-100/80 mt-4">
@@ -567,22 +547,28 @@ export default function App() {
};
// ── Auth gate ──────────────────────────────────────────────────────────────
// Signed out → login screen. User role → their single allocated store console
// (scoped by applocationid). Only the admin role reaches the full operations
// dashboard with the all-stores registry below.
if (authRole === null) {
return <LoginView onLogin={handleLogin} />;
}
if (authRole === 'user' && authUser) {
return <UserStorePage onLogout={handleLogout} user={authUser} />;
return (
<Routes>
<Route path="/login" element={<LoginView onLogin={handleLogin} />} />
<Route path="*" element={<Navigate to="/login" replace />} />
</Routes>
);
}
return (
<div className="min-h-screen bg-[#f8fafc] text-[#0f172a] font-sans antialiased">
if (authRole === 'user' && authUser) {
return (
<Routes>
<Route path="/store/*" element={<UserStorePage onLogout={handleLogout} user={authUser} />} />
<Route path="*" element={<Navigate to="/store/console" replace />} />
</Routes>
);
}
const AdminConsole = (
<div className="min-h-screen bg-[#f8fafc] text-[#0f172a] font-sans antialiased overflow-x-hidden">
{/* Navbar segment */}
<Header
currentSection={currentSection}
setCurrentSection={handleSetSection}
isCoimbatoreView={isCoimbatoreView}
onToggleSidebar={() => setSidebarOpen((prev) => !prev)}
isSidebarOpen={sidebarOpen}
@@ -610,60 +596,69 @@ export default function App() {
/>
{/* Main Container workspace layout splits */}
<div className="flex pt-16">
<div className="flex pt-16 w-full max-w-[100vw]">
{/* Interactive Left Rail */}
<Sidebar
currentSection={currentSection}
setCurrentSection={handleSetSection}
isCoimbatoreView={isCoimbatoreView}
setIsCoimbatoreView={setIsCoimbatoreView}
isOpen={sidebarOpen}
isAdmin={authRole === 'admin'}
onClose={() => setSidebarOpen(false)}
/>
{/* Main core pages payload area */}
<main className={`flex-1 min-w-0 transition-all duration-300 ${sidebarOpen ? 'md:pl-64' : 'md:pl-20'} ${currentSection === 'inventory' ? 'h-[calc(100vh-64px)] overflow-hidden' : 'min-h-[calc(100vh-64px)]'}`}>
<div className={`w-full transition-all duration-300 ${currentSection === 'inventory' ? 'h-full p-4 md:p-6 overflow-hidden' : 'p-container-margin md:p-xl space-y-lg'}`}>
{/* Nav content routing */}
{currentSection === 'dashboard' && (
selectedStore ? (
renderStoresSection()
) : (
<div className="space-y-6">
<DashboardView searchQuery={searchQuery} isCoimbatoreView={isCoimbatoreView} tenantId={tenantId} />
<div>
{renderStoresSection()}
<Routes>
<Route index element={<Navigate to="dashboard" replace />} />
<Route path="dashboard" element={
selectedStore ? (
renderStoresSection()
) : (
<div className="space-y-6">
<DashboardView searchQuery={searchQuery} isCoimbatoreView={isCoimbatoreView} tenantId={tenantId} />
<div>
{renderStoresSection()}
</div>
</div>
</div>
)
)}
{currentSection === 'inventory' && (
<InventoryView
searchQuery={searchQuery}
isCoimbatoreView={isCoimbatoreView}
tenantId={tenantId}
/>
)}
{currentSection === 'reports' && (
<ReportsView
searchQuery={searchQuery}
isCoimbatoreView={isCoimbatoreView}
setIsCoimbatoreView={setIsCoimbatoreView}
tenantId={tenantId}
/>
)}
{/* Handle alternative sections: Settings */}
{['settings'].includes(currentSection) &&
renderSecondarySection()
}
)
} />
<Route path="inventory" element={
<InventoryView
searchQuery={searchQuery}
isCoimbatoreView={isCoimbatoreView}
tenantId={tenantId}
/>
} />
<Route path="reports" element={
<ReportsView
searchQuery={searchQuery}
isCoimbatoreView={isCoimbatoreView}
setIsCoimbatoreView={setIsCoimbatoreView}
tenantId={tenantId}
/>
} />
<Route path="settings" element={
<SettingsView tenantId={tenantId} user={authUser ?? undefined} />
} />
</Routes>
</div>
</main>
</div>
</div>
);
return (
<>
<Routes>
<Route path="/admin/*" element={AdminConsole} />
<Route path="*" element={<Navigate to="/admin/dashboard" replace />} />
</Routes>
{/* CALENDAR SCHEDULER DIALOG MODAL */}
{showCalendarModal && (
@@ -798,6 +793,6 @@ export default function App() {
)}
<ComparisonModal />
</div>
</>
);
}