Compare commits
2 Commits
5df46cba7e
...
b997e14fe6
| Author | SHA1 | Date | |
|---|---|---|---|
| b997e14fe6 | |||
| ee1ce09508 |
@@ -9,6 +9,103 @@ if (!defined('ABSPATH')) {
|
|||||||
|
|
||||||
class WC_Aluxpay_Payment_Gateway extends WC_Payment_Gateway {
|
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, you’ll 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 don’t 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, you’ll 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 don’t 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
|
* 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_api_' . $this->id, array($this, 'webhook_handler'));
|
||||||
add_action('woocommerce_thankyou_' . $this->id, array($this, 'thankyou_page'));
|
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);
|
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) {
|
public function thankyou_page($order_id) {
|
||||||
|
|
||||||
if ($this->description) {
|
/**if ($this->description) {
|
||||||
echo wpautop(wptexturize($this->description));
|
echo wpautop(wptexturize($this->description));
|
||||||
}
|
}*/
|
||||||
|
|
||||||
$order = wc_get_order($order_id);
|
$order = wc_get_order($order_id);
|
||||||
|
|
||||||
if ($order && $order->get_status() === 'processing') {
|
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) {
|
public function email_instructions($order, $sent_to_admin, $plain_text = false) {
|
||||||
|
|
||||||
if ($this->description && !$sent_to_admin && $this->id === $order->get_payment_method()) {
|
/** if ($this->description && !$sent_to_admin && $this->id === $order->get_payment_method()) {
|
||||||
echo wpautop(wptexturize($this->description)) . PHP_EOL;
|
* 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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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,
|
||||||
|
|||||||
@@ -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">
|
||||||
|
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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}>
|
||||||
<App />
|
<ThemeProvider attribute="class" defaultTheme="light" enableSystem={false}>
|
||||||
</Provider>
|
<App />
|
||||||
|
</ThemeProvider>
|
||||||
|
</ChakraProvider>
|
||||||
</StrictMode>,
|
</StrictMode>,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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
8
frontend/src/theme.js
Normal 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);
|
||||||
Reference in New Issue
Block a user