Compare commits

...

2 Commits

Author SHA1 Message Date
b997e14fe6 Added text for failed and successful orders 2025-10-12 01:18:26 +02:00
ee1ce09508 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
2025-10-12 00:45:36 +02:00
8 changed files with 208 additions and 29 deletions

View File

@@ -9,6 +9,103 @@ if (!defined('ABSPATH')) {
class WC_Aluxpay_Payment_Gateway extends WC_Payment_Gateway {
/**
* Reusable: HTML notice for Thank You page + HTML emails
*/
protected function get_generic_notice_html(): string {
// Keep inline styles for email clients; translate strings
$html .= '<p><strong>' . esc_html__( 'Thank you for your payment!', 'aluxpay-payment-gateway' ) . '</strong> ';
$html .= esc_html__( 'Your order has been successfully processed, and a confirmation email has been sent from our webstore.', 'aluxpay-payment-gateway' ) . '</p>';
$html .= '<h5>' . esc_html__( 'Important Note:', 'aluxpay-payment-gateway' ) . '</h5>';
$html .= '<p>' . esc_html__( "Because of the nature of our business and how our website integrates with PayPal, youll also receive a PayPal payment confirmation email. That email will display a generic product name instead of the specific item(s) you purchased.", 'aluxpay-payment-gateway' ) . '</p>';
$html .= '<p>' . esc_html__( 'Rest assured — your order is fully confirmed, and the webstore confirmation email contains the correct details of your purchase.', 'aluxpay-payment-gateway' ) . '</p>';
$html .= '<p>' . esc_html__( "If you have any questions or need assistance, please dont hesitate to contact our support team.", 'aluxpay-payment-gateway' ) . '</p>';
// For frontend we can allow basic tags; for email we echo directly.
$allowed = array(
'p' => array('style'=>true),
'h5' => array('style'=>true),
'strong' => array(),
);
return wp_kses( $html, $allowed );
}
/**
* Reusable: Plain-text version for plain emails
*/
protected function get_generic_notice_plain(): string {
$lines = array(
__( 'Thank you for your payment! Your order has been successfully processed, and a confirmation email has been sent from our webstore.', 'aluxpay-payment-gateway' ),
'',
__( 'Important Note:', 'aluxpay-payment-gateway' ),
__( "Because of the nature of our business and how our website integrates with PayPal, youll also receive a PayPal payment confirmation email. That email will display a generic product name instead of the specific item(s) you purchased.", 'aluxpay-payment-gateway' ),
__( 'Rest assured — your order is fully confirmed, and the webstore confirmation email contains the correct details of your purchase.', 'aluxpay-payment-gateway' ),
'',
__( "If you have any questions or need assistance, please dont hesitate to contact our support team.", 'aluxpay-payment-gateway' ),
);
return implode( PHP_EOL, $lines ) . PHP_EOL;
}
/**
* Reusable: HTML notice for Failed Order emails
*/
protected function get_failed_notice_html(): string {
$html = '';
$html .= '<p><strong>' . esc_html__( 'Payment Failed', 'aluxpay-payment-gateway' ) . '</strong></p>';
$html .= '<p>' . esc_html__( 'Unfortunately, your payment could not be processed. This may have occurred for one of the following reasons:', 'aluxpay-payment-gateway' ) . '</p>';
$html .= '<ul style="margin-left: 20px;">';
$html .= '<li>' . esc_html__( 'Insufficient funds in your account', 'aluxpay-payment-gateway' ) . '</li>';
$html .= '<li>' . esc_html__( 'Payment was cancelled during the process', 'aluxpay-payment-gateway' ) . '</li>';
$html .= '<li>' . esc_html__( 'Payment method declined the transaction', 'aluxpay-payment-gateway' ) . '</li>';
$html .= '<li>' . esc_html__( 'Technical issue during payment processing', 'aluxpay-payment-gateway' ) . '</li>';
$html .= '</ul>';
$html .= '<p>' . esc_html__( 'Your order has not been completed and no charges have been made to your account.', 'aluxpay-payment-gateway' ) . '</p>';
$html .= '<h5>' . esc_html__( 'What to do next:', 'aluxpay-payment-gateway' ) . '</h5>';
$html .= '<p>' . esc_html__( 'You can try placing your order again by visiting our website. If you continue to experience issues, please contact us for assistance.', 'aluxpay-payment-gateway' ) . '</p>';
$html .= '<p>' . esc_html__( 'We apologize for any inconvenience this may have caused.', 'aluxpay-payment-gateway' ) . '</p>';
$allowed = array(
'p' => array('style'=>true),
'h5' => array('style'=>true),
'ul' => array('style'=>true),
'li' => array(),
'strong' => array(),
);
return wp_kses( $html, $allowed );
}
/**
* Reusable: Plain-text version for Failed Order emails
*/
protected function get_failed_notice_plain(): string {
$lines = array(
__( 'Payment Failed', 'aluxpay-payment-gateway' ),
'',
__( 'Unfortunately, your payment could not be processed. This may have occurred for one of the following reasons:', 'aluxpay-payment-gateway' ),
'',
'- ' . __( 'Insufficient funds in your account', 'aluxpay-payment-gateway' ),
'- ' . __( 'Payment was cancelled during the process', 'aluxpay-payment-gateway' ),
'- ' . __( 'Payment method declined the transaction', 'aluxpay-payment-gateway' ),
'- ' . __( 'Technical issue during payment processing', 'aluxpay-payment-gateway' ),
'',
__( 'Your order has not been completed and no charges have been made to your account.', 'aluxpay-payment-gateway' ),
'',
__( 'What to do next:', 'aluxpay-payment-gateway' ),
__( 'You can try placing your order again by visiting our website. If you continue to experience issues, please contact us for assistance.', 'aluxpay-payment-gateway' ),
'',
__( 'We apologize for any inconvenience this may have caused.', 'aluxpay-payment-gateway' ),
);
return implode( PHP_EOL, $lines ) . PHP_EOL;
}
/**
* Constructor
*/
@@ -42,8 +139,12 @@ class WC_Aluxpay_Payment_Gateway extends WC_Payment_Gateway {
add_action('woocommerce_api_' . $this->id, array($this, 'webhook_handler'));
add_action('woocommerce_thankyou_' . $this->id, array($this, 'thankyou_page'));
// Customer Emails
// Customer Emails - Success
add_action('woocommerce_email_before_order_table', array($this, 'email_instructions'), 10, 3);
// Customer Emails - Failed Orders
add_action('woocommerce_email_before_order_table', array($this, 'failed_email_instructions'), 10, 3);
}
/**
@@ -233,24 +334,58 @@ class WC_Aluxpay_Payment_Gateway extends WC_Payment_Gateway {
*/
public function thankyou_page($order_id) {
if ($this->description) {
/**if ($this->description) {
echo wpautop(wptexturize($this->description));
}
}*/
$order = wc_get_order($order_id);
if ($order && $order->get_status() === 'processing') {
echo '<p>' . __('Your payment has been received and your order is being processed.', 'aluxpay-payment-gateway') . '</p>';
echo $this->get_generic_notice_html();
}
}
/**
* Add content to the WC emails
* Add content to the WC emails for successful orders
*/
public function email_instructions($order, $sent_to_admin, $plain_text = false) {
if ($this->description && !$sent_to_admin && $this->id === $order->get_payment_method()) {
echo wpautop(wptexturize($this->description)) . PHP_EOL;
/** if ($this->description && !$sent_to_admin && $this->id === $order->get_payment_method()) {
* echo wpautop(wptexturize($this->description)) . PHP_EOL;
*} */
if ( $sent_to_admin ) return; // customers only
if ( ! $order instanceof WC_Order ) return;
if ( $order->get_payment_method() !== $this->id ) return;
// Only show for completed/processing orders
if ( ! in_array( $order->get_status(), array( 'processing', 'completed' ) ) ) return;
// Pick the right format for the email renderer
if ( $plain_text ) {
echo $this->get_generic_notice_plain();
} else {
echo $this->get_generic_notice_html();
}
}
/**
* Add content to the WC emails for failed orders
*/
public function failed_email_instructions($order, $sent_to_admin, $plain_text = false) {
if ( $sent_to_admin ) return; // customers only
if ( ! $order instanceof WC_Order ) return;
if ( $order->get_payment_method() !== $this->id ) return;
// Only show for failed orders
if ( $order->get_status() !== 'failed' ) return;
// Pick the right format for the email renderer
if ( $plain_text ) {
echo $this->get_failed_notice_plain();
} else {
echo $this->get_failed_notice_html();
}
}
}

View File

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

View File

@@ -39,11 +39,11 @@ function App() {
gap={4}
>
<Image width="550px" src={logo} className="logo react" alt="React logo" />
<Center>
<Button variant="outline" onClick={toggleColorMode} >
{colorMode === "light" ? <><LuSun /> Toggle Light mode</> : <><LuMoon /> Toogle Dark mode</>}
</Button>
</Center>
{/*<Center>*/}
{/* <Button variant="outline" onClick={toggleColorMode} >*/}
{/* {colorMode === "light" ? <><LuSun /> Toggle Light mode</> : <><LuMoon /> Toogle Dark mode</>}*/}
{/* </Button>*/}
{/*</Center>*/}
</Grid>
<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.Item>
)}*/}
{order.shipping.method &&
<DataList.Item pt="4">
<DataList.ItemLabel>
<Badge colorPalette="teal" variant="solid">
@@ -72,7 +73,7 @@ const OrderSummary = ({ orderData, loading, order }) => {
</Badge>
</DataList.ItemLabel>
<DataList.ItemValue>{formatCurrency(order.shipping.total, orderData.currency)}</DataList.ItemValue>
</DataList.Item>
</DataList.Item> }
</> }
<DataList.Item pt="4" textStyle="xl">
<DataList.ItemLabel><strong>Total Amount:</strong></DataList.ItemLabel>

View File

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

View File

@@ -16,20 +16,40 @@ const Cancel = () => {
const [searchParams] = useSearchParams();
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 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 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 = () => {
// Build the payment URL with original parameters
const paymentUrl = new URL('/payment', window.location.origin);
if (orderId) {
paymentUrl.searchParams.set('wc_order_id', orderId);
// You might want to fetch original order details here
paymentUrl.searchParams.set('total', '25.99'); // This should come from order data
}
// Preserve all original order parameters
if (orderId) paymentUrl.searchParams.set('wc_order_id', orderId);
if (orderTotal) paymentUrl.searchParams.set('total', orderTotal);
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();
};
@@ -41,7 +61,7 @@ const Cancel = () => {
<Alert.Content>
<Alert.Title>Payment Cancelled</Alert.Title>
<Alert.Description>
<Text>Your payment was cancelled. You can try again or choose a different payment method.</Text>
<Text>{getErrorMessage()}</Text>
</Alert.Description>
</Alert.Content>
</Alert.Root>
@@ -63,6 +83,13 @@ const Cancel = () => {
<strong>Order ID:</strong>
<span className="badge bg-secondary ms-2">{orderId}</span>
<br/>
{orderTotal && (
<>
<strong>Order Total:</strong>
<span className="ms-2">{formatCurrency(orderTotal, currency)}</span>
<br/>
</>
)}
<small className="mt-2 d-block">
Your order is still pending. You can complete the payment to process your order.
</small>
@@ -121,7 +148,7 @@ const Cancel = () => {
<Accordion.ItemIndicator/>
</Accordion.ItemTrigger>
<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.Item>
</Accordion.Root>

View File

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