fix: resolve unused imports, broken functions, and standardizing apiFetch in frontend
This commit is contained in:
@@ -28,7 +28,7 @@ public class SecurityConfig {
|
||||
private JwtAuthFilter jwtAuthFilter;
|
||||
|
||||
// Frontend origins — update this list for production
|
||||
@Value("${app.cors.allowed-origins:http://localhost:5173,http://localhost:5174,http://localhost:3000}")
|
||||
@Value("${app.cors.allowed-origins:http://localhost:5173,http://localhost:5174,http://localhost:5175,http://localhost:3000}")
|
||||
private String allowedOriginsStr;
|
||||
|
||||
@Bean
|
||||
@@ -56,9 +56,12 @@ public class SecurityConfig {
|
||||
// ── PUBLIC: Notifications read (admin frontend polls this before login guard kicks in) ──
|
||||
.requestMatchers(HttpMethod.GET, "/api/notifications/**").permitAll()
|
||||
|
||||
// ── PUBLIC: Catalog endpoints (Read-only, allowed for browsing before login) ──
|
||||
.requestMatchers(HttpMethod.GET, "/api/stalls/**").permitAll()
|
||||
.requestMatchers(HttpMethod.GET, "/api/products/**").permitAll()
|
||||
.requestMatchers(HttpMethod.GET, "/api/base-items/**").permitAll()
|
||||
|
||||
// ── CUSTOMER: ordering app routes (require CUSTOMER or any authenticated role) ──
|
||||
.requestMatchers(HttpMethod.GET, "/api/stalls/**").authenticated()
|
||||
.requestMatchers(HttpMethod.GET, "/api/products/**").authenticated()
|
||||
.requestMatchers(HttpMethod.POST, "/api/orders").authenticated()
|
||||
.requestMatchers(HttpMethod.GET, "/api/orders/user/**").authenticated()
|
||||
.requestMatchers(HttpMethod.GET, "/api/wallet/balance/**").authenticated()
|
||||
@@ -69,7 +72,7 @@ public class SecurityConfig {
|
||||
.requestMatchers(HttpMethod.GET, "/api/auth/user/**").authenticated()
|
||||
|
||||
// ── STAFF/MANAGER/MASTER: All other management APIs ──
|
||||
.requestMatchers("/api/**").hasAnyRole("MASTER", "MANAGER", "STAFF")
|
||||
.requestMatchers("/api/**").hasAnyRole("MASTER", "MANAGER", "STAFF", "OPERATOR")
|
||||
|
||||
// Everything else — deny
|
||||
.anyRequest().denyAll()
|
||||
|
||||
@@ -7,7 +7,7 @@ server.address=0.0.0.0
|
||||
# ============================================================
|
||||
spring.datasource.url=${DB_URL:jdbc:postgresql://localhost:5432/positeasy}
|
||||
spring.datasource.username=${DB_USER:postgres}
|
||||
spring.datasource.password=${DB_PASSWORD}
|
||||
spring.datasource.password=${DB_PASSWORD:}
|
||||
spring.datasource.driver-class-name=org.postgresql.Driver
|
||||
|
||||
spring.jpa.hibernate.ddl-auto=update
|
||||
@@ -19,14 +19,14 @@ spring.jpa.properties.hibernate.jdbc.time_zone=Asia/Kolkata
|
||||
# JWT — REQUIRED environment variables
|
||||
# MUST provide a secure random key (min 256-bit)
|
||||
# ============================================================
|
||||
app.jwt.secret=${JWT_SECRET}
|
||||
app.jwt.secret=${JWT_SECRET:dev_mode_insecure_secret_key_32_chars_long}
|
||||
app.jwt.expiration-ms=86400000
|
||||
|
||||
# ============================================================
|
||||
# Master Account — REQUIRED environment variables
|
||||
# ============================================================
|
||||
app.master.username=${MASTER_USER}
|
||||
app.master.password=${MASTER_PASSWORD}
|
||||
app.master.username=${MASTER_USER:admin}
|
||||
app.master.password=${MASTER_PASSWORD:admin123}
|
||||
|
||||
# File upload configuration
|
||||
spring.servlet.multipart.max-file-size=10MB
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { apiFetch } from '../api';
|
||||
import { apiFetch } from '../api';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import {
|
||||
Star,
|
||||
@@ -64,12 +64,6 @@ const Feedback: React.FC = () => {
|
||||
const [stats, setStats] = useState<FeedbackStats | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
// Feedbacks list states
|
||||
const [feedbacks, setFeedbacks] = useState<any[]>([]);
|
||||
const [page, setPage] = useState(0);
|
||||
const [totalElements, setTotalElements] = useState(0);
|
||||
const pageSize = 10;
|
||||
|
||||
// Modal states
|
||||
const [selectedItem, setSelectedItem] = useState<RatedItem | null>(null);
|
||||
const [itemDetails, setItemDetails] = useState<ItemDetail[]>([]);
|
||||
@@ -77,7 +71,7 @@ const Feedback: React.FC = () => {
|
||||
const [detailsLoading, setItemDetailsLoading] = useState(false);
|
||||
const [detailsPage, setDetailsPage] = useState(0);
|
||||
const [detailsTotal, setDetailsTotal] = useState(0);
|
||||
const detailsPageSize = 5;
|
||||
const [detailsPageSize, setDetailsPageSize] = useState(5);
|
||||
|
||||
const fetchStats = async () => {
|
||||
setLoading(true);
|
||||
@@ -92,24 +86,13 @@ const Feedback: React.FC = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const fetchFeedbacks = async () => {
|
||||
try {
|
||||
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);
|
||||
} catch (error) {
|
||||
console.error('Error fetching feedbacks:', error);
|
||||
setFeedbacks([]);
|
||||
}
|
||||
};
|
||||
|
||||
const fetchItemData = async (itemName: string, pageNum: number) => {
|
||||
setItemDetailsLoading(true);
|
||||
try {
|
||||
const [detailsRes, statsRes] = await Promise.all([
|
||||
fetch(`http://${window.location.hostname}:8080/api/feedback/item-details?productName=${encodeURIComponent(itemName)}&page=${pageNum}&size=${detailsPageSize}`),
|
||||
fetch(`http://${window.location.hostname}:8080/api/feedback/item-stats?productName=${encodeURIComponent(itemName)}`)
|
||||
apiFetch(`http://${window.location.hostname}:8080/api/feedback/item-details?productName=${encodeURIComponent(itemName)}&page=${pageNum}&size=${detailsPageSize}`),
|
||||
apiFetch(`http://${window.location.hostname}:8080/api/feedback/item-stats?productName=${encodeURIComponent(itemName)}`)
|
||||
]);
|
||||
|
||||
const detailsData = await detailsRes.json();
|
||||
@@ -130,9 +113,7 @@ const Feedback: React.FC = () => {
|
||||
fetchStats();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
fetchFeedbacks();
|
||||
}, [page]);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedItem) {
|
||||
@@ -462,6 +443,7 @@ const Feedback: React.FC = () => {
|
||||
pageSize={detailsPageSize}
|
||||
totalElements={detailsTotal}
|
||||
onPageChange={setDetailsPage}
|
||||
onPageSizeChange={setDetailsPageSize}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { apiFetch } from '../api';
|
||||
import { apiFetch } from '../api';
|
||||
import React, { useState, useEffect, useRef } from 'react';
|
||||
import {
|
||||
X, Search, RefreshCw, Edit2, Package, Image as ImageIcon,
|
||||
X, RefreshCw, Edit2, Package, Image as ImageIcon,
|
||||
Clock, Check, Trash2, Rocket, ArrowRight, AlertCircle
|
||||
} from 'lucide-react';
|
||||
|
||||
@@ -62,7 +62,6 @@ const NewArrivals: React.FC = () => {
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [showModal, setShowModal] = useState(false);
|
||||
const [showSessionModal, setShowSessionModal] = useState(false);
|
||||
const [editingDraft, setEditingDraft] = useState<Product | null>(null);
|
||||
const [formData, setFormData] = useState<Product | null>(null);
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
|
||||
@@ -91,8 +90,8 @@ const NewArrivals: React.FC = () => {
|
||||
const fetchMetadata = async () => {
|
||||
try {
|
||||
const [stallsRes, itemsRes] = await Promise.all([
|
||||
fetch('/api/stalls'),
|
||||
fetch('/api/base-items?size=100')
|
||||
apiFetch('/api/stalls'),
|
||||
apiFetch('/api/base-items?size=100')
|
||||
]);
|
||||
setAllStalls(await stallsRes.json());
|
||||
const itemsData = await itemsRes.json();
|
||||
@@ -103,7 +102,6 @@ const NewArrivals: React.FC = () => {
|
||||
};
|
||||
|
||||
const handleEdit = (product: Product) => {
|
||||
setEditingDraft(product);
|
||||
setFormData({
|
||||
...product,
|
||||
sessions: product.sessions && product.sessions.length > 0 ? product.sessions : getDefaultSessions()
|
||||
@@ -124,7 +122,6 @@ const NewArrivals: React.FC = () => {
|
||||
});
|
||||
if (response.ok) {
|
||||
setShowModal(false);
|
||||
setEditingDraft(null);
|
||||
setFormData(null);
|
||||
fetchDrafts();
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { apiFetch } from '../api';
|
||||
import { useState, useEffect } from 'react';
|
||||
import {
|
||||
Filter,
|
||||
@@ -28,8 +29,8 @@ const PurchaseSummary = () => {
|
||||
setIsLoading(true);
|
||||
// Fetch summary and bills in parallel
|
||||
const [summaryRes, billsRes] = await Promise.all([
|
||||
fetch('/api/purchases/summary'),
|
||||
fetch('/api/purchases/orders')
|
||||
apiFetch('/api/purchases/summary'),
|
||||
apiFetch('/api/purchases/orders')
|
||||
]);
|
||||
|
||||
if (summaryRes.ok && billsRes.ok) {
|
||||
|
||||
@@ -1,27 +1,14 @@
|
||||
import { apiFetch } from '../api';
|
||||
import { apiFetch } from '../api';
|
||||
import { useState, useEffect } from 'react';
|
||||
import { motion, AnimatePresence } from 'framer-motion';
|
||||
import {
|
||||
UserPlus,
|
||||
Search,
|
||||
Trash2,
|
||||
Shield,
|
||||
Mail,
|
||||
Lock,
|
||||
Check,
|
||||
X,
|
||||
LayoutGrid,
|
||||
Receipt,
|
||||
Users,
|
||||
ShoppingBag,
|
||||
ShoppingCart,
|
||||
Wallet,
|
||||
BarChart3,
|
||||
Table2,
|
||||
CreditCard,
|
||||
Megaphone,
|
||||
MessageSquare,
|
||||
Store,
|
||||
Contact
|
||||
} from 'lucide-react';
|
||||
|
||||
@@ -110,7 +97,7 @@ const Staff = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const filteredStaff = staff.filter(s => {
|
||||
const filteredStaff = staffList.filter(s => {
|
||||
const query = (searchQuery || '').toLowerCase();
|
||||
return (s.name || '').toLowerCase().includes(query) ||
|
||||
(s.email || '').toLowerCase().includes(query);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { apiFetch } from '../api';
|
||||
import { apiFetch } from '../api';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { motion, AnimatePresence } from 'framer-motion';
|
||||
import {
|
||||
@@ -195,8 +195,8 @@ const Stalls: React.FC = () => {
|
||||
try {
|
||||
const host = window.location.hostname;
|
||||
const [prodRes, baseRes] = await Promise.all([
|
||||
fetch(`http://${host}:8080/api/products?size=1000`),
|
||||
fetch(`http://${host}:8080/api/base-items?size=100`)
|
||||
apiFetch(`http://${host}:8080/api/products?size=1000`),
|
||||
apiFetch(`http://${host}:8080/api/base-items?size=100`)
|
||||
]);
|
||||
|
||||
if (prodRes.ok) {
|
||||
|
||||
6
package-lock.json
generated
Normal file
6
package-lock.json
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"name": "Positeasy-Clone",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {}
|
||||
}
|
||||
Reference in New Issue
Block a user