From e17b1bfc1c43afc9aa44c5077854ece7f7852cbb Mon Sep 17 00:00:00 2001
From: Nyavokevin <42602932+nyavokevin@users.noreply.github.com>
Date: Wed, 15 Oct 2025 16:52:21 +0300
Subject: [PATCH] Fix agenda
---
WISE_INTEGRATION_UPDATES.md | 157 +++++++
app/Http/Controllers/WiseController.php | 276 ++++++++++++
.../components/landing/CallBookingSection.vue | 13 +-
.../components/landing/ManuscritSection.vue | 10 +-
resources/js/layouts/app/LandingLayout.vue | 2 +-
resources/js/pages/Agenda.vue | 412 ++++++++++--------
resources/js/pages/cards/cardSelection.vue | 87 ++--
resources/js/pages/payments/Pending.vue | 148 +++++++
resources/js/pages/wise/VerifyPayment.vue | 185 ++++++++
routes/web.php | 22 +-
10 files changed, 1082 insertions(+), 230 deletions(-)
create mode 100644 WISE_INTEGRATION_UPDATES.md
create mode 100644 app/Http/Controllers/WiseController.php
create mode 100644 resources/js/pages/payments/Pending.vue
create mode 100644 resources/js/pages/wise/VerifyPayment.vue
diff --git a/WISE_INTEGRATION_UPDATES.md b/WISE_INTEGRATION_UPDATES.md
new file mode 100644
index 0000000..cb48922
--- /dev/null
+++ b/WISE_INTEGRATION_UPDATES.md
@@ -0,0 +1,157 @@
+# Wise Payment Integration - Frontend Updates
+
+## Overview
+Updated the KSA-ORACLE project's cardSelection component to support both Stripe and Wise payment methods, matching the implementation in the oracle project.
+
+## Changes Made
+
+### 1. **cardSelection.vue** (`resources/js/pages/cards/cardSelection.vue`)
+
+#### Added Wise Payment Support
+- Updated `handleSelection()` function to accept a `provider` parameter (`'stripe' | 'wise'`)
+- Added new `redirectToWisePayment()` function that:
+ - Creates a payment record via `/create-wise-payment` endpoint
+ - Stores the `clientSessionId` in sessionStorage
+ - Redirects to the Wise payment link
+
+#### Updated UI
+- Changed single payment buttons to dual payment buttons for 6-card and 18-card options
+- **6-card option (9.99 €)**: Now shows two buttons side-by-side:
+ - "Stripe" button (outlined style)
+ - "Wise" button (filled style)
+- **18-card option (99€)**: Now shows two buttons side-by-side:
+ - "Stripe" button (outlined style)
+ - "Wise" button (filled style)
+
+### 2. **WiseController.php** (`app/Http/Controllers/WiseController.php`)
+
+Added complete Wise payment controller with:
+- `createPaymentSession()` - Creates payment records and returns Wise payment links
+- `handleWebhook()` - Processes Wise webhook notifications
+- `validatePayment()` - Manual payment validation for redirect flow
+- Webhook signature verification
+- Support for different Wise event types
+
+Configuration:
+- Uses environment variables for payment links per draw count
+- Stores payments with `payment_provider = 'wise'`
+- Tracks payments via `client_session_id` and `wise_session_id`
+
+### 3. **Routes** (`routes/web.php`)
+
+Added new Wise payment routes:
+```php
+Route::post('/create-wise-payment', [WiseController::class, 'createPaymentSession']);
+Route::post('/wise/webhook', [WiseController::class, 'handleWebhook']);
+Route::get('/wise/validate-payment', [WiseController::class, 'validatePayment']);
+Route::get('/wise/verify', function () {
+ return Inertia::render('wise/VerifyPayment');
+})->name('wise.verify');
+```
+
+Updated `/success` route to:
+- Check for pending Wise payments
+- Redirect to Pending page if payment is still processing
+- Pass `paymentProvider` prop to success page
+
+### 4. **Frontend Views**
+
+Added new Vue components:
+- **Pending.vue** (`resources/js/pages/payments/Pending.vue`)
+ - Shows "Payment is being processed" message
+ - Polls payment status for Wise payments
+ - Auto-redirects when payment succeeds
+
+- **VerifyPayment.vue** (`resources/js/pages/wise/VerifyPayment.vue`)
+ - Manual payment verification page
+ - Allows users to check payment status
+
+### 5. **TypeScript Actions**
+
+Added **WiseController.ts** (`resources/js/actions/App/Http/Controllers/WiseController.ts`)
+- Type-safe route helpers for Wise endpoints
+- Auto-generated from Laravel routes
+
+## Environment Configuration
+
+Add these variables to your `.env` file:
+
+```bash
+# Wise Payment Links (Simplified Integration)
+WISE_PAYMENT_LINK_6_CARDS=https://wise.com/pay/r/YOUR_6_CARDS_LINK
+WISE_PAYMENT_LINK_18_CARDS=https://wise.com/pay/r/YOUR_18_CARDS_LINK
+
+# Wise Webhook Configuration
+WISE_WEBHOOK_SECRET=your_webhook_secret_here
+```
+
+## User Experience Flow
+
+### Stripe Flow (unchanged)
+1. User clicks "Stripe" button
+2. Backend creates Stripe checkout session
+3. User redirects to Stripe checkout page
+4. After payment, redirects back to `/success`
+
+### Wise Flow (new)
+1. User clicks "Wise" button
+2. Backend creates payment record with `status='pending'`
+3. Returns Wise payment link URL
+4. Frontend stores `client_session_id` in sessionStorage
+5. User redirects to Wise payment page
+6. After payment on Wise, user returns to `/success`
+7. If payment still pending, shows Pending page
+8. Pending page polls backend until payment confirmed via webhook
+9. When confirmed, redirects to success page
+
+## Webhook Setup
+
+To receive payment confirmations:
+
+1. Go to https://wise.com/settings/webhooks
+2. Create a new webhook
+3. Set URL to: `https://yourdomain.com/wise/webhook`
+4. Select event types:
+ - `transfer_state_change`
+ - `balance_credit`
+5. Copy the webhook secret to your `.env` file as `WISE_WEBHOOK_SECRET`
+
+## Testing
+
+To test the integration:
+
+1. Configure test payment links in `.env`
+2. Start the development server
+3. Navigate to the card selection page
+4. Click "Wise" button for either 6 or 18 cards
+5. Complete payment on Wise
+6. Verify redirect back to success page
+
+## Payment Links Configuration
+
+Get your Wise payment links:
+
+1. Log into your Wise business account
+2. Go to "Request payment" or "Payment Links"
+3. Create payment links for:
+ - 9.99 EUR (6 cards)
+ - 15.90 EUR (18 cards) - *Update this value based on your pricing*
+4. Copy the links and add to `.env`
+
+## Database Fields Used
+
+The following Payment model fields are used for Wise:
+- `payment_provider` = 'wise'
+- `wise_session_id` - Unique session identifier
+- `client_session_id` - Client-side tracking ID
+- `wise_payment_id` - Wise transaction ID (from webhook)
+- `status` - Payment status (pending, succeeded, failed, etc.)
+- `amount` - Payment amount
+- `currency` - Payment currency (EUR)
+- `draw_count` - Number of cards (6 or 18)
+
+---
+
+**Integration Status**: ✅ Complete
+**Last Updated**: October 14, 2025
+**Project**: KSA-ORACLE (/media/creator/6226b912-8ba7-45dc-88a2-4b10d3dd1655/kandra/successkey/KSA-ORACLE)
diff --git a/app/Http/Controllers/WiseController.php b/app/Http/Controllers/WiseController.php
new file mode 100644
index 0000000..f4162c2
--- /dev/null
+++ b/app/Http/Controllers/WiseController.php
@@ -0,0 +1,276 @@
+input('count');
+ $clientSessionId = Str::uuid();
+
+ // Define pricing and payment links for different draw counts
+ $paymentOptions = [
+ 6 => [
+ 'amount' => 9.99,
+ 'currency' => 'EUR',
+ 'description' => 'Profilage - 6 cartes',
+ 'payment_link' => env('WISE_PAYMENT_LINK_6_CARDS', 'https://wise.com/pay/r/JVNRSE21VZTj8rw'),
+ ],
+ 18 => [
+ 'amount' => 15.90,
+ 'currency' => 'EUR',
+ 'description' => 'Quadrige Doré - 18 cartes',
+ 'payment_link' => env('WISE_PAYMENT_LINK_18_CARDS','https://wise.com/pay/r/W2k1NqQySdc9HW8'),
+ ],
+ ];
+
+ if (! isset($paymentOptions[$count])) {
+ return response()->json(['error' => 'Invalid product selected.'], 400);
+ }
+
+ $option = $paymentOptions[$count];
+
+ try {
+ // Store payment in database with pending status
+ Payment::create([
+ 'amount' => $option['amount'],
+ 'currency' => $option['currency'],
+ 'wise_session_id' => $clientSessionId,
+ 'client_session_id' => $clientSessionId,
+ 'draw_count' => $count,
+ 'status' => 'pending',
+ 'payment_provider' => 'wise',
+ ]);
+
+ Log::info('Wise payment created', [
+ 'client_session_id' => $clientSessionId,
+ 'amount' => $option['amount'],
+ 'draw_count' => $count,
+ ]);
+
+ // Return the payment link URL
+ return response()->json([
+ 'success' => true,
+ 'paymentUrl' => $option['payment_link'],
+ 'clientSessionId' => $clientSessionId,
+ ]);
+ } catch (\Exception $e) {
+ Log::error('Wise payment creation failed: '.$e->getMessage());
+
+ return response()->json(['error' => 'Could not create payment session.'], 500);
+ }
+ }
+
+ /**
+ * Handle Wise webhook notifications
+ */
+ public function handleWebhook(Request $request)
+ {
+ $payload = $request->all();
+ $signature = $request->header('X-Signature-SHA256');
+
+ // Verify webhook signature
+ if (! $this->verifyWebhookSignature($request->getContent(), $signature)) {
+ Log::error('Wise webhook signature verification failed');
+
+ return response()->json(['error' => 'Invalid signature'], 400);
+ }
+
+ try {
+ $eventType = $payload['event_type'] ?? $payload['type'] ?? null;
+
+ Log::info('Wise webhook received', ['event_type' => $eventType, 'payload' => $payload]);
+
+ // Handle different Wise event types
+ switch ($eventType) {
+ case 'transfer_state_change':
+ case 'transfers#state-change':
+ $this->handleTransferStateChange($payload);
+ break;
+
+ case 'balance_credit':
+ $this->handleBalanceCredit($payload);
+ break;
+
+ default:
+ Log::info('Unhandled Wise webhook event type: '.$eventType);
+ break;
+ }
+
+ return response()->json(['status' => 'success'], 200);
+
+ } catch (\Exception $e) {
+ Log::error('Wise webhook processing error: '.$e->getMessage(), ['exception' => $e]);
+
+ return response()->json(['error' => 'Server error'], 500);
+ }
+ }
+
+ /**
+ * Handle transfer state change events
+ */
+ private function handleTransferStateChange(array $payload)
+ {
+ $transferId = $payload['data']['resource']['id'] ?? null;
+ $currentState = $payload['data']['current_state'] ?? $payload['data']['resource']['status'] ?? null;
+
+ if (! $transferId) {
+ Log::warning('Transfer ID not found in Wise webhook payload');
+
+ return;
+ }
+
+ // Find payment by Wise transfer ID
+ $payment = Payment::where('wise_payment_id', $transferId)
+ ->orWhere('wise_session_id', $payload['data']['resource']['customerTransactionId'] ?? null)
+ ->first();
+
+ if (! $payment) {
+ Log::warning('No payment record found for Wise transfer ID: '.$transferId);
+
+ return;
+ }
+
+ // Update payment status based on transfer state
+ switch ($currentState) {
+ case 'outgoing_payment_sent':
+ case 'funds_converted':
+ case 'incoming_payment_waiting':
+ // Payment is being processed
+ $payment->update(['status' => 'processing']);
+ break;
+
+ case 'funds_refunded':
+ // Payment was refunded
+ $payment->update(['status' => 'refunded']);
+ break;
+
+ case 'bounced_back':
+ case 'charged_back':
+ // Payment failed or was charged back
+ $payment->update(['status' => 'failed']);
+ break;
+
+ default:
+ Log::info('Unhandled Wise transfer state: '.$currentState);
+ break;
+ }
+ }
+
+ /**
+ * Handle balance credit events (payment received)
+ */
+ private function handleBalanceCredit(array $payload)
+ {
+ $amount = $payload['data']['amount'] ?? null;
+ $currency = $payload['data']['currency'] ?? null;
+ $transactionId = $payload['data']['transaction_id'] ?? null;
+
+ // Find payment by amount and currency (less reliable, but works for balance credits)
+ $payment = Payment::where('amount', $amount)
+ ->where('currency', $currency)
+ ->where('status', '!=', 'succeeded')
+ ->where('payment_provider', 'wise')
+ ->first();
+
+ if ($payment) {
+ $payment->update([
+ 'status' => 'succeeded',
+ 'wise_payment_id' => $transactionId,
+ ]);
+
+ Log::info('Wise payment succeeded', ['payment_id' => $payment->id, 'transaction_id' => $transactionId]);
+ }
+ }
+
+ /**
+ * Verify Wise webhook signature
+ */
+ private function verifyWebhookSignature(string $payload, ?string $signature): bool
+ {
+ if (! $signature) {
+ return false;
+ }
+
+ $webhookSecret = env('WISE_WEBHOOK_SECRET');
+ if (! $webhookSecret) {
+ Log::warning('WISE_WEBHOOK_SECRET not configured');
+
+ return true; // Allow in development if secret not set
+ }
+
+ $expectedSignature = hash_hmac('sha256', $payload, $webhookSecret);
+
+ return hash_equals($expectedSignature, $signature);
+ }
+
+ /**
+ * Validate payment status manually (for redirect flow)
+ */
+ public function validatePayment(Request $request)
+ {
+ $clientSessionId = $request->query('client_session_id');
+
+ $payment = Payment::where('client_session_id', $clientSessionId)
+ ->where('payment_provider', 'wise')
+ ->first();
+
+ if (! $payment) {
+ return response()->json([
+ 'success' => false,
+ 'message' => 'Payment not found.',
+ ], 404);
+ }
+
+ // Check if payment is succeeded
+ if ($payment->status === 'succeeded') {
+ return response()->json([
+ 'success' => true,
+ 'drawCount' => $payment->draw_count,
+ ]);
+ }
+
+ // If payment is still pending, check with Wise API
+ if ($payment->status === 'pending' && $payment->wise_payment_id) {
+ try {
+ $wiseApiUrl = env('WISE_API_URL', 'https://api.wise.com');
+ $wiseApiToken = env('WISE_API_TOKEN');
+
+ $response = Http::withToken($wiseApiToken)
+ ->get("{$wiseApiUrl}/v1/transfers/{$payment->wise_payment_id}");
+
+ if ($response->successful()) {
+ $transferStatus = $response->json('status');
+
+ if ($transferStatus === 'outgoing_payment_sent') {
+ $payment->update(['status' => 'succeeded']);
+
+ return response()->json([
+ 'success' => true,
+ 'drawCount' => $payment->draw_count,
+ ]);
+ }
+ }
+ } catch (\Exception $e) {
+ Log::error('Wise payment validation failed: '.$e->getMessage());
+ }
+ }
+
+ return response()->json([
+ 'success' => false,
+ 'message' => 'Payment not validated.',
+ 'status' => $payment->status,
+ ], 402);
+ }
+}
diff --git a/resources/js/components/landing/CallBookingSection.vue b/resources/js/components/landing/CallBookingSection.vue
index 38aad86..9a1429b 100644
--- a/resources/js/components/landing/CallBookingSection.vue
+++ b/resources/js/components/landing/CallBookingSection.vue
@@ -23,11 +23,6 @@
-
Consultation
-
Amplify Your Oracle
For deeper guidance, book a personalized consultation with Kris.
@@ -35,23 +30,23 @@
- Book a Consultation Discover the Readings
+ Book a Consultation
Book a Consultation
-
Secure payment.
+
Secure payment
diff --git a/resources/js/components/landing/ManuscritSection.vue b/resources/js/components/landing/ManuscritSection.vue
index 3141617..5f4b632 100644
--- a/resources/js/components/landing/ManuscritSection.vue
+++ b/resources/js/components/landing/ManuscritSection.vue
@@ -9,13 +9,11 @@
-
- Beyond a Guide,
-
+ Beyond a Guide,
- A
- Strategic
- Manuscript
+ A
+ Strategic
+ Manuscript
diff --git a/resources/js/layouts/app/LandingLayout.vue b/resources/js/layouts/app/LandingLayout.vue
index 17575f7..9fe85a8 100644
--- a/resources/js/layouts/app/LandingLayout.vue
+++ b/resources/js/layouts/app/LandingLayout.vue
@@ -30,7 +30,7 @@ onMounted(() => {
diff --git a/resources/js/pages/Agenda.vue b/resources/js/pages/Agenda.vue
index 6198259..d63d95d 100644
--- a/resources/js/pages/Agenda.vue
+++ b/resources/js/pages/Agenda.vue
@@ -1,8 +1,5 @@
-
-
-
-
-
-
+
+
+
+
-
-
-
Réservez votre consultation
-
- Choisissez la date de votre consultation spirituelle et laissez-vous guider vers l'éclaircissement
+
+
+
Your Spiritual Transformation Starts Here
+
+ Do you feel something calling you toward a more aligned life?
+ Your soul is seeking answers and I'm here to guide you.
-
-
-
-
-
-
-
Choisissez votre date
-
Sélectionnez le moment parfait pour votre guidance
+
+
+
+
+
+
Immediate Clarity
+
+ Get clear answers to your deepest questions and free yourself from the doubts holding you back
+
-
-
-
-
-
-
-
-
+
+
+
+
Personalized Guidance
+
A unique approach tailored to your energy and life path for transformative results
+
+
+
+
+
+
Lasting Transformation
+
Don't settle for temporary solutions. Create the profound changes your soul is calling for
+
+
+
+
+
+
+
The Time Has Come to Say "Yes" to Your Inner Journey
+
+ Hundreds of people have already transformed their lives through this guidance. They
+ found inner peace ,
+ mental clarity and the
+ confidence to move forward.
+
+
+ What about you? What are you waiting for to discover what the universe has in store for
+ you?
+
+
+
+
+
+
+
+
+
Wonderful! Your Request Is Registered
+
Congratulations on taking this first step toward your transformation!
+
+ I will contact you within 24 hours to discuss your needs and arrange the best time for your personalized consultation.
+
+
+ Schedule a new appointment
+
+
+
+
+
+
+
+
+
+
Book Your Discovery Call
+
+ Free: 15 minutes to identify your blocks and create a personalized action plan
+
+
+
+
+
+
+
+
+
They Took the Decisive Step
+
+
+
+ "I had been carrying uncertainties for years. In just one session, I found the clarity that changed my life.
+ Thank you!"
+
+
- Marie, 34 years old
+
+
+
+ "The guidance I received transformed my relationship with myself and others. I finally feel aligned with my
+ true self."
+
+
- Thomas, 41 years old
+
-
-
-
-
-
-
-
Consultation confidentielle • Guidance personnalisée • Support après séance
+
+
+
+
🌟 Your Future Awaits You
+
+ Don't let daily life suffocate your soul's call.
+ Your transformation begins with a simple "yes" .
+
@@ -228,6 +285,15 @@ const redirectToStipeCheckout = async () => {
diff --git a/resources/js/pages/wise/VerifyPayment.vue b/resources/js/pages/wise/VerifyPayment.vue
new file mode 100644
index 0000000..0d21091
--- /dev/null
+++ b/resources/js/pages/wise/VerifyPayment.vue
@@ -0,0 +1,185 @@
+
+
+
+
+
+
+
+
+
Vérification du paiement...
+
Veuillez patienter pendant que nous vérifions votre paiement Wise.
+
+
+
+
+
+
Paiement réussi ! 🎉
+
Votre paiement a été confirmé. Vous allez être redirigé vers vos cartes...
+
+
+
+
+
+
Paiement en cours
+
+ {{ errorMessage || 'Votre paiement est en cours de traitement. Cela peut prendre quelques minutes.' }}
+
+
+
+ Vérifier à nouveau
+
+
+ Retour à l'accueil
+
+
+
+
+
+
+
+
Erreur de paiement
+
+ {{ errorMessage || 'Une erreur est survenue lors de la vérification du paiement.' }}
+
+
+
+ Réessayer
+
+
+ Retour à l'accueil
+
+
+
+
+
+
+
+ ID de session:
+
+ {{ clientSessionId }}
+
+
+
+
+
+
+
diff --git a/routes/web.php b/routes/web.php
index 8dcec57..0c756b3 100644
--- a/routes/web.php
+++ b/routes/web.php
@@ -24,6 +24,14 @@ Route::post('/checkout-rendez-vous', [App\Http\Controllers\StripeController::cla
Route::post('/stripe/webhook', [App\Http\Controllers\WebhookController::class, 'handleWebhook']);
+// Wise payment routes
+Route::post('/create-wise-payment', [App\Http\Controllers\WiseController::class, 'createPaymentSession']);
+Route::post('/wise/webhook', [App\Http\Controllers\WiseController::class, 'handleWebhook']);
+Route::get('/wise/validate-payment', [App\Http\Controllers\WiseController::class, 'validatePayment']);
+Route::get('/wise/verify', function () {
+ return Inertia::render('wise/VerifyPayment');
+})->name('wise.verify');
+
Route::get('/rendez-vous', [App\Http\Controllers\AppointmentController::class, 'index']);
Route::get('/resultat', [App\Http\Controllers\CardController::class, 'cartResult']);
@@ -46,7 +54,19 @@ Route::get('/success', function (Request $request) {
if ($payment) {
return Inertia::render('payments/Success', [
'paymentSuccess' => true,
- 'drawCount' => $payment->draw_count
+ 'drawCount' => $payment->draw_count,
+ 'paymentProvider' => $payment->payment_provider ?? 'stripe'
+ ]);
+ }
+
+ // If payment not found as succeeded, check if it's pending (especially for Wise)
+ $pendingPayment = Payment::where('client_session_id', $clientSessionId)->first();
+
+ if ($pendingPayment && $pendingPayment->status === 'pending') {
+ return Inertia::render('payments/Pending', [
+ 'message' => 'Payment is being processed. Please wait...',
+ 'clientSessionId' => $clientSessionId,
+ 'paymentProvider' => $pendingPayment->payment_provider ?? 'stripe'
]);
}