138 lines
No EOL
3.7 KiB
JavaScript
138 lines
No EOL
3.7 KiB
JavaScript
import React, { useState } from 'react';
|
|
import {
|
|
TextField,
|
|
Button,
|
|
Box,
|
|
Typography,
|
|
CircularProgress,
|
|
Alert,
|
|
Paper,
|
|
Divider,
|
|
Chip
|
|
} from '@mui/material';
|
|
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
|
import couponService from '../services/couponService';
|
|
import { useAuth } from '../hooks/reduxHooks';
|
|
|
|
/**
|
|
* Component for inputting and applying coupon codes to the cart
|
|
*/
|
|
const CouponInput = () => {
|
|
const [couponCode, setCouponCode] = useState('');
|
|
const [error, setError] = useState(null);
|
|
const { user } = useAuth();
|
|
const queryClient = useQueryClient();
|
|
|
|
// Get current cart data from cache
|
|
const cartData = queryClient.getQueryData(['cart', user]);
|
|
|
|
// Apply coupon mutation
|
|
const applyCoupon = useMutation({
|
|
mutationFn: ({ userId, code }) => couponService.applyCoupon(userId, code),
|
|
onSuccess: (data) => {
|
|
// Update React Query cache directly
|
|
queryClient.setQueryData(['cart', user], data);
|
|
setError(null);
|
|
},
|
|
onError: (error) => {
|
|
setError(error.message || 'Failed to apply coupon');
|
|
},
|
|
});
|
|
|
|
// Remove coupon mutation
|
|
const removeCoupon = useMutation({
|
|
mutationFn: (userId) => couponService.removeCoupon(userId),
|
|
onSuccess: (data) => {
|
|
// Update React Query cache directly
|
|
queryClient.setQueryData(['cart', user], data);
|
|
setError(null);
|
|
},
|
|
onError: (error) => {
|
|
setError(error.message || 'Failed to remove coupon');
|
|
},
|
|
});
|
|
|
|
// Handle coupon code input change
|
|
const handleCouponChange = (e) => {
|
|
setCouponCode(e.target.value.toUpperCase());
|
|
setError(null);
|
|
};
|
|
|
|
// Handle applying coupon
|
|
const handleApplyCoupon = () => {
|
|
if (!couponCode) {
|
|
setError('Please enter a coupon code');
|
|
return;
|
|
}
|
|
|
|
applyCoupon.mutate({ userId: user, code: couponCode });
|
|
};
|
|
|
|
// Handle removing coupon
|
|
const handleRemoveCoupon = () => {
|
|
removeCoupon.mutate(user);
|
|
setCouponCode('');
|
|
};
|
|
|
|
// Check if a coupon is already applied
|
|
const hasCoupon = cartData?.couponCode;
|
|
|
|
return (
|
|
<Paper variant="outlined" sx={{ p: 2, mb: 3 }}>
|
|
<Typography variant="h6" gutterBottom>
|
|
Discount Code
|
|
</Typography>
|
|
|
|
{error && (
|
|
<Alert severity="error" sx={{ mb: 2 }}>
|
|
{error}
|
|
</Alert>
|
|
)}
|
|
|
|
{hasCoupon ? (
|
|
<Box>
|
|
<Box sx={{ display: 'flex', alignItems: 'center', mb: 2 }}>
|
|
<Chip
|
|
label={cartData.couponCode}
|
|
color="success"
|
|
sx={{ mr: 2 }}
|
|
/>
|
|
<Typography variant="body2" color="success.main">
|
|
Discount applied: -${cartData.couponDiscount?.toFixed(2)}
|
|
</Typography>
|
|
</Box>
|
|
<Button
|
|
variant="outlined"
|
|
color="error"
|
|
size="small"
|
|
onClick={handleRemoveCoupon}
|
|
disabled={removeCoupon.isLoading}
|
|
>
|
|
{removeCoupon.isLoading ? <CircularProgress size={24} /> : 'Remove Coupon'}
|
|
</Button>
|
|
</Box>
|
|
) : (
|
|
<Box sx={{ display: 'flex' }}>
|
|
<TextField
|
|
fullWidth
|
|
placeholder="Enter coupon code"
|
|
value={couponCode}
|
|
onChange={handleCouponChange}
|
|
disabled={applyCoupon.isLoading}
|
|
inputProps={{ style: { textTransform: 'uppercase' } }}
|
|
sx={{ mr: 2 }}
|
|
/>
|
|
<Button
|
|
variant="contained"
|
|
onClick={handleApplyCoupon}
|
|
disabled={!couponCode || applyCoupon.isLoading}
|
|
>
|
|
{applyCoupon.isLoading ? <CircularProgress size={24} /> : 'Apply'}
|
|
</Button>
|
|
</Box>
|
|
)}
|
|
</Paper>
|
|
);
|
|
};
|
|
|
|
export default CouponInput; |