feat: complete security overhaul with JWT backend and authenticated frontend API

This commit is contained in:
Shanmuga Krishnan S M
2026-04-28 14:30:03 +05:30
parent 655fb251b9
commit b13ee0195b
50 changed files with 1004 additions and 404 deletions

View File

@@ -1,3 +1,4 @@
import { apiFetch } from '../api';
import React, { useState, useEffect, useMemo } from 'react';
import {
Search,
@@ -77,7 +78,7 @@ const ArchivedOrders: React.FC = () => {
params.append('page', currentPage.toString());
params.append('size', pageSize.toString());
const response = await fetch(`http://${window.location.hostname}:8080/api/orders/all?${params.toString()}`);
const response = await apiFetch(`http://${window.location.hostname}:8080/api/orders/all?${params.toString()}`);
const data = await response.json();
if (data && data.content && Array.isArray(data.content)) {

View File

@@ -1,3 +1,4 @@
import { apiFetch } from '../api';
import React, { useState, useEffect, useRef } from 'react';
import { Plus, X, Search, Filter, MoreVertical, RefreshCw, Edit2, Power, PowerOff, ShoppingCart, Package, ExternalLink } from 'lucide-react';
import Pagination from '../components/Pagination';
@@ -78,7 +79,7 @@ const BaseMenu = () => {
params.append('search', debouncedSearchTerm);
}
const response = await fetch(`http://${host}:8080/api/base-items?${params.toString()}`);
const response = await apiFetch(`http://${host}:8080/api/base-items?${params.toString()}`);
const data = await response.json();
if (data && data.content) {
setItems(data.content);
@@ -99,7 +100,7 @@ const BaseMenu = () => {
setShowProductsModal(true);
setProductsLoading(true);
try {
const response = await fetch(`http://localhost:8080/api/products/category/${encodeURIComponent(baseItem.name)}`);
const response = await apiFetch(`http://localhost:8080/api/products/category/${encodeURIComponent(baseItem.name)}`);
const data = await response.json();
setAssociatedProducts(data);
} catch (error) {
@@ -117,7 +118,7 @@ const BaseMenu = () => {
const method = editingItem ? 'PUT' : 'POST';
try {
const response = await fetch(url, {
const response = await apiFetch(url, {
method,
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(newItem),
@@ -142,7 +143,7 @@ const BaseMenu = () => {
const handleToggleActive = async (item: BaseItem) => {
try {
const response = await fetch(`http://localhost:8080/api/base-items/${item.id}`, {
const response = await apiFetch(`http://localhost:8080/api/base-items/${item.id}`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ ...item, active: !item.active }),

View File

@@ -1,3 +1,4 @@
import { apiFetch } from '../api';
import React, { useState, useEffect } from 'react';
import { Search, ChevronRight, Filter, Loader2, Download, Printer, X } from 'lucide-react';
import { format } from 'date-fns';
@@ -31,7 +32,7 @@ const Bills: React.FC = () => {
const fetchOrders = async () => {
try {
setIsLoading(true);
const response = await fetch('/api/purchases/orders');
const response = await apiFetch('/api/purchases/orders');
if (response.ok) {
const data = await response.json();
setOrders(data);
@@ -50,7 +51,7 @@ const Bills: React.FC = () => {
setIsSaving(true);
const updatedPaidTotal = Number(selectedOrder.paidTotal) + Number(paymentAmount);
const response = await fetch('/api/purchases/orders', {
const response = await apiFetch('/api/purchases/orders', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({

View File

@@ -1,3 +1,4 @@
import { apiFetch } from '../api';
import React, { useState, useEffect } from 'react';
import { Search, User, Phone, Tag, ChevronRight, UserCheck, UserMinus, MoreVertical, LayoutGrid, List, Edit2, Trash2, Shield, X, Eye, EyeOff, Loader2, AlertCircle, CheckCircle, CircleDollarSign } from 'lucide-react';
import Pagination from '../components/Pagination';
@@ -63,7 +64,7 @@ const Customers: React.FC = () => {
params.append('search', debouncedSearchTerm);
}
const response = await fetch(`http://${host}:8080/api/auth/users?${params.toString()}`);
const response = await apiFetch(`http://${host}:8080/api/auth/users?${params.toString()}`);
if (response.ok) {
const data = await response.json();
if (data && data.content) {
@@ -106,7 +107,7 @@ const Customers: React.FC = () => {
try {
const host = window.location.hostname;
const response = await fetch(`http://${host}:8080/api/auth/users/${user.id}`, {
const response = await apiFetch(`http://${host}:8080/api/auth/users/${user.id}`, {
method: 'DELETE',
});
if (response.ok) {
@@ -125,7 +126,7 @@ const Customers: React.FC = () => {
const handleSuspendToggle = async (user: UserDto) => {
try {
const host = window.location.hostname;
const response = await fetch(`http://${host}:8080/api/auth/users/${user.id}/suspend`, {
const response = await apiFetch(`http://${host}:8080/api/auth/users/${user.id}/suspend`, {
method: 'PATCH',
});
if (response.ok) {
@@ -165,7 +166,7 @@ const Customers: React.FC = () => {
setIsSaving(true);
try {
const host = window.location.hostname;
const response = await fetch(`http://${host}:8080/api/auth/users/${editingUser.id}`, {
const response = await apiFetch(`http://${host}:8080/api/auth/users/${editingUser.id}`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(editForm),

View File

@@ -1,3 +1,4 @@
import { apiFetch } from '../api';
import { useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import {
@@ -105,7 +106,7 @@ const Dashboard = () => {
}
console.log('[DASHBOARD-TRACE] Fetching stats from:', url);
const response = await fetch(url);
const response = await apiFetch(url);
if (response.ok) {
const result = await response.json();
setData(result);

View File

@@ -1,3 +1,4 @@
import { apiFetch } from '../api';
import React, { useState, useEffect } from 'react';
import {
Star,
@@ -81,7 +82,7 @@ const Feedback: React.FC = () => {
const fetchStats = async () => {
setLoading(true);
try {
const response = await fetch(`http://${window.location.hostname}:8080/api/feedback/stats`);
const response = await apiFetch(`http://${window.location.hostname}:8080/api/feedback/stats`);
const data = await response.json();
setStats(data);
} catch (error) {
@@ -93,7 +94,7 @@ const Feedback: React.FC = () => {
const fetchFeedbacks = async () => {
try {
const response = await fetch(`http://${window.location.hostname}:8080/api/feedback?page=${page}&size=${pageSize}`);
const response = await apiFetch(`http://${window.location.hostname}:8080/api/feedback?page=${page}&size=${pageSize}`);
const data = await response.json();
setFeedbacks(data?.content || []);
setTotalElements(data?.totalElements || 0);

View File

@@ -1,3 +1,4 @@
import { apiFetch } from '../api';
import React, { useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import { motion } from 'framer-motion';
@@ -68,7 +69,7 @@ const IntentDashboard: React.FC<IntentDashboardProps> = ({ title }) => {
const fetchStats = async () => {
setLoading(true);
try {
const response = await fetch(`http://${window.location.hostname}:8080/api/purchases/intent/summary`);
const response = await apiFetch(`http://${window.location.hostname}:8080/api/purchases/intent/summary`);
const data = await response.json();
setStats(data);
} catch (error) {

View File

@@ -1,3 +1,4 @@
import { apiFetch } from '../api';
import React, { useState, useEffect } from 'react';
import {
Eye,
@@ -49,7 +50,7 @@ const IntentList: React.FC<IntentListProps> = ({ title }) => {
const fetchVendors = async () => {
try {
const response = await fetch(`http://${window.location.hostname}:8080/api/purchases/vendors`);
const response = await apiFetch(`http://${window.location.hostname}:8080/api/purchases/vendors`);
if (response.ok) {
const result = await response.json();
setVendors(result);
@@ -62,7 +63,7 @@ const IntentList: React.FC<IntentListProps> = ({ title }) => {
const fetchData = async () => {
setLoading(true);
try {
const response = await fetch(`http://${window.location.hostname}:8080/api/purchases/orders`);
const response = await apiFetch(`http://${window.location.hostname}:8080/api/purchases/orders`);
const result = await response.json();
setData(result);
} catch (error) {
@@ -104,7 +105,7 @@ const IntentList: React.FC<IntentListProps> = ({ title }) => {
date: new Date(newOrder.date).toISOString()
};
const response = await fetch(`http://${window.location.hostname}:8080/api/purchases/orders`, {
const response = await apiFetch(`http://${window.location.hostname}:8080/api/purchases/orders`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)

View File

@@ -52,14 +52,14 @@ const Login = () => {
sessionStorage.setItem('isLoggedIn', 'true');
sessionStorage.setItem('userRole', user.role.toLowerCase());
sessionStorage.setItem('userPermissions', JSON.stringify(user.permissions || []));
// Persist user profile for personalized greetings and settings
localStorage.setItem('systemUser', JSON.stringify(user));
// Persist user profile + JWT token for authenticated API calls
localStorage.setItem('systemUser', JSON.stringify(user)); // user object now includes `token`
navigate('/store-dashboard');
} else {
const error = await response.text();
alert(error || 'Invalid credentials');
const error = await response.json().catch(() => ({ error: 'Invalid credentials' }));
alert(error.error || 'Invalid credentials');
}
} catch (err) {
console.error('Login error:', err);

View File

@@ -1,3 +1,4 @@
import { apiFetch } from '../api';
import { useState, useEffect } from 'react';
import {
Ticket,
@@ -44,7 +45,7 @@ const ManageCoupons = () => {
const fetchCoupons = async () => {
try {
setIsLoading(true);
const response = await fetch('/api/coupons');
const response = await apiFetch('/api/coupons');
if (response.ok) {
const data = await response.json();
setCoupons(data);
@@ -63,7 +64,7 @@ const ManageCoupons = () => {
const handleCreateCoupon = async (e: React.FormEvent) => {
e.preventDefault();
try {
const response = await fetch('/api/coupons', {
const response = await apiFetch('/api/coupons', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
@@ -85,7 +86,7 @@ const ManageCoupons = () => {
const handleToggleStatus = async (id: number) => {
try {
const response = await fetch(`/api/coupons/${id}/toggle`, { method: 'PATCH' });
const response = await apiFetch(`/api/coupons/${id}/toggle`, { method: 'PATCH' });
if (response.ok) fetchCoupons();
} catch (error) {
console.error('Error toggling status:', error);
@@ -95,7 +96,7 @@ const ManageCoupons = () => {
const handleDelete = async (id: number) => {
if (!window.confirm('Are you sure you want to delete this coupon?')) return;
try {
const response = await fetch(`/api/coupons/${id}`, { method: 'DELETE' });
const response = await apiFetch(`/api/coupons/${id}`, { method: 'DELETE' });
if (response.ok) fetchCoupons();
} catch (error) {
console.error('Error deleting coupon:', error);

View File

@@ -1,3 +1,4 @@
import { apiFetch } from '../api';
import { useState, useEffect } from 'react';
import {
Users,
@@ -33,7 +34,7 @@ const ManageWallets = () => {
const fetchUsers = async () => {
try {
setIsLoading(true);
const response = await fetch('/api/wallet/users');
const response = await apiFetch('/api/wallet/users');
if (response.ok) {
const data = await response.json();
setUsers(data);
@@ -57,7 +58,7 @@ const ManageWallets = () => {
setStatus(null);
try {
const response = await fetch('/api/wallet/topup', {
const response = await apiFetch('/api/wallet/topup', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({

View File

@@ -1,3 +1,4 @@
import { apiFetch } from '../api';
import { useState, useEffect } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
import {
@@ -66,7 +67,7 @@ const Managers = () => {
const fetchManagers = async () => {
setLoading(true);
try {
const res = await fetch('/api/system/managers');
const res = await apiFetch('/api/system/managers');
if (res.ok) {
const data = await res.json();
// Backend uses 'permissions' field, map it to 'sections' for the component if needed
@@ -99,7 +100,7 @@ const Managers = () => {
const handleCreateAccount = async (e: React.FormEvent) => {
e.preventDefault();
try {
const response = await fetch('/api/system/managers', {
const response = await apiFetch('/api/system/managers', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
@@ -127,7 +128,7 @@ const Managers = () => {
const dismissManager = async (id: string) => {
if (window.confirm('Are you sure you want to dismiss this manager?')) {
try {
const response = await fetch(`/api/system/managers/${id}`, {
const response = await apiFetch(`/api/system/managers/${id}`, {
method: 'DELETE'
});
if (response.ok) {

View File

@@ -1,3 +1,4 @@
import { apiFetch } from '../api';
import React, { useState, useEffect, useRef } from 'react';
import {
X, Search, RefreshCw, Edit2, Package, Image as ImageIcon,
@@ -75,7 +76,7 @@ const NewArrivals: React.FC = () => {
const fetchDrafts = async () => {
setLoading(true);
try {
const response = await fetch('/api/products/drafts');
const response = await apiFetch('/api/products/drafts');
if (response.ok) {
const data = await response.json();
setDrafts(data);
@@ -116,7 +117,7 @@ const NewArrivals: React.FC = () => {
setIsSaving(true);
try {
const response = await fetch(`/api/products/${formData.id}/publish`, {
const response = await apiFetch(`/api/products/${formData.id}/publish`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(formData),
@@ -137,7 +138,7 @@ const NewArrivals: React.FC = () => {
const handleDelete = async (id: number) => {
if (!window.confirm('Delete this draft product?')) return;
try {
await fetch(`/api/products/${id}`, { method: 'DELETE' });
await apiFetch(`/api/products/${id}`, { method: 'DELETE' });
fetchDrafts();
} catch (error) {
console.error('Error deleting draft:', error);

View File

@@ -1,3 +1,4 @@
import { apiFetch } from '../api';
import React, { useState, useEffect, useMemo } from 'react';
import {
Search,
@@ -103,7 +104,7 @@ const Orders: React.FC = () => {
const fetchProducts = async () => {
try {
const response = await fetch(`http://${window.location.hostname}:8080/api/products`);
const response = await apiFetch(`http://${window.location.hostname}:8080/api/products`);
if (response.ok) {
const data = await response.json();
setAllProducts(data);
@@ -127,7 +128,7 @@ const Orders: React.FC = () => {
params.append('page', currentPage.toString());
params.append('size', pageSize.toString());
const response = await fetch(`http://${window.location.hostname}:8080/api/orders/all?${params.toString()}`);
const response = await apiFetch(`http://${window.location.hostname}:8080/api/orders/all?${params.toString()}`);
const data = await response.json();
if (data && data.content && Array.isArray(data.content)) {
@@ -156,7 +157,7 @@ const Orders: React.FC = () => {
const handleApproveOrder = async (orderId: number) => {
try {
const response = await fetch(`http://${window.location.hostname}:8080/api/orders/${orderId}/status`, {
const response = await apiFetch(`http://${window.location.hostname}:8080/api/orders/${orderId}/status`, {
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ status: 'COMPLETED' })
@@ -174,7 +175,7 @@ const Orders: React.FC = () => {
const handleMarkUndelivered = async (orderId: number) => {
try {
const response = await fetch(`http://${window.location.hostname}:8080/api/orders/${orderId}/status`, {
const response = await apiFetch(`http://${window.location.hostname}:8080/api/orders/${orderId}/status`, {
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ status: 'PAID' })
@@ -230,7 +231,7 @@ const Orders: React.FC = () => {
if (!selectedOrder) return;
setIsUpdatingOrder(true);
try {
const response = await fetch(`http://${window.location.hostname}:8080/api/orders/${selectedOrder.id}`, {
const response = await apiFetch(`http://${window.location.hostname}:8080/api/orders/${selectedOrder.id}`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
@@ -297,7 +298,7 @@ const Orders: React.FC = () => {
setIsRegenerating(true);
try {
const newOrderNumber = `ORD-${Math.random().toString(36).substring(2, 10).toUpperCase()}`;
const response = await fetch(`http://${window.location.hostname}:8080/api/orders/${selectedOrder.id}`, {
const response = await apiFetch(`http://${window.location.hostname}:8080/api/orders/${selectedOrder.id}`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({

View File

@@ -1,3 +1,4 @@
import { apiFetch } from '../api';
import React, { useState, useEffect, useRef } from 'react';
import { Plus, X, Search, Filter, MoreVertical, RefreshCw, Edit2, Power, PowerOff, Tag, Package, Image as ImageIcon, Barcode, DollarSign, ChevronDown, Clock, Check, Trash2, Database } from 'lucide-react';
import Pagination from '../components/Pagination';
@@ -161,7 +162,7 @@ const Products = () => {
params.append('search', debouncedSearchTerm);
}
const response = await fetch(`http://${host}:8080/api/products?${params.toString()}`);
const response = await apiFetch(`http://${host}:8080/api/products?${params.toString()}`);
const data = await response.json();
if (data && data.content) {
setProducts(data.content);
@@ -179,7 +180,7 @@ const Products = () => {
const fetchBaseItems = async () => {
try {
const response = await fetch('http://localhost:8080/api/base-items?size=100');
const response = await apiFetch('http://localhost:8080/api/base-items?size=100');
const data = await response.json();
setBaseItems(data.content || data);
} catch (error) {
@@ -189,7 +190,7 @@ const Products = () => {
const fetchAllStalls = async () => {
try {
const response = await fetch('http://localhost:8080/api/stalls');
const response = await apiFetch('http://localhost:8080/api/stalls');
const data = await response.json();
setAllStalls(data);
} catch (error) {
@@ -205,7 +206,7 @@ const Products = () => {
const method = editingProduct ? 'PUT' : 'POST';
try {
const response = await fetch(url, {
const response = await apiFetch(url, {
method,
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(formData),
@@ -233,7 +234,7 @@ const Products = () => {
const handleToggleActive = async (product: Product) => {
try {
const response = await fetch(`http://localhost:8080/api/products/${product.id}`, {
const response = await apiFetch(`http://localhost:8080/api/products/${product.id}`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ ...product, active: !product.active }),
@@ -249,7 +250,7 @@ const Products = () => {
const handleToggleStock = async (product: Product) => {
try {
const response = await fetch(`http://localhost:8080/api/products/${product.id}/toggle-stock`, {
const response = await apiFetch(`http://localhost:8080/api/products/${product.id}/toggle-stock`, {
method: 'PATCH',
});
if (response.ok) {
@@ -264,7 +265,7 @@ const Products = () => {
const handleDelete = async (product: Product) => {
if (!window.confirm(`Are you sure you want to delete ${product.name}?`)) return;
try {
const response = await fetch(`http://localhost:8080/api/products/${product.id}`, {
const response = await apiFetch(`http://localhost:8080/api/products/${product.id}`, {
method: 'DELETE',
});
if (response.ok) {

View File

@@ -1,3 +1,4 @@
import { apiFetch } from '../api';
import React, { useState, useEffect } from 'react';
import {
TrendingUp,
@@ -71,7 +72,7 @@ const PurchaseAnalytics = () => {
const fetchData = async () => {
try {
setIsLoading(true);
const response = await fetch('/api/purchases/orders');
const response = await apiFetch('/api/purchases/orders');
if (response.ok) {
const data = await response.json();
processAnalytics(data);

View File

@@ -1,3 +1,4 @@
import { apiFetch } from '../api';
import React, { useState, useEffect } from 'react';
import { Search, ShoppingCart, Eye, Plus, X, Loader2, CheckCircle, Trash2, Edit2 } from 'lucide-react';
@@ -65,7 +66,7 @@ const Purchases: React.FC = () => {
const fetchOrders = async () => {
try {
setIsLoading(true);
const response = await fetch('/api/purchases/orders');
const response = await apiFetch('/api/purchases/orders');
if (response.ok) {
const data = await response.json();
setOrders(data);
@@ -79,7 +80,7 @@ const Purchases: React.FC = () => {
const fetchVendors = async () => {
try {
const response = await fetch('/api/purchases/vendors');
const response = await apiFetch('/api/purchases/vendors');
if (response.ok) {
const data = await response.json();
setVendors(data);
@@ -91,7 +92,7 @@ const Purchases: React.FC = () => {
const fetchProducts = async () => {
try {
const response = await fetch('/api/products?size=1000');
const response = await apiFetch('/api/products?size=1000');
if (response.ok) {
const data = await response.json();
setAvailableProducts(data.content || data);
@@ -150,7 +151,7 @@ const Purchases: React.FC = () => {
date: new Date(newOrder.date).toISOString()
};
const response = await fetch('/api/purchases/orders', {
const response = await apiFetch('/api/purchases/orders', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
@@ -172,7 +173,7 @@ const Purchases: React.FC = () => {
const deleteOrder = async (id: number) => {
if (!window.confirm('Delete this purchase order?')) return;
try {
await fetch(`/api/purchases/orders/${id}`, { method: 'DELETE' });
await apiFetch(`/api/purchases/orders/${id}`, { method: 'DELETE' });
fetchOrders();
} catch (error) {
console.error('Error deleting order:', error);
@@ -197,7 +198,7 @@ const Purchases: React.FC = () => {
const order = orders.find(o => o.id === orderId);
if (!order) return;
const response = await fetch(`/api/purchases/orders`, {
const response = await apiFetch(`/api/purchases/orders`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ ...order, status: newStatus })
@@ -229,7 +230,7 @@ const Purchases: React.FC = () => {
const fetchOrderHistory = async (order: PurchaseOrder) => {
try {
setActiveHistoryOrder(order);
const response = await fetch(`/api/purchases/orders/${order.id}/history`);
const response = await apiFetch(`/api/purchases/orders/${order.id}/history`);
if (response.ok) {
const data = await response.json();
setOrderHistory(data);

View File

@@ -1,3 +1,4 @@
import { apiFetch } from '../api';
import React, { useState, useEffect } from 'react';
import {
Download,
@@ -66,7 +67,7 @@ const Reports: React.FC = () => {
try {
const fromStr = dateRange.from.toISOString();
const toStr = dateRange.to.toISOString();
const response = await fetch(`http://${window.location.hostname}:8080/api/reports/monthly?from=${fromStr}&to=${toStr}`);
const response = await apiFetch(`http://${window.location.hostname}:8080/api/reports/monthly?from=${fromStr}&to=${toStr}`);
const result = await response.json();
setData(result);
} catch (error) {

View File

@@ -1,3 +1,4 @@
import { apiFetch } from '../api';
import React, { useState, useEffect } from 'react';
import {
Building2,
@@ -56,11 +57,11 @@ const RitzPage: React.FC = () => {
setIsLoading(true);
const host = window.location.hostname;
const statsRes = await fetch(`http://${host}:8080/api/wallet/stats`);
const statsRes = await apiFetch(`http://${host}:8080/api/wallet/stats`);
const statsData = await statsRes.json();
setStats(statsData);
const transRes = await fetch(`http://${host}:8080/api/wallet/transactions/all`);
const transRes = await apiFetch(`http://${host}:8080/api/wallet/transactions/all`);
const transData = await transRes.json();
setTransactions(Array.isArray(transData) ? transData : []);
} catch (error) {

View File

@@ -1,3 +1,4 @@
import { apiFetch } from '../api';
import React, { useState, useEffect } from 'react';
import {
CircleDollarSign,
@@ -52,7 +53,7 @@ const RitzCirculation: React.FC = () => {
try {
setIsLoading(true);
const host = window.location.hostname;
const res = await fetch(`http://${host}:8080/api/wallet/circulation?page=${page}&size=${size}`);
const res = await apiFetch(`http://${host}:8080/api/wallet/circulation?page=${page}&size=${size}`);
const data: PageResponse = await res.json();
setTokens(data.content || []);

View File

@@ -1,3 +1,4 @@
import { apiFetch } from '../api';
import React, { useState, useEffect } from 'react';
import {
User,
@@ -47,7 +48,7 @@ const Settings = () => {
const fetchAdmins = async () => {
try {
const response = await fetch('/api/system/admins');
const response = await apiFetch('/api/system/admins');
const data = await response.json();
setAdmins(data);
} catch (err) {
@@ -69,7 +70,7 @@ const Settings = () => {
setStatus('loading');
try {
const response = await fetch('/api/system/update-master', {
const response = await apiFetch('/api/system/update-master', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
@@ -102,7 +103,7 @@ const Settings = () => {
e.preventDefault();
setStatus('loading');
try {
const response = await fetch('/api/system/admins', {
const response = await apiFetch('/api/system/admins', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(newAdmin)

View File

@@ -1,3 +1,4 @@
import { apiFetch } from '../api';
import { useState, useEffect } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
import {
@@ -50,7 +51,7 @@ const Staff = () => {
const fetchStaff = async () => {
setLoading(true);
try {
const res = await fetch('/api/system/staff');
const res = await apiFetch('/api/system/staff');
if (res.ok) {
const data = await res.json();
setStaffList(data);
@@ -69,7 +70,7 @@ const Staff = () => {
const handleCreateStaff = async (e: React.FormEvent) => {
e.preventDefault();
try {
const response = await fetch('/api/system/staff', {
const response = await apiFetch('/api/system/staff', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
@@ -97,7 +98,7 @@ const Staff = () => {
const deleteStaff = async (id: string) => {
if (window.confirm('Are you sure you want to remove this staff member?')) {
try {
const response = await fetch(`/api/system/staff/${id}`, {
const response = await apiFetch(`/api/system/staff/${id}`, {
method: 'DELETE'
});
if (response.ok) {

View File

@@ -1,3 +1,4 @@
import { apiFetch } from '../api';
import React, { useState, useEffect } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
import {
@@ -94,7 +95,7 @@ const Stalls: React.FC = () => {
try {
setLoading(true);
const host = window.location.hostname;
const response = await fetch(`http://${host}:8080/api/stalls`);
const response = await apiFetch(`http://${host}:8080/api/stalls`);
if (response.ok) {
const data = await response.json();
setStalls(data);
@@ -126,7 +127,7 @@ const Stalls: React.FC = () => {
? `http://${host}:8080/api/stalls/${editingStall.id}`
: `http://${host}:8080/api/stalls`;
const response = await fetch(url, {
const response = await apiFetch(url, {
method: editingStall ? 'PUT' : 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
@@ -173,7 +174,7 @@ const Stalls: React.FC = () => {
if (!window.confirm('Are you sure you want to delete this stall?')) return;
try {
const host = window.location.hostname;
const response = await fetch(`http://${host}:8080/api/stalls/${id}`, {
const response = await apiFetch(`http://${host}:8080/api/stalls/${id}`, {
method: 'DELETE'
});
if (response.ok) {
@@ -216,7 +217,7 @@ const Stalls: React.FC = () => {
setIsSaving(true);
try {
const host = window.location.hostname;
const response = await fetch(`http://${host}:8080/api/stalls/${selectedStall.id}/items`, {
const response = await apiFetch(`http://${host}:8080/api/stalls/${selectedStall.id}/items`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({

View File

@@ -1,3 +1,4 @@
import { apiFetch } from '../api';
import { useState, useEffect } from 'react';
import {
ChevronRight,
@@ -99,7 +100,7 @@ const StoreDashboard = () => {
params.append('from', range.from);
params.append('to', range.to);
const response = await fetch(`/api/dashboard/stats?${params.toString()}`);
const response = await apiFetch(`/api/dashboard/stats?${params.toString()}`);
if (response.ok) {
const data = await response.json();
console.log('Dashboard data received successfully:', data);

View File

@@ -1,3 +1,4 @@
import { apiFetch } from '../api';
import React, { useState, useEffect } from 'react';
import { motion } from 'framer-motion';
import {
@@ -32,7 +33,7 @@ const Terminals = () => {
const fetchTerminals = async () => {
setLoading(true);
try {
const response = await fetch('/api/terminals');
const response = await apiFetch('/api/terminals');
if (response.ok) {
const data = await response.json();
setTerminals(data);
@@ -52,7 +53,7 @@ const Terminals = () => {
e.stopPropagation();
if (window.confirm('Are you sure you want to remove this terminal?')) {
try {
const response = await fetch(`/api/terminals/${id}`, { method: 'DELETE' });
const response = await apiFetch(`/api/terminals/${id}`, { method: 'DELETE' });
if (response.ok) fetchTerminals();
} catch (error) {
console.error('Failed to delete terminal:', error);

View File

@@ -1,3 +1,4 @@
import { apiFetch } from '../api';
import { useState, useEffect } from 'react';
import { motion } from 'framer-motion';
import {
@@ -53,7 +54,7 @@ const VendorDashboard = () => {
const fetchData = async () => {
try {
setIsLoading(true);
const response = await fetch('/api/dashboard/procurement');
const response = await apiFetch('/api/dashboard/procurement');
if (response.ok) {
const result = await response.json();
setData(result);

View File

@@ -1,3 +1,4 @@
import { apiFetch } from '../api';
import React, { useState, useEffect } from 'react';
import { Search, Building2, Phone, Mail, MoreVertical, List, LayoutGrid, Edit2, Trash2, X, Loader2, AlertCircle, CheckCircle, Plus } from 'lucide-react';
import Pagination from '../components/Pagination';
@@ -43,7 +44,7 @@ const Vendors: React.FC = () => {
const fetchVendors = async () => {
try {
setIsLoading(true);
const response = await fetch('/api/purchases/vendors');
const response = await apiFetch('/api/purchases/vendors');
if (response.ok) {
const data = await response.json();
setVendors(data);
@@ -85,7 +86,7 @@ const Vendors: React.FC = () => {
if (!window.confirm(`Are you sure you want to delete ${vendor.name}?`)) return;
try {
const response = await fetch(`/api/purchases/vendors/${vendor.id}`, {
const response = await apiFetch(`/api/purchases/vendors/${vendor.id}`, {
method: 'DELETE',
});
if (response.ok) {
@@ -111,7 +112,7 @@ const Vendors: React.FC = () => {
setIsSaving(true);
try {
const response = await fetch('/api/purchases/vendors', {
const response = await apiFetch('/api/purchases/vendors', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(editingVendor ? { ...form, id: editingVendor.id } : form),