Site resource conservation added, for faster loading time. Only for Admin Frontend

This commit is contained in:
Sidharth Prabhu
2026-08-04 13:54:34 +05:30
parent 1a000a3be2
commit 6750c5456f
36 changed files with 352 additions and 306 deletions

View File

@@ -0,0 +1,9 @@
import{m as e,t,u as n}from"./index-Cw6Vy2ED.js";import{a as r,c as i,i as a,n as o,o as s,r as c,s as l}from"./proxy-D2DvKtgS.js";var u=t(),d=e(n(),1);function f(e,t){if(typeof e==`function`)return e(t);e!=null&&(e.current=t)}function p(...e){return t=>{let n=!1,r=e.map(e=>{let r=f(e,t);return!n&&typeof r==`function`&&(n=!0),r});if(n)return()=>{for(let t=0;t<r.length;t++){let n=r[t];typeof n==`function`?n():f(e[t],null)}}}}function m(...e){return d.useCallback(p(...e),e)}var h=class extends d.Component{getSnapshotBeforeUpdate(e){let t=this.props.childRef.current;if(a(t)&&e.isPresent&&!this.props.isPresent&&this.props.pop!==!1){let e=t.offsetParent,n=a(e)&&e.offsetWidth||0,r=a(e)&&e.offsetHeight||0,i=getComputedStyle(t),o=this.props.sizeRef.current;o.height=parseFloat(i.height),o.width=parseFloat(i.width),o.top=t.offsetTop,o.left=t.offsetLeft,o.right=n-o.width-o.left,o.bottom=r-o.height-o.top}return null}componentDidUpdate(){}render(){return this.props.children}};function g({children:e,isPresent:t,anchorX:n,anchorY:r,root:i,pop:a}){let o=(0,d.useId)(),s=(0,d.useRef)(null),l=(0,d.useRef)({width:0,height:0,top:0,left:0,right:0,bottom:0}),{nonce:f}=(0,d.useContext)(c),p=m(s,e.props?.ref??e?.ref);return(0,d.useInsertionEffect)(()=>{let{width:e,height:c,top:u,left:d,right:p,bottom:m}=l.current;if(t||a===!1||!s.current||!e||!c)return;let h=n===`left`?`left: ${d}`:`right: ${p}`,g=r===`bottom`?`bottom: ${m}`:`top: ${u}`;s.current.dataset.motionPopId=o;let _=document.createElement(`style`);f&&(_.nonce=f);let v=i??document.head;return v.appendChild(_),_.sheet&&_.sheet.insertRule(`
[data-motion-pop-id="${o}"] {
position: absolute !important;
width: ${e}px !important;
height: ${c}px !important;
${h}px !important;
${g}px !important;
}
`),()=>{s.current?.removeAttribute(`data-motion-pop-id`),v.contains(_)&&v.removeChild(_)}},[t]),(0,u.jsx)(h,{isPresent:t,childRef:s,sizeRef:l,pop:a,children:a===!1?e:d.cloneElement(e,{ref:p})})}var _=({children:e,initial:t,isPresent:n,onExitComplete:i,custom:a,presenceAffectsLayout:o,mode:s,anchorX:c,anchorY:f,root:p})=>{let m=l(v),h=(0,d.useId)(),_=!0,y=(0,d.useMemo)(()=>(_=!1,{id:h,initial:t,isPresent:n,custom:a,onExitComplete:e=>{m.set(e,!0);for(let e of m.values())if(!e)return;i&&i()},register:e=>(m.set(e,!1),()=>m.delete(e))}),[n,m,i]);return o&&_&&(y={...y}),(0,d.useMemo)(()=>{m.forEach((e,t)=>m.set(t,!1))},[n]),d.useEffect(()=>{!n&&!m.size&&i&&i()},[n]),e=(0,u.jsx)(g,{pop:s===`popLayout`,isPresent:n,anchorX:c,anchorY:f,root:p,children:e}),(0,u.jsx)(r.Provider,{value:y,children:e})};function v(){return new Map}var y=e=>e.key||``;function b(e){let t=[];return d.Children.forEach(e,e=>{(0,d.isValidElement)(e)&&t.push(e)}),t}var x=({children:e,custom:t,initial:n=!0,onExitComplete:r,presenceAffectsLayout:a=!0,mode:c=`sync`,propagate:f=!1,anchorX:p=`left`,anchorY:m=`top`,root:h})=>{let[g,v]=o(f),x=(0,d.useMemo)(()=>b(e),[e]),S=f&&!g?[]:x.map(y),C=(0,d.useRef)(!0),w=(0,d.useRef)(x),T=l(()=>new Map),E=(0,d.useRef)(new Set),[D,O]=(0,d.useState)(x),[k,A]=(0,d.useState)(x);s(()=>{C.current=!1,w.current=x;for(let e=0;e<k.length;e++){let t=y(k[e]);S.includes(t)?(T.delete(t),E.current.delete(t)):T.get(t)!==!0&&T.set(t,!1)}},[k,S.length,S.join(`-`)]);let j=[];if(x!==D){let e=[...x];for(let t=0;t<k.length;t++){let n=k[t],r=y(n);S.includes(r)||(e.splice(t,0,n),j.push(n))}return c===`wait`&&j.length&&(e=j),A(b(e)),O(x),null}let{forceRender:M}=(0,d.useContext)(i);return(0,u.jsx)(u.Fragment,{children:k.map(e=>{let i=y(e),o=f&&!g?!1:x===k||S.includes(i);return(0,u.jsx)(_,{isPresent:o,initial:!C.current||n?void 0:!1,custom:t,presenceAffectsLayout:a,mode:c,root:h,onExitComplete:o?void 0:()=>{if(E.current.has(i))return;if(T.has(i))E.current.add(i),T.set(i,!0);else return;let e=!0;T.forEach(t=>{t||(e=!1)}),e&&(M?.(),A(w.current),f&&v?.(),r&&r())},anchorX:p,anchorY:m,children:e},i)})})};export{x as t};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
import{c as e,t,u as n}from"./index-Cw6Vy2ED.js";var r=e(`chevron-left`,[[`path`,{d:`m15 18-6-6 6-6`,key:`1wnfg3`}]]),i=e(`chevron-right`,[[`path`,{d:`m9 18 6-6-6-6`,key:`mthhwq`}]]);n();var a=t(),o=({currentPage:e,pageSize:t,totalElements:n,onPageChange:o,onPageSizeChange:s})=>{let c=Math.ceil(n/t),l=e*t+1,u=Math.min((e+1)*t,n);return n===0?null:(0,a.jsxs)(`div`,{className:`px-8 py-6 border-t border-slate-100 flex flex-col sm:flex-row items-center justify-between gap-6 bg-white shrink-0`,children:[(0,a.jsxs)(`div`,{className:`flex items-center gap-4`,children:[(0,a.jsx)(`span`,{className:`text-xs font-black text-slate-400 uppercase tracking-widest leading-none`,children:`Show`}),(0,a.jsx)(`select`,{value:t,onChange:e=>s(Number(e.target.value)),className:`bg-slate-50 border border-slate-200 rounded-xl px-4 py-2 text-xs font-black text-slate-900 outline-none focus:ring-4 focus:ring-primary/5 focus:border-primary transition-all appearance-none pr-8 relative`,style:{backgroundImage:`url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke='%2394a3b8'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M19 9l-7 7-7-7'%3E%3C/path%3E%3C/svg%3E")`,backgroundRepeat:`no-repeat`,backgroundPosition:`right 0.5rem center`,backgroundSize:`1rem`},children:[5,10,25,50].map(e=>(0,a.jsxs)(`option`,{value:e,children:[e,` items`]},e))}),(0,a.jsxs)(`span`,{className:`text-[10px] font-bold text-slate-300 uppercase tracking-widest whitespace-nowrap`,children:[l,`-`,u,` of `,n,` units`]})]}),(0,a.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,a.jsx)(`button`,{disabled:e===0,onClick:()=>o(e-1),className:`w-10 h-10 flex items-center justify-center rounded-xl border border-slate-100 text-slate-400 hover:text-primary hover:bg-primary/5 disabled:opacity-30 disabled:hover:bg-transparent transition-all`,children:(0,a.jsx)(r,{size:18})}),(0,a.jsx)(`div`,{className:`flex items-center gap-1`,children:Array.from({length:c},(t,n)=>(0,a.jsx)(`button`,{onClick:()=>o(n),className:`w-10 h-10 font-bold text-xs rounded-xl transition-all ${e===n?`bg-primary text-white shadow-lg shadow-primary/20`:`text-slate-400 hover:bg-slate-50`}`,children:n+1},n)).slice(Math.max(0,e-1),Math.min(c,e+2))}),(0,a.jsx)(`button`,{disabled:e>=c-1,onClick:()=>o(e+1),className:`w-10 h-10 flex items-center justify-center rounded-xl border border-slate-100 text-slate-400 hover:text-primary hover:bg-primary/5 disabled:opacity-30 disabled:hover:bg-transparent transition-all`,children:(0,a.jsx)(i,{size:18})})]})]})};export{o as t};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
import{c as e}from"./index-Cw6Vy2ED.js";var t=e(`minus`,[[`path`,{d:`M5 12h14`,key:`1ays0h`}]]);export{t};

