Fixed order total mismatch issue on cancelled page

Fixed token validation issue
Fixed issue displaying shipping method and fee on checkout
Added Light only theme
Fixed positioning issue on mobile view
This commit is contained in:
2025-10-12 00:45:36 +02:00
parent 5df46cba7e
commit ee1ce09508
7 changed files with 66 additions and 22 deletions

View File

@@ -160,17 +160,20 @@ router.post('/capture-order', validateCaptureOrder, async (req, res) => {
tokenLength: token?.length tokenLength: token?.length
}); });
// Declare tokenData at function scope
let tokenData = null;
// Verify token (optional in development) // Verify token (optional in development)
const skipTokenValidation = process.env.NODE_ENV === 'development' && process.env.SKIP_TOKEN_VALIDATION === 'true'; const skipTokenValidation = process.env.NODE_ENV === 'development' && process.env.SKIP_TOKEN_VALIDATION === 'true';
if (token && !skipTokenValidation) { if (token && !skipTokenValidation) {
const tokenData = verifyToken(token); tokenData = verifyToken(token);
console.log('Token verification result:', { console.log('Token verification result:', {
isValid: !!tokenData, isValid: !!tokenData,
tokenData: tokenData tokenData: tokenData
}); });
if (!tokenData || tokenData.wc_order_id !== parseInt(wc_order_id)) { if (!tokenData || tokenData.wc_order_id !== String(wc_order_id)) {
console.error('Token validation failed:', { console.error('Token validation failed:', {
tokenData, tokenData,
expectedOrderId: wc_order_id, expectedOrderId: wc_order_id,

View File

@@ -39,11 +39,11 @@ function App() {
gap={4} gap={4}
> >
<Image width="550px" src={logo} className="logo react" alt="React logo" /> <Image width="550px" src={logo} className="logo react" alt="React logo" />
<Center> {/*<Center>*/}
<Button variant="outline" onClick={toggleColorMode} > {/* <Button variant="outline" onClick={toggleColorMode} >*/}
{colorMode === "light" ? <><LuSun /> Toggle Light mode</> : <><LuMoon /> Toogle Dark mode</>} {/* {colorMode === "light" ? <><LuSun /> Toggle Light mode</> : <><LuMoon /> Toogle Dark mode</>}*/}
</Button> {/* </Button>*/}
</Center> {/*</Center>*/}
</Grid> </Grid>
<Flex direction="row" gap="4" justify="space-between" align="center" mb="10"> <Flex direction="row" gap="4" justify="space-between" align="center" mb="10">

View File

@@ -65,6 +65,7 @@ const OrderSummary = ({ orderData, loading, order }) => {
<DataList.ItemValue>{orderData.customer_email}</DataList.ItemValue> <DataList.ItemValue>{orderData.customer_email}</DataList.ItemValue>
</DataList.Item> </DataList.Item>
)}*/} )}*/}
{order.shipping.method &&
<DataList.Item pt="4"> <DataList.Item pt="4">
<DataList.ItemLabel> <DataList.ItemLabel>
<Badge colorPalette="teal" variant="solid"> <Badge colorPalette="teal" variant="solid">
@@ -72,7 +73,7 @@ const OrderSummary = ({ orderData, loading, order }) => {
</Badge> </Badge>
</DataList.ItemLabel> </DataList.ItemLabel>
<DataList.ItemValue>{formatCurrency(order.shipping.total, orderData.currency)}</DataList.ItemValue> <DataList.ItemValue>{formatCurrency(order.shipping.total, orderData.currency)}</DataList.ItemValue>
</DataList.Item> </DataList.Item> }
</> } </> }
<DataList.Item pt="4" textStyle="xl"> <DataList.Item pt="4" textStyle="xl">
<DataList.ItemLabel><strong>Total Amount:</strong></DataList.ItemLabel> <DataList.ItemLabel><strong>Total Amount:</strong></DataList.ItemLabel>

View File

@@ -1,13 +1,18 @@
import { Provider } from "@/components/ui/provider" import { Provider } from "@/components/ui/provider"
import { StrictMode } from 'react' import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client' import { createRoot } from 'react-dom/client'
import { ChakraProvider } from "@chakra-ui/react";
import { system } from "./theme";
import './index.css' import './index.css'
import App from './App.jsx' import App from './App.jsx'
import {ThemeProvider} from "next-themes";
createRoot(document.getElementById('root')).render( createRoot(document.getElementById('root')).render(
<StrictMode> <StrictMode>
<Provider> <ChakraProvider value={system}>
<ThemeProvider attribute="class" defaultTheme="light" enableSystem={false}>
<App /> <App />
</Provider> </ThemeProvider>
</ChakraProvider>
</StrictMode>, </StrictMode>,
) )

View File

@@ -16,20 +16,40 @@ const Cancel = () => {
const [searchParams] = useSearchParams(); const [searchParams] = useSearchParams();
const error = searchParams.get('error'); const error = searchParams.get('error');
const orderId = searchParams.get('order_id'); const orderId = searchParams.get('order_id') || searchParams.get('wc_order_id');
const paypalToken = searchParams.get('token'); const paypalToken = searchParams.get('token');
const orderTotal = searchParams.get('total');
const currency = searchParams.get('currency') || 'USD';
const description = searchParams.get('description');
const customerEmail = searchParams.get('customer_email');
const cancelUrl = searchParams.get('cancel_url'); const cancelUrl = searchParams.get('cancel_url');
const returnUrl = searchParams.get('return_url');
const formatCurrency = (amount, curr = 'USD') => {
return new Intl.NumberFormat('en-US', {
style: 'currency',
currency: curr,
}).format(parseFloat(amount));
};
const getErrorMessage = () => {
if (error) {
return decodeURIComponent(error);
}
return 'Your payment was cancelled. You can try again or choose a different payment method.';
};
const handleRetryPayment = () => { const handleRetryPayment = () => {
// Build the payment URL with original parameters
const paymentUrl = new URL('/payment', window.location.origin); const paymentUrl = new URL('/payment', window.location.origin);
if (orderId) { // Preserve all original order parameters
paymentUrl.searchParams.set('wc_order_id', orderId); if (orderId) paymentUrl.searchParams.set('wc_order_id', orderId);
// You might want to fetch original order details here if (orderTotal) paymentUrl.searchParams.set('total', orderTotal);
paymentUrl.searchParams.set('total', '25.99'); // This should come from order data if (currency) paymentUrl.searchParams.set('currency', currency);
} if (description) paymentUrl.searchParams.set('description', description);
if (customerEmail) paymentUrl.searchParams.set('customer_email', customerEmail);
if (returnUrl) paymentUrl.searchParams.set('return_url', returnUrl);
if (cancelUrl) paymentUrl.searchParams.set('cancel_url', cancelUrl);
window.location.href = paymentUrl.toString(); window.location.href = paymentUrl.toString();
}; };
@@ -41,7 +61,7 @@ const Cancel = () => {
<Alert.Content> <Alert.Content>
<Alert.Title>Payment Cancelled</Alert.Title> <Alert.Title>Payment Cancelled</Alert.Title>
<Alert.Description> <Alert.Description>
<Text>Your payment was cancelled. You can try again or choose a different payment method.</Text> <Text>{getErrorMessage()}</Text>
</Alert.Description> </Alert.Description>
</Alert.Content> </Alert.Content>
</Alert.Root> </Alert.Root>
@@ -63,6 +83,13 @@ const Cancel = () => {
<strong>Order ID:</strong> <strong>Order ID:</strong>
<span className="badge bg-secondary ms-2">{orderId}</span> <span className="badge bg-secondary ms-2">{orderId}</span>
<br/> <br/>
{orderTotal && (
<>
<strong>Order Total:</strong>
<span className="ms-2">{formatCurrency(orderTotal, currency)}</span>
<br/>
</>
)}
<small className="mt-2 d-block"> <small className="mt-2 d-block">
Your order is still pending. You can complete the payment to process your order. Your order is still pending. You can complete the payment to process your order.
</small> </small>
@@ -121,7 +148,7 @@ const Cancel = () => {
<Accordion.ItemIndicator/> <Accordion.ItemIndicator/>
</Accordion.ItemTrigger> </Accordion.ItemTrigger>
<Accordion.ItemContent> <Accordion.ItemContent>
<Accordion.ItemBody>Text</Accordion.ItemBody> <Accordion.ItemBody>Contact Support: Reach us anytime at {import.meta.env.VITE_REACT_APP_SUPPORT_EMAIL} or through live chat.</Accordion.ItemBody>
</Accordion.ItemContent> </Accordion.ItemContent>
</Accordion.Item> </Accordion.Item>
</Accordion.Root> </Accordion.Root>

View File

@@ -190,7 +190,7 @@ const Payment = () => {
<Grid <Grid
templateColumns={{ base: "1fr", md: "repeat(3, 1fr)" }} templateColumns={{ base: "1fr", md: "repeat(3, 1fr)" }}
templateRows="repeat(1, 1fr)" templateRows="repeat(1, 1fr)"
gap="6" // gap="6"
> >
<GridItem colSpan={2}> <GridItem colSpan={2}>
<Center> <Center>

8
frontend/src/theme.js Normal file
View File

@@ -0,0 +1,8 @@
import { createSystem, defaultConfig, defineConfig } from "@chakra-ui/react";
const config = defineConfig({
// put tokens/recipes if you need; not required just to force light mode
theme: {},
});
export const system = createSystem(defaultConfig, config);