fixed cart desync

This commit is contained in:
2ManyProjects 2025-04-28 15:38:46 -05:00
parent 202e99b12f
commit c913b09edf
6 changed files with 54 additions and 25 deletions

View file

@ -52,7 +52,7 @@ const upload = multer({
storage, storage,
fileFilter, fileFilter,
limits: { limits: {
fileSize: 5 * 1024 * 1024 // 5MB limit fileSize: 10 * 1024 * 1024 // 10MB
} }
}); });

View file

@ -15,7 +15,6 @@ const createTransporter = () => {
}); });
}; };
// Mock email transporter for development
const transporter = createTransporter(); const transporter = createTransporter();
module.exports = (pool, query) => { module.exports = (pool, query) => {
@ -94,7 +93,6 @@ module.exports = (pool, query) => {
[authId, user.id] [authId, user.id]
); );
// Send email with code (mock in development)
const loginLink = `${config.site.protocol}://${config.site.domain}/verify?code=${authCode}&email=${encodeURIComponent(email)}`; const loginLink = `${config.site.protocol}://${config.site.domain}/verify?code=${authCode}&email=${encodeURIComponent(email)}`;

View file

@ -513,7 +513,6 @@ module.exports = (pool, query, authMiddleware) => {
? shippingService.parseAddressString(shippingAddress) ? shippingService.parseAddressString(shippingAddress)
: shippingAddress; : shippingAddress;
console.log("Fetching rates for parsed address:", parsedAddress);
const shippingResponse = await shippingService.getShippingRates( const shippingResponse = await shippingService.getShippingRates(
null, // Use default from config null, // Use default from config

View file

@ -3,6 +3,7 @@ import { loadStripe } from '@stripe/stripe-js';
import { Elements } from '@stripe/react-stripe-js'; import { Elements } from '@stripe/react-stripe-js';
import config from '../config'; import config from '../config';
import apiClient from '@services/api'; import apiClient from '@services/api';
import { useAuth } from '@hooks/reduxHooks';
// Create the context // Create the context
const StripeContext = createContext(); const StripeContext = createContext();
@ -12,13 +13,19 @@ export const StripeProvider = ({ children }) => {
const [clientSecret, setClientSecret] = useState(''); const [clientSecret, setClientSecret] = useState('');
const [isLoading, setIsLoading] = useState(true); const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState(null); const [error, setError] = useState(null);
const { isAuthenticated } = useAuth();
// Load or reload Stripe configuration when authentication state changes
useEffect(() => { useEffect(() => {
// Reset state when auth changes
setIsLoading(true);
setError(null);
// Try to load Stripe public key from environment // Try to load Stripe public key from environment
let publicKey = import.meta.env.VITE_STRIPE_PUBLIC_KEY; let publicKey = import.meta.env.VITE_STRIPE_PUBLIC_KEY;
// If not found, fetch from API // If not found, fetch from API
if (!publicKey) { if (isAuthenticated) {
// Fetch Stripe public key from backend // Fetch Stripe public key from backend
apiClient.get('/payment/config') apiClient.get('/payment/config')
.then(response => { .then(response => {
@ -34,10 +41,10 @@ export const StripeProvider = ({ children }) => {
setError('Failed to load payment configuration'); setError('Failed to load payment configuration');
setIsLoading(false); setIsLoading(false);
}); });
} else { } else if(publicKey){
loadStripeInstance(publicKey); loadStripeInstance(publicKey);
} }
}, []); }, [isAuthenticated]); // Add isAuthenticated as a dependency to reload on auth changes
const loadStripeInstance = (publicKey) => { const loadStripeInstance = (publicKey) => {
try { try {
@ -102,7 +109,27 @@ export const StripeProvider = ({ children }) => {
error, error,
createCheckoutSession, createCheckoutSession,
checkSessionStatus, checkSessionStatus,
completeOrder completeOrder,
reloadConfig: () => {
setIsLoading(true);
setError(null);
if (isAuthenticated){
apiClient.get('/payment/config')
.then(response => {
if (response.data.stripePublicKey) {
loadStripeInstance(response.data.stripePublicKey);
} else {
setError('Stripe public key not found');
setIsLoading(false);
}
})
.catch(err => {
console.error('Error fetching Stripe config:', err);
setError('Failed to load payment configuration');
setIsLoading(false);
});
}
}
}; };
return ( return (

View file

@ -28,7 +28,6 @@ import apiClient from '../../services/api';
import { useAdminCategories } from '../../hooks/categoryAdminHooks'; import { useAdminCategories } from '../../hooks/categoryAdminHooks';
const AdminDashboardPage = () => { const AdminDashboardPage = () => {
// Mock data - would be replaced with real API calls
const [stats, setStats] = useState({ const [stats, setStats] = useState({
totalProducts: 0, totalProducts: 0,
totalUsers: 0, totalUsers: 0,
@ -53,7 +52,6 @@ const AdminDashboardPage = () => {
// Fetch categories // Fetch categories
const { data: categories, isLoading: categoriesLoading } = useAdminCategories(); const { data: categories, isLoading: categoriesLoading } = useAdminCategories();
// Mock recent orders - would be replaced with real API data
const recentOrders = [ const recentOrders = [
{ id: '4532', customer: 'John Doe', date: '2023-04-22', total: 49.99, status: 'Delivered' }, { id: '4532', customer: 'John Doe', date: '2023-04-22', total: 49.99, status: 'Delivered' },
{ id: '4531', customer: 'Jane Smith', date: '2023-04-21', total: 89.95, status: 'Processing' }, { id: '4531', customer: 'Jane Smith', date: '2023-04-21', total: 89.95, status: 'Processing' },
@ -67,10 +65,9 @@ const AdminDashboardPage = () => {
setStats(prev => ({ setStats(prev => ({
...prev, ...prev,
totalProducts: products.length, totalProducts: products.length,
// Other stats would be updated from their respective API calls totalUsers: 15,
totalUsers: 15, // Mock data totalOrders: 42,
totalOrders: 42, // Mock data revenue: 2459.99
revenue: 2459.99 // Mock data
})); }));
} }

View file

@ -23,8 +23,8 @@ import {
FormLabel FormLabel
} from '@mui/material'; } from '@mui/material';
import { useNavigate, Link as RouterLink } from 'react-router-dom'; import { useNavigate, Link as RouterLink } from 'react-router-dom';
import { useAuth, useCart } from '../hooks/reduxHooks'; import { useAuth } from '../hooks/reduxHooks';
import { useCheckout } from '../hooks/apiHooks'; import { useCheckout, useGetCart } from '../hooks/apiHooks';
import { useStripe, StripeElementsProvider } from '../context/StripeContext'; import { useStripe, StripeElementsProvider } from '../context/StripeContext';
import apiClient from '../services/api'; import apiClient from '../services/api';
@ -34,7 +34,7 @@ const steps = ['Shipping Address', 'Shipping Method', 'Review Order', 'Payment',
const CheckoutPage = () => { const CheckoutPage = () => {
const navigate = useNavigate(); const navigate = useNavigate();
const { user, userData } = useAuth(); const { user, userData } = useAuth();
const { items, total, itemCount } = useCart(); const { data: cart, isLoading: cartLoading } = useGetCart(user);
const checkout = useCheckout(); const checkout = useCheckout();
const { createCheckoutSession, isLoading: isStripeLoading } = useStripe(); const { createCheckoutSession, isLoading: isStripeLoading } = useStripe();
@ -54,8 +54,8 @@ const CheckoutPage = () => {
// State for form data // State for form data
const [formData, setFormData] = useState({ const [formData, setFormData] = useState({
firstName: userData?.first_name || '', firstName: userData?.firstName || '',
lastName: userData?.last_name || '', lastName: userData?.lastName || '',
email: userData?.email || '', email: userData?.email || '',
address: '', address: '',
city: '', city: '',
@ -125,7 +125,6 @@ const CheckoutPage = () => {
for (const field of requiredFields) { for (const field of requiredFields) {
if (!formData[field]) { if (!formData[field]) {
// In a real app, you'd set specific errors for each field
setError(`Please fill in all required fields`); setError(`Please fill in all required fields`);
return false; return false;
} }
@ -210,7 +209,7 @@ const CheckoutPage = () => {
// Handle place order // Handle place order
const handlePlaceOrder = async () => { const handlePlaceOrder = async () => {
if (!user || !items || items.length === 0) { if (!user || !cart || !cart.items || cart.items.length === 0) {
return; return;
} }
@ -280,8 +279,17 @@ const CheckoutPage = () => {
} }
}, [checkoutUrl]); }, [checkoutUrl]);
// Loading state
if (cartLoading) {
return (
<Box sx={{ display: 'flex', justifyContent: 'center', my: 8 }}>
<CircularProgress />
</Box>
);
}
// If no items in cart, redirect to cart page // If no items in cart, redirect to cart page
if (!items || items.length === 0) { if (!cart || !cart.items || cart.items.length === 0) {
return ( return (
<Box sx={{ textAlign: 'center', py: 6 }}> <Box sx={{ textAlign: 'center', py: 6 }}>
<Typography variant="h5" gutterBottom> <Typography variant="h5" gutterBottom>
@ -489,7 +497,7 @@ const CheckoutPage = () => {
</Typography> </Typography>
<List disablePadding> <List disablePadding>
{items.map((item) => ( {cart.items.map((item) => (
<ListItem key={item.product_id} sx={{ py: 1, px: 0 }}> <ListItem key={item.product_id} sx={{ py: 1, px: 0 }}>
<ListItemText <ListItemText
primary={item.name} primary={item.name}
@ -503,7 +511,7 @@ const CheckoutPage = () => {
<ListItem sx={{ py: 1, px: 0 }}> <ListItem sx={{ py: 1, px: 0 }}>
<ListItemText primary="Subtotal" /> <ListItemText primary="Subtotal" />
<Typography variant="body2">${total.toFixed(2)}</Typography> <Typography variant="body2">${cart.subtotal.toFixed(2)}</Typography>
</ListItem> </ListItem>
<ListItem sx={{ py: 1, px: 0 }}> <ListItem sx={{ py: 1, px: 0 }}>
@ -519,7 +527,7 @@ const CheckoutPage = () => {
<ListItem sx={{ py: 1, px: 0 }}> <ListItem sx={{ py: 1, px: 0 }}>
<ListItemText primary="Total" /> <ListItemText primary="Total" />
<Typography variant="subtitle1" sx={{ fontWeight: 700 }}> <Typography variant="subtitle1" sx={{ fontWeight: 700 }}>
${(total + shippingCost).toFixed(2)} ${(cart.subtotal + shippingCost).toFixed(2)}
</Typography> </Typography>
</ListItem> </ListItem>
</List> </List>