udpates on the ui changesand api integration

This commit is contained in:
Gokul
2026-06-09 11:25:29 +05:30
parent 7dbae96b5f
commit 9f25c5f60a
26 changed files with 4324 additions and 2639 deletions

View File

@@ -9,7 +9,6 @@ import {
Truck,
Sliders,
Calendar,
AlertTriangle,
FileCheck,
Building,
CheckCircle2,
@@ -42,9 +41,54 @@ import ReportsView from './components/ReportsView';
import InventoryView from './components/InventoryView';
import SettingsView from './components/SettingsView';
import StoreDetailView from './components/StoreDetailView';
import LoginView from './components/LoginView';
import UserStorePage from './components/UserStorePage';
import AwaitingApi from './components/AwaitingApi';
import type { AuthUser } from './services/auth';
import ragulStoreCover from './assets/images/store_front_view_1780299351800.png';
const AUTH_STORAGE_KEY = 'nearledaily.auth';
/** Rehydrate the signed-in user from localStorage (keeps the session across refreshes). */
function loadStoredUser(): AuthUser | null {
try {
const raw = localStorage.getItem(AUTH_STORAGE_KEY);
if (!raw) return null;
const parsed = JSON.parse(raw) as AuthUser;
return parsed && typeof parsed === 'object' && (parsed.role === 'admin' || parsed.role === 'user')
? parsed
: null;
} catch {
return null;
}
}
export default function App() {
// Auth gate — null = signed out (show login). Admin → full dashboard, user →
// their single store console. The verified user is persisted to localStorage so
// a refresh keeps the session (rehydrated via the lazy initializer); authRole
// is derived from it so the two can't drift out of sync.
const [authUser, setAuthUser] = useState<AuthUser | null>(() => loadStoredUser());
const authRole = authUser?.role ?? null;
// Persist (or clear) the session whenever the signed-in user changes.
useEffect(() => {
try {
if (authUser) localStorage.setItem(AUTH_STORAGE_KEY, JSON.stringify(authUser));
else localStorage.removeItem(AUTH_STORAGE_KEY);
} catch {
/* storage unavailable (private mode / quota) — session just won't persist */
}
}, [authUser]);
const handleLogin = (user: AuthUser) => setAuthUser(user);
const currentUser = {
name: authUser?.name || 'Account',
role: authRole === 'admin' ? 'Operations Admin' : 'Team Member',
email: authUser?.email || '—',
};
// 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);
@@ -176,35 +220,53 @@ export default function App() {
const [showCalendarModal, setShowCalendarModal] = useState(false);
// Callback action triggers
const handleNewReport = () => {
setCurrentSection('reports');
alert('System routed back to reports dashboard interface. Select product item metadata matrices.');
};
const handleHelp = () => {
alert('nearledaily User Manual & Documentation Center linked successfully. Contact Coimbatore regional IT hub desk for urgent escalations.');
};
const handleLogout = () => {
const ok = window.confirm('Are you sure you want to terminate this active secure session?');
if (ok) {
alert('Secure session suspended. Page reloading and restarting database state simulation.');
window.location.reload();
}
};
const handleLogout = () => setAuthUser(null);
// Define secondary sections (Stores, Logistics, Staffing, Settings) within main body
const renderSecondarySection = () => {
switch (currentSection) {
case 'stores':
if (selectedStore) {
case 'stores': {
// A single-store merchant has no branches, so skip the one-card registry
// and open that store directly. Add a branch (2+ stores) and the grid
// returns automatically. Clicking a card in multi-store mode also opens
// the console, with a Back-to-registry button.
const isSoleStore = !selectedStore && storesList.length === 1;
const activeStore = selectedStore ?? (isSoleStore ? storesList[0] : null);
if (activeStore) {
return (
<StoreDetailView
store={selectedStore}
onBack={() => setSelectedStore(null)}
/>
<div className="space-y-md animate-in fade-in duration-300">
{isSoleStore && (
<div className="flex flex-col md:flex-row md:items-center justify-between gap-4 pb-4 border-b border-zinc-205">
<div>
<h1 className="font-sans font-bold text-2xl tracking-tight text-[#0f172a]">
Store Console
</h1>
<p className="text-zinc-500 font-sans text-xs mt-1">
This merchant operates a single store. Add a branch to manage multiple outlets.
</p>
</div>
<button
onClick={() => setShowAddStoreModal(true)}
className="bg-[#581c87] text-white px-5 py-2.5 rounded-lg text-xs font-bold uppercase tracking-wider flex items-center justify-center gap-2 cursor-pointer hover:bg-purple-800 transition shadow-sm self-start md:self-auto"
>
<Plus className="w-4 h-4" />
Add Retail Outlet Node
</button>
</div>
)}
<StoreDetailView
store={activeStore}
onBack={selectedStore ? () => setSelectedStore(null) : undefined}
/>
</div>
);
}
return (
<div className="space-y-lg animate-in fade-in duration-300">
{/* Simple and elegant premium header */}
@@ -468,6 +530,7 @@ export default function App() {
</div>
</div>
);
}
case 'settings':
return <SettingsView tenantId={FIESTA_TENANT_ID} />;
@@ -477,6 +540,17 @@ 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 (
<div className="min-h-screen bg-[#f8fafc] text-[#0f172a] font-sans antialiased">
{/* Navbar segment */}
@@ -486,9 +560,9 @@ export default function App() {
isCoimbatoreView={isCoimbatoreView}
onToggleSidebar={() => setSidebarOpen((prev) => !prev)}
isSidebarOpen={sidebarOpen}
onNewReportClick={handleNewReport}
onHelpClick={handleHelp}
onLogoutClick={handleLogout}
profile={currentUser}
/>
{/* Main Container workspace layout splits */}
@@ -556,28 +630,10 @@ export default function App() {
<div className="p-md space-y-md overflow-y-auto flex-1">
<p className="text-zinc-500 leading-relaxed font-semibold">
Automated compliance summaries are scheduled to generate and export on the following dates:
Automated compliance summaries will appear here once scheduled-report exports are available.
</p>
<div className="divide-y divide-[#f1f5f9] select-none text-[11px]">
<div className="py-2 flex justify-between items-center">
<span className="font-semibold text-zinc-700">Monthly Assortment Audit Ledger</span>
<span className="font-mono text-[#581c87] font-bold">Oct 31, 2023</span>
</div>
<div className="py-2 flex justify-between items-center">
<span className="font-semibold text-zinc-700">Daily Regional Turnover Sheet</span>
<span className="text-emerald-600 font-bold">Everyday 23:59 (GMT)</span>
</div>
<div className="py-2 flex justify-between items-center">
<span className="font-semibold text-zinc-700">Q4 Outlook Forecast Draft</span>
<span className="font-mono text-zinc-500 font-bold">Nov 15, 2023</span>
</div>
</div>
<div className="p-sm bg-amber-50 border border-amber-100 rounded-lg flex gap-sm text-amber-900 font-medium">
<AlertTriangle size={16} className="shrink-0 mt-0.5" />
<span>Next automated sync will occur at standard local closing hour thresholds.</span>
</div>
<AwaitingApi label="Scheduled reports" api="[R13]" />
</div>
<div className="p-sm bg-[#f8fafc] border-t border-[#e2e8f0] flex justify-end shrink-0">