View File

@@ -0,0 +1 @@
import{c as e}from"./index-Cw6Vy2ED.js";var t=e(`plus`,[[`path`,{d:`M5 12h14`,key:`1ays0h`}],[`path`,{d:`M12 5v14`,key:`s699le`}]]);export{t};

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 204 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 MiB

View File

@@ -0,0 +1 @@
import{c as e}from"./index-Cw6Vy2ED.js";var t=e(`trash-2`,[[`path`,{d:`M10 11v6`,key:`nco0om`}],[`path`,{d:`M14 11v6`,key:`outv1u`}],[`path`,{d:`M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6`,key:`miytrc`}],[`path`,{d:`M3 6h18`,key:`d0wm0j`}],[`path`,{d:`M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2`,key:`e791ji`}]]);export{t};

View File

@@ -0,0 +1 @@
import{c as e}from"./index-Cw6Vy2ED.js";var t=e(`check`,[[`path`,{d:`M20 6 9 17l-5-5`,key:`1gmf2c`}]]),n=e(`pen`,[[`path`,{d:`M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z`,key:`1a8usu`}]]),r=e(`x`,[[`path`,{d:`M18 6 6 18`,key:`1bl5f8`}],[`path`,{d:`m6 6 12 12`,key:`d8bk6v`}]]);export{n,t as r,r as t};

View File

@@ -5,8 +5,8 @@
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Counter POS</title>
<script type="module" crossorigin src="/assets/index-C3UP9F-T.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-8tt0cn-G.css">
<script type="module" crossorigin src="/assets/index-Cw6Vy2ED.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-HWj_Y8q4.css">
</head>
<body>
<div id="root"></div>

View File

@@ -1,34 +1,46 @@
import React from 'react';
import React, { lazy, Suspense } from 'react';
import { BrowserRouter as Router, Routes, Route, Navigate } from 'react-router-dom';
import Login from './pages/Login';
import POS from './pages/POS';
import Orders from './pages/Orders';
import Categories from './pages/Categories';
import Products from './pages/Products';
import Layout from './components/Layout';
// Lazy load pages to decrease initial bundle size
const Login = lazy(() => import('./pages/Login'));
const POS = lazy(() => import('./pages/POS'));
const Orders = lazy(() => import('./pages/Orders'));
const Categories = lazy(() => import('./pages/Categories'));
const Products = lazy(() => import('./pages/Products'));
const ProtectedRoute = ({ children }: { children: React.ReactNode }) => {
const isLoggedIn = sessionStorage.getItem('isCounterLoggedIn') === 'true';
return isLoggedIn ? <>{children}</> : <Navigate to="/login" replace />;
};
const LoadingFallback = () => (
<div className="min-h-screen flex items-center justify-center bg-[#f4fbf7]">
<div className="text-primary font-black uppercase tracking-widest text-sm animate-pulse">
Loading...
</div>
</div>
);
function App() {
return (
<Router>
<Routes>
<Route path="/login" element={<Login />} />
<Route path="/" element={
<ProtectedRoute>
<Layout />
</ProtectedRoute>
}>
<Route index element={<Navigate to="/pos" replace />} />
<Route path="pos" element={<POS />} />
<Route path="orders" element={<Orders />} />
<Route path="categories" element={<Categories />} />
<Route path="products" element={<Products />} />
</Route>
</Routes>
<Suspense fallback={<LoadingFallback />}>
<Routes>
<Route path="/login" element={<Login />} />
<Route path="/" element={
<ProtectedRoute>
<Layout />
</ProtectedRoute>
}>
<Route index element={<Navigate to="/pos" replace />} />
<Route path="pos" element={<POS />} />
<Route path="orders" element={<Orders />} />
<Route path="categories" element={<Categories />} />
<Route path="products" element={<Products />} />
</Route>
</Routes>
</Suspense>
</Router>
);
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

After

Width:  |  Height:  |  Size: 204 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 MiB

After

Width:  |  Height:  |  Size: 41 KiB

View File

@@ -26,7 +26,7 @@ const Login = () => {
e.preventDefault();
try {
const host = window.location.hostname;
const response = await fetch(`https://cmsapi.rit-services.in/api/system/login`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },

View File

@@ -1,101 +1,111 @@
import { BrowserRouter as Router, Routes, Route, Navigate } from 'react-router-dom';
import { lazy, Suspense } from 'react';
import Layout from './components/Layout.tsx';
import Dashboard from './pages/Dashboard.tsx';
import BaseMenu from './pages/BaseMenu.tsx';
import Products from './pages/Products.tsx';
import Orders from './pages/Orders.tsx';
import ArchivedOrders from './pages/ArchivedOrders.tsx';
import Customers from './pages/Customers.tsx';
import Login from './pages/Login.tsx';
import Managers from './pages/Managers.tsx';
import Stalls from './pages/Stalls.tsx';
import Staff from './pages/Staff.tsx';
import Terminals from './pages/Terminals.tsx';
import Vendors from './pages/Vendors.tsx';
import Purchases from './pages/Purchases.tsx';
import VendorDashboard from './pages/VendorDashboard.tsx';
import PurchaseAnalytics from './pages/PurchaseAnalytics.tsx';
import Bills from './pages/Bills.tsx';
import PurchaseSummary from './pages/PurchaseSummary.tsx';
import IntentDashboard from './pages/IntentDashboard.tsx';
import IntentList from './pages/IntentList.tsx';
import NewArrivals from './pages/NewArrivals.tsx';
import Reports from './pages/Reports.tsx';
import Feedback from './pages/Feedback.tsx';
import Ritz from './pages/Ritz.tsx';
import RitzCirculation from './pages/RitzCirculation.tsx';
import ManageWallets from './pages/ManageWallets.tsx';
import ManageCoupons from './pages/ManageCoupons.tsx';
import Settings from './pages/Settings.tsx';
import NotFound from './pages/NotFound.tsx';
// Lazy load pages to decrease initial bundle size
const Dashboard = lazy(() => import('./pages/Dashboard.tsx'));
const BaseMenu = lazy(() => import('./pages/BaseMenu.tsx'));
const Products = lazy(() => import('./pages/Products.tsx'));
const Orders = lazy(() => import('./pages/Orders.tsx'));
const ArchivedOrders = lazy(() => import('./pages/ArchivedOrders.tsx'));
const Customers = lazy(() => import('./pages/Customers.tsx'));
const Login = lazy(() => import('./pages/Login.tsx'));
const Managers = lazy(() => import('./pages/Managers.tsx'));
const Stalls = lazy(() => import('./pages/Stalls.tsx'));
const Staff = lazy(() => import('./pages/Staff.tsx'));
const Terminals = lazy(() => import('./pages/Terminals.tsx'));
const Vendors = lazy(() => import('./pages/Vendors.tsx'));
const Purchases = lazy(() => import('./pages/Purchases.tsx'));
const VendorDashboard = lazy(() => import('./pages/VendorDashboard.tsx'));
const PurchaseAnalytics = lazy(() => import('./pages/PurchaseAnalytics.tsx'));
const Bills = lazy(() => import('./pages/Bills.tsx'));
const PurchaseSummary = lazy(() => import('./pages/PurchaseSummary.tsx'));
const IntentDashboard = lazy(() => import('./pages/IntentDashboard.tsx'));
const IntentList = lazy(() => import('./pages/IntentList.tsx'));
const NewArrivals = lazy(() => import('./pages/NewArrivals.tsx'));
const Reports = lazy(() => import('./pages/Reports.tsx'));
const Feedback = lazy(() => import('./pages/Feedback.tsx'));
const Ritz = lazy(() => import('./pages/Ritz.tsx'));
const RitzCirculation = lazy(() => import('./pages/RitzCirculation.tsx'));
const ManageWallets = lazy(() => import('./pages/ManageWallets.tsx'));
const ManageCoupons = lazy(() => import('./pages/ManageCoupons.tsx'));
const Settings = lazy(() => import('./pages/Settings.tsx'));
const NotFound = lazy(() => import('./pages/NotFound.tsx'));
const ProtectedRoute = ({ children }: { children: React.ReactNode }) => {
const isLoggedIn = sessionStorage.getItem('isLoggedIn') === 'true';
return isLoggedIn ? <>{children}</> : <Navigate to="/login" replace />;
};
const LoadingFallback = () => (
<div className="min-h-screen flex items-center justify-center bg-slate-50/50">
<div className="text-primary font-black uppercase tracking-widest text-sm animate-pulse">
Loading...
</div>
</div>
);
function App() {
return (
<Router>
<Routes>
<Route path="/login" element={<Login />} />
<Route path="/" element={
<ProtectedRoute>
<Layout />
</ProtectedRoute>
}>
<Route index element={<Navigate to="/dashboard" replace />} />
<Route path="dashboard" element={<Dashboard />} />
{/* Sale */}
<Route path="sale/orders" element={<Orders />} />
<Route path="sale/archived-bills" element={<ArchivedOrders />} />
{/* Customers */}
<Route path="customers/orders" element={<Customers />} />
{/* Purchases */}
<Route path="purchases/dashboard" element={<VendorDashboard />} />
<Route path="purchases/orders" element={<Purchases />} />
<Route path="purchases/summary" element={<PurchaseSummary />} />
<Route path="purchases/bills" element={<Bills />} />
<Route path="purchases/vendor" element={<Vendors />} />
<Route path="purchases/analytics" element={<PurchaseAnalytics />} />
{/* Intent */}
<Route path="purchases/intent/orders-dashboard" element={<IntentDashboard title="ORDER DASHBOARD" />} />
<Route path="purchases/intent/receives-dashboard" element={<IntentDashboard title="RECEIVABLE DASHBOARD" />} />
<Route path="purchases/intent/orders" element={<IntentList title="ORDERS" />} />
<Route path="purchases/intent/receives" element={<IntentList title="RECEIVES" />} />
<Suspense fallback={<LoadingFallback />}>
<Routes>
<Route path="/login" element={<Login />} />
<Route path="/" element={
<ProtectedRoute>
<Layout />
</ProtectedRoute>
}>
<Route index element={<Navigate to="/dashboard" replace />} />
<Route path="dashboard" element={<Dashboard />} />
{/* Sale */}
<Route path="sale/orders" element={<Orders />} />
<Route path="sale/archived-bills" element={<ArchivedOrders />} />
{/* Customers */}
<Route path="customers/orders" element={<Customers />} />
{/* Purchases */}
<Route path="purchases/dashboard" element={<VendorDashboard />} />
<Route path="purchases/orders" element={<Purchases />} />
<Route path="purchases/summary" element={<PurchaseSummary />} />
<Route path="purchases/bills" element={<Bills />} />
<Route path="purchases/vendor" element={<Vendors />} />
<Route path="purchases/analytics" element={<PurchaseAnalytics />} />
{/* Intent */}
<Route path="purchases/intent/orders-dashboard" element={<IntentDashboard title="ORDER DASHBOARD" />} />
<Route path="purchases/intent/receives-dashboard" element={<IntentDashboard title="RECEIVABLE DASHBOARD" />} />
<Route path="purchases/intent/orders" element={<IntentList title="ORDERS" />} />
<Route path="purchases/intent/receives" element={<IntentList title="RECEIVES" />} />
{/* Inventory */}
<Route path="inventory/new-arrivals" element={<NewArrivals />} />
<Route path="inventory/base" element={<BaseMenu />} />
<Route path="inventory/products" element={<Products />} />
<Route path="inventory/online" element={<Navigate to="/inventory/products" replace />} />
{/* Others */}
<Route path="reports" element={<Reports />} />
<Route path="feedback" element={<Feedback />} />
<Route path="ritz/overview" element={<Ritz />} />
<Route path="ritz/circulation" element={<RitzCirculation />} />
<Route path="ritz/wallets" element={<ManageWallets />} />
<Route path="ritz/coupons" element={<ManageCoupons />} />
{/* Inventory */}
<Route path="inventory/new-arrivals" element={<NewArrivals />} />
<Route path="inventory/base" element={<BaseMenu />} />
<Route path="inventory/products" element={<Products />} />
<Route path="inventory/online" element={<Navigate to="/inventory/products" replace />} />
{/* Others */}
<Route path="reports" element={<Reports />} />
<Route path="feedback" element={<Feedback />} />
<Route path="ritz/overview" element={<Ritz />} />
<Route path="ritz/circulation" element={<RitzCirculation />} />
<Route path="ritz/wallets" element={<ManageWallets />} />
<Route path="ritz/coupons" element={<ManageCoupons />} />
{/* Stores */}
<Route path="stores/terminals" element={<Terminals />} />
<Route path="stores/managers" element={<Managers />} />
<Route path="stores/staffs" element={<Staff />} />
<Route path="stores/stalls" element={<Stalls />} />
{/* Stores */}
<Route path="stores/terminals" element={<Terminals />} />
<Route path="stores/managers" element={<Managers />} />
<Route path="stores/staffs" element={<Staff />} />
<Route path="stores/stalls" element={<Stalls />} />
{/* Settings */}
<Route path="settings" element={<Settings />} />
</Route>
<Route path="*" element={<NotFound />} />
</Routes>
{/* Settings */}
<Route path="settings" element={<Settings />} />
</Route>
<Route path="*" element={<NotFound />} />
</Routes>
</Suspense>
</Router>
);
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

After

Width:  |  Height:  |  Size: 204 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 MiB

After

Width:  |  Height:  |  Size: 41 KiB

View File

@@ -19,7 +19,7 @@ import { motion, AnimatePresence } from 'framer-motion';
import { clsx, type ClassValue } from 'clsx';
import { twMerge } from 'tailwind-merge';
import collegeLogo from '../assets/college-logo.png';
import colorVector from '../assets/color-vector.png';
import colorVector from '../assets/color-vector.webp';
function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));

View File

@@ -1,4 +1,4 @@
import { apiFetch } from '../api';
import { apiFetch } from '../api';
import React, { useState, useEffect } from 'react';
import {
Building2,
@@ -14,7 +14,7 @@ import {
Fingerprint
} from 'lucide-react';
import { motion } from 'framer-motion';
import colorVector from '../assets/color-vector.png';
import colorVector from '../assets/color-vector.webp';
interface TokenTransaction {
id: number;

View File

@@ -1,4 +1,4 @@
import { apiFetch } from '../api';
import { apiFetch } from '../api';
import React, { useState, useEffect } from 'react';
import {
CircleDollarSign,
@@ -15,7 +15,7 @@ import {
ChevronRight
} from 'lucide-react';
import { motion } from 'framer-motion';
import colorVector from '../assets/color-vector.png';
import colorVector from '../assets/color-vector.webp';
interface TokenUnit {
id: number;

View File

@@ -1,110 +1,121 @@
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import { lazy, Suspense } from 'react';
import { CartProvider } from './contexts/CartContext';
import { AuthProvider } from './contexts/AuthContext';
import { FoodProvider } from './contexts/FoodContext';
import { ThemeProvider } from './contexts/ThemeContext';
import ProtectedRoute from './components/ProtectedRoute';
import HomeScreen from './pages/HomeScreen';
import CategoryScreen from './pages/CategoryScreen';
import ItemDetailScreen from './pages/ItemDetailScreen';
import CartScreen from './pages/CartScreen';
import CheckoutScreen from './pages/CheckoutScreen';
import SuccessScreen from './pages/SuccessScreen';
import MyOrdersScreen from './pages/MyOrdersScreen';
import LoginScreen from './pages/LoginScreen';
import ProfileScreen from './pages/ProfileScreen';
import ChangePinScreen from './pages/ChangePinScreen';
import StallDetailScreen from './pages/StallDetailScreen';
import WalletScreen from './pages/WalletScreen';
import TopUpScreen from './pages/TopUpScreen';
import PreferencesScreen from './pages/PreferencesScreen';
import NotFoundScreen from './pages/NotFoundScreen';
import StockAlert from './components/StockAlert';
import './App.css';
// Lazy load screens
const HomeScreen = lazy(() => import('./pages/HomeScreen'));
const CategoryScreen = lazy(() => import('./pages/CategoryScreen'));
const ItemDetailScreen = lazy(() => import('./pages/ItemDetailScreen'));
const CartScreen = lazy(() => import('./pages/CartScreen'));
const CheckoutScreen = lazy(() => import('./pages/CheckoutScreen'));
const SuccessScreen = lazy(() => import('./pages/SuccessScreen'));
const MyOrdersScreen = lazy(() => import('./pages/MyOrdersScreen'));
const LoginScreen = lazy(() => import('./pages/LoginScreen'));
const ProfileScreen = lazy(() => import('./pages/ProfileScreen'));
const ChangePinScreen = lazy(() => import('./pages/ChangePinScreen'));
const StallDetailScreen = lazy(() => import('./pages/StallDetailScreen'));
const WalletScreen = lazy(() => import('./pages/WalletScreen'));
const TopUpScreen = lazy(() => import('./pages/TopUpScreen'));
const PreferencesScreen = lazy(() => import('./pages/PreferencesScreen'));
const NotFoundScreen = lazy(() => import('./pages/NotFoundScreen'));
const LoadingFallback = () => (
<div className="container" style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', height: '100vh' }}>
<div className="loading-spinner">Loading...</div>
</div>
);
function App() {
return (
<ThemeProvider>
<AuthProvider>
<FoodProvider>
<CartProvider>
<StockAlert />
<Router>
<Routes>
<Route path="/login" element={<LoginScreen />} />
<Route path="/" element={
<ProtectedRoute>
<HomeScreen />
</ProtectedRoute>
} />
<Route path="/orders" element={
<ProtectedRoute>
<MyOrdersScreen />
</ProtectedRoute>
} />
<Route path="/category/:categoryId" element={
<ProtectedRoute>
<CategoryScreen />
</ProtectedRoute>
} />
<Route path="/item/:itemId" element={
<ProtectedRoute>
<ItemDetailScreen />
</ProtectedRoute>
} />
<Route path="/stall/:id" element={
<ProtectedRoute>
<StallDetailScreen />
</ProtectedRoute>
} />
<Route path="/cart" element={
<ProtectedRoute>
<CartScreen />
</ProtectedRoute>
} />
<Route path="/checkout" element={
<ProtectedRoute>
<CheckoutScreen />
</ProtectedRoute>
} />
<Route path="/success" element={
<ProtectedRoute>
<SuccessScreen />
</ProtectedRoute>
} />
<Route path="/profile" element={
<ProtectedRoute>
<ProfileScreen />
</ProtectedRoute>
} />
<Route path="/change-pin" element={
<ProtectedRoute>
<ChangePinScreen />
</ProtectedRoute>
} />
<Route path="/wallet" element={
<ProtectedRoute>
<WalletScreen />
</ProtectedRoute>
} />
<Route path="/topup" element={
<ProtectedRoute>
<TopUpScreen />
</ProtectedRoute>
} />
<Route path="/preferences" element={
<ProtectedRoute>
<PreferencesScreen />
</ProtectedRoute>
} />
<Route path="*" element={<NotFoundScreen />} />
</Routes>
</Router>
</CartProvider>
</FoodProvider>
</AuthProvider>
<StockAlert />
<Router>
<Suspense fallback={<LoadingFallback />}>
<Routes>
<Route path="/login" element={<LoginScreen />} />
<Route path="/" element={
<ProtectedRoute>
<HomeScreen />
</ProtectedRoute>
} />
<Route path="/orders" element={
<ProtectedRoute>
<MyOrdersScreen />
</ProtectedRoute>
} />
<Route path="/category/:categoryId" element={
<ProtectedRoute>
<CategoryScreen />
</ProtectedRoute>
} />
<Route path="/item/:itemId" element={
<ProtectedRoute>
<ItemDetailScreen />
</ProtectedRoute>
} />
<Route path="/stall/:id" element={
<ProtectedRoute>
<StallDetailScreen />
</ProtectedRoute>
} />
<Route path="/cart" element={
<ProtectedRoute>
<CartScreen />
</ProtectedRoute>
} />
<Route path="/checkout" element={
<ProtectedRoute>
<CheckoutScreen />
</ProtectedRoute>
} />
<Route path="/success" element={
<ProtectedRoute>
<SuccessScreen />
</ProtectedRoute>
} />
<Route path="/profile" element={
<ProtectedRoute>
<ProfileScreen />
</ProtectedRoute>
} />
<Route path="/change-pin" element={
<ProtectedRoute>
<ChangePinScreen />
</ProtectedRoute>
} />
<Route path="/wallet" element={
<ProtectedRoute>
<WalletScreen />
</ProtectedRoute>
} />
<Route path="/topup" element={
<ProtectedRoute>
<TopUpScreen />
</ProtectedRoute>
} />
<Route path="/preferences" element={
<ProtectedRoute>
<PreferencesScreen />
</ProtectedRoute>
} />
<Route path="*" element={<NotFoundScreen />} />
</Routes>
</Suspense>
</Router>
</CartProvider>
</FoodProvider>
</AuthProvider>
</ThemeProvider>
);
}

View File

@@ -8,7 +8,7 @@ import {
PlusCircle,
CreditCard
} from 'lucide-react';
import tokenImage from '../assets/display_ritz.png';
import tokenImage from '../assets/display_ritz.webp';
import { motion, AnimatePresence } from 'framer-motion';
import Header from '../components/Header';
import StockConflictModal from '../components/StockConflictModal';

View File

@@ -9,7 +9,7 @@ import FeedbackModal from '../components/FeedbackModal';
import { useFood } from '../contexts/FoodContext';
import { useAuth } from '../contexts/AuthContext';
import { motion, AnimatePresence } from 'framer-motion';
import walletIcon from '../assets/front.png';
import walletIcon from '../assets/front.webp';
import './HomeScreen.css';
const HomeScreen: React.FC = () => {