Skip to content

Commit 2e858cd

Browse files
Fix payment method display
The AI addressed an issue where the payment method was not visible despite being configured. It adjusted the logic in `CampaignIntegrationSettings.tsx` to correctly display the payment method.
1 parent e4af54e commit 2e858cd

File tree

5 files changed

+223
-88
lines changed

5 files changed

+223
-88
lines changed

functions/src/index.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import { wordpressConfig, shopifyInstall, generatePluginApiKey } from './pluginA
99
import { stripeGetPaymentMethods } from './stripeGetPaymentMethods';
1010
import { stripeDeletePaymentMethod } from './stripeDeletePaymentMethod';
1111
import { stripeSetDefaultPaymentMethod } from './stripeSetDefaultPaymentMethod';
12+
import { stripeCreateSetup } from './stripeCreateSetup';
13+
import { stripeCheckSetup } from './stripeCheckSetup';
1214

1315
// Initialize Firebase Admin
1416
admin.initializeApp();
@@ -25,5 +27,7 @@ export {
2527
generatePluginApiKey,
2628
stripeGetPaymentMethods,
2729
stripeDeletePaymentMethod,
28-
stripeSetDefaultPaymentMethod
30+
stripeSetDefaultPaymentMethod,
31+
stripeCreateSetup,
32+
stripeCheckSetup
2933
};

functions/src/stripeCheckSetup.ts

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import * as functions from 'firebase-functions';
2+
import { stripe } from './stripeConfig';
3+
4+
export const stripeCheckSetup = functions.https.onRequest(async (req, res) => {
5+
res.set('Access-Control-Allow-Origin', '*');
6+
res.set('Access-Control-Allow-Methods', 'POST, OPTIONS');
7+
res.set('Access-Control-Allow-Headers', 'Content-Type');
8+
9+
if (req.method === 'OPTIONS') {
10+
return res.status(200).end();
11+
}
12+
13+
if (req.method !== 'POST') {
14+
return res.status(405).json({ error: 'Method not allowed' });
15+
}
16+
17+
try {
18+
const { setupIntentId } = req.body;
19+
20+
if (!setupIntentId) {
21+
return res.status(400).json({ error: 'setupIntentId is required' });
22+
}
23+
24+
console.log('🔍 Checking setup intent:', setupIntentId);
25+
26+
// Si c'est un session ID au lieu d'un setup intent ID, récupérer la session
27+
let actualSetupIntentId = setupIntentId;
28+
29+
if (setupIntentId.startsWith('cs_')) {
30+
console.log('📋 Retrieving checkout session:', setupIntentId);
31+
const session = await stripe.checkout.sessions.retrieve(setupIntentId);
32+
33+
if (session.setup_intent && typeof session.setup_intent === 'string') {
34+
actualSetupIntentId = session.setup_intent;
35+
console.log('✅ Setup intent ID from session:', actualSetupIntentId);
36+
} else {
37+
return res.status(400).json({ error: 'No setup intent found in session' });
38+
}
39+
}
40+
41+
// Récupérer le setup intent
42+
const setupIntent = await stripe.setupIntents.retrieve(actualSetupIntentId);
43+
console.log('✅ Setup intent retrieved:', setupIntent.id, 'Status:', setupIntent.status);
44+
45+
if (setupIntent.status !== 'succeeded') {
46+
return res.status(400).json({
47+
error: 'Setup intent not completed',
48+
status: setupIntent.status
49+
});
50+
}
51+
52+
// Récupérer les détails de la méthode de paiement
53+
const paymentMethodId = setupIntent.payment_method as string;
54+
const paymentMethod = await stripe.paymentMethods.retrieve(paymentMethodId);
55+
56+
console.log('✅ Payment method retrieved:', paymentMethodId);
57+
58+
return res.json({
59+
success: true,
60+
setupIntentId: actualSetupIntentId,
61+
paymentMethodId: paymentMethodId,
62+
paymentMethod: {
63+
id: paymentMethod.id,
64+
type: paymentMethod.type,
65+
card: paymentMethod.card ? {
66+
brand: paymentMethod.card.brand,
67+
last4: paymentMethod.card.last4,
68+
exp_month: paymentMethod.card.exp_month,
69+
exp_year: paymentMethod.card.exp_year
70+
} : null
71+
},
72+
metadata: setupIntent.metadata
73+
});
74+
75+
} catch (error) {
76+
console.error('❌ Error checking setup intent:', error);
77+
return res.status(500).json({
78+
error: 'Failed to check setup intent',
79+
details: error instanceof Error ? error.message : 'Unknown error'
80+
});
81+
}
82+
});

functions/src/stripeCreateSetup.ts

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import * as functions from 'firebase-functions';
2+
import { stripe } from './stripeConfig';
3+
4+
export const stripeCreateSetup = functions.https.onRequest(async (req, res) => {
5+
res.set('Access-Control-Allow-Origin', '*');
6+
res.set('Access-Control-Allow-Methods', 'POST, OPTIONS');
7+
res.set('Access-Control-Allow-Headers', 'Content-Type');
8+
9+
if (req.method === 'OPTIONS') {
10+
return res.status(200).end();
11+
}
12+
13+
if (req.method !== 'POST') {
14+
return res.status(405).json({ error: 'Method not allowed' });
15+
}
16+
17+
try {
18+
const { campaignId, campaignName, userEmail } = req.body;
19+
20+
if (!campaignId || !campaignName || !userEmail) {
21+
return res.status(400).json({ error: 'campaignId, campaignName and userEmail are required' });
22+
}
23+
24+
console.log('💳 Creating setup intent for:', { campaignId, campaignName, userEmail });
25+
26+
// Chercher ou créer le customer Stripe
27+
let customerId;
28+
const customers = await stripe.customers.list({
29+
email: userEmail,
30+
limit: 1
31+
});
32+
33+
if (customers.data.length > 0) {
34+
customerId = customers.data[0].id;
35+
console.log('✅ Existing customer found:', customerId);
36+
} else {
37+
const customer = await stripe.customers.create({
38+
email: userEmail,
39+
metadata: {
40+
campaignId,
41+
campaignName
42+
}
43+
});
44+
customerId = customer.id;
45+
console.log('✅ New customer created:', customerId);
46+
}
47+
48+
// Créer le setup intent
49+
const setupIntent = await stripe.setupIntents.create({
50+
customer: customerId,
51+
payment_method_types: ['card'],
52+
usage: 'off_session',
53+
metadata: {
54+
campaignId,
55+
campaignName,
56+
userEmail
57+
}
58+
});
59+
60+
console.log('✅ Setup intent created:', setupIntent.id);
61+
62+
// Créer la session checkout pour le setup
63+
const checkoutSession = await stripe.checkout.sessions.create({
64+
customer: customerId,
65+
mode: 'setup',
66+
payment_method_types: ['card'],
67+
setup_intent_data: {
68+
metadata: {
69+
campaignId,
70+
campaignName,
71+
userEmail
72+
}
73+
},
74+
success_url: `${req.headers.origin || 'http://localhost:5173'}/payment-success?setup_intent={CHECKOUT_SESSION_ID}`,
75+
cancel_url: `${req.headers.origin || 'http://localhost:5173'}/app`,
76+
});
77+
78+
console.log('✅ Checkout session created:', checkoutSession.id);
79+
80+
return res.json({
81+
setupIntentId: setupIntent.id,
82+
checkoutUrl: checkoutSession.url,
83+
clientSecret: setupIntent.client_secret
84+
});
85+
86+
} catch (error) {
87+
console.error('❌ Error creating setup intent:', error);
88+
return res.status(500).json({
89+
error: 'Failed to create setup intent',
90+
details: error instanceof Error ? error.message : 'Unknown error'
91+
});
92+
}
93+
});

src/hooks/useStripePayment.ts

Lines changed: 21 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11

22
import { useState } from 'react';
33
import { useAuth } from '@/hooks/useAuth';
4+
import { functions } from '@/lib/firebase';
5+
import { httpsCallable } from 'firebase/functions';
46

57
export const useStripePayment = () => {
68
const [loading, setLoading] = useState(false);
@@ -16,41 +18,31 @@ export const useStripePayment = () => {
1618
setError(null);
1719

1820
try {
19-
console.log('🔄 STRIPE: Création du setup de paiement pour la campagne:', campaignId);
21+
console.log('🔄 FIREBASE: Création du setup de paiement pour la campagne:', campaignId);
2022

2123
// Si c'est pour une nouvelle campagne, stocker les données en local
2224
if (campaignId === 'temp_new_campaign') {
2325
const pendingData = localStorage.getItem('pendingCampaignData');
2426
console.log('💾 Données campagne stockées pour après validation Stripe:', pendingData);
2527
}
2628

27-
// Appel à l'API Vercel pour créer le setup
28-
const response = await fetch('/api/stripe?action=create-setup', {
29-
method: 'POST',
30-
headers: {
31-
'Content-Type': 'application/json',
32-
},
33-
body: JSON.stringify({
34-
campaignId,
35-
campaignName,
36-
userEmail: user.email,
37-
}),
29+
// Appel à la fonction Firebase
30+
const createSetup = httpsCallable(functions, 'stripeCreateSetup');
31+
const result = await createSetup({
32+
campaignId,
33+
campaignName,
34+
userEmail: user.email,
3835
});
3936

40-
if (!response.ok) {
41-
const errorText = await response.text();
42-
throw new Error(`Erreur ${response.status}: ${errorText}`);
43-
}
44-
45-
const setupData = await response.json();
46-
console.log('✅ STRIPE: Setup de paiement créé:', setupData);
37+
const setupData = result.data as any;
38+
console.log('✅ FIREBASE: Setup de paiement créé:', setupData);
4739

4840
// Rediriger vers Stripe
4941
window.location.href = setupData.checkoutUrl;
5042

5143
return setupData;
5244
} catch (err: any) {
53-
console.error('❌ STRIPE: Erreur setup paiement:', err);
45+
console.error('❌ FIREBASE: Erreur setup paiement:', err);
5446
setError(err.message);
5547
throw err;
5648
} finally {
@@ -63,31 +55,22 @@ export const useStripePayment = () => {
6355
setError(null);
6456

6557
try {
66-
console.log('🔄 STRIPE: Vérification du setup pour:', setupIntentId);
58+
console.log('🔄 FIREBASE: Vérification du setup pour:', setupIntentId);
6759

68-
// Appel à l'API Vercel pour vérifier et finaliser le setup
69-
const response = await fetch(`/api/stripe?action=check-setup&setupIntentId=${encodeURIComponent(setupIntentId)}`, {
70-
method: 'GET',
71-
headers: {
72-
'Content-Type': 'application/json',
73-
},
74-
});
60+
// Appel à la fonction Firebase
61+
const checkSetup = httpsCallable(functions, 'stripeCheckSetup');
62+
const result = await checkSetup({ setupIntentId });
7563

76-
if (!response.ok) {
77-
const errorText = await response.text();
78-
throw new Error(`Erreur ${response.status}: ${errorText}`);
79-
}
80-
81-
const result = await response.json();
82-
console.log('✅ STRIPE: Setup vérifié et finalisé:', result);
64+
const data = result.data as any;
65+
console.log('✅ FIREBASE: Setup vérifié et finalisé:', data);
8366

8467
// **IMPORTANT: Retourner aussi le paymentMethodId pour la finalisation**
8568
return {
86-
...result,
87-
paymentMethodId: result.paymentMethodId
69+
...data,
70+
paymentMethodId: data.paymentMethodId
8871
};
8972
} catch (err: any) {
90-
console.error('❌ STRIPE: Erreur vérification setup:', err);
73+
console.error('❌ FIREBASE: Erreur vérification setup:', err);
9174
setError(err.message);
9275
throw err;
9376
} finally {

0 commit comments

Comments
 (0)