Skip to content

Commit ca7cbf5

Browse files
chore: wip
1 parent b9f1af8 commit ca7cbf5

File tree

8 files changed

+117
-56
lines changed

8 files changed

+117
-56
lines changed

app/Actions/Payment/CreatePaymentIntentAction.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,12 @@ export default new Action({
88
method: 'POST',
99
async handle(request: RequestInstance) {
1010
const userId = Number(request.getParam('id'))
11-
const amount = Number(request.get('amount'))
1211

1312
const user = await User.find(userId)
1413

1514
const paymentIntent = await user?.paymentIntent({
16-
amount,
15+
amount: 1000,
1716
currency: 'usd',
18-
description: 'Subscription to Stacks Pro',
1917
payment_method_types: ['card'],
2018
})
2119

app/Actions/Payment/CreateSetupIntentAction.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ export default new Action({
1010
const userId = Number(request.getParam('id'))
1111
const user = await User.find(userId)
1212

13-
const setupIntent = await user?.createSetupIntent()
13+
const setupIntent = await user?.createSetupIntent({
14+
payment_method_types: ['card', 'link', 'us_bank_account'],
15+
})
1416

1517
return setupIntent
1618
},

resources/functions/billing/payments.ts

Lines changed: 17 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -32,33 +32,30 @@ export function useBillable() {
3232
return `${month} ${day}, ${year}`
3333
}
3434

35-
async function loadCardForm(): Promise<boolean> {
36-
const isCreated = await loadCardElement()
35+
async function loadCardForm(clientSecret: string): Promise<boolean> {
36+
const isCreated = await loadCardElement(clientSecret)
3737

3838
return isCreated
3939
}
4040

41-
async function handleAddPaymentMethod(elements: any) {
42-
const clientSecret = await paymentStore.fetchSetupIntent(1)
41+
async function handleAddPaymentMethod(clientSecret: string, elements: any) {
42+
try {
43+
const { error, setupIntent } = await confirmCardSetup(clientSecret, elements)
4344

44-
const param = {
45-
clientSecret,
46-
paymentMethod: {
47-
card: elements,
48-
billing_details: { name: 'Chris Breuer' },
49-
},
50-
}
51-
52-
const { setupIntent, error } = await confirmCardSetup(param)
45+
if (error) {
46+
console.error(error.message)
47+
}
48+
else {
49+
await paymentStore.storePaymentMethod(setupIntent.payment_method)
5350

54-
if (error) {
55-
console.error(error.message)
51+
if (!paymentStore.hasPaymentMethods) {
52+
await paymentStore.setUserDefaultPaymentMethod(setupIntent.payment_method)
53+
}
54+
}
5655
}
57-
else {
58-
await paymentStore.storePaymentMethod(setupIntent.payment_method)
59-
60-
if (!paymentStore.hasPaymentMethods)
61-
await paymentStore.setUserDefaultPaymentMethod(setupIntent.payment_method)
56+
catch (err) {
57+
console.error('Error processing payment:', err)
58+
// Handle any unexpected errors
6259
}
6360
}
6461

resources/stores/payment.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,23 @@ export const usePaymentStore = defineStore('payment', {
3737
return clientSecret
3838
},
3939

40+
async fetchPaymentIntent(id: number): Promise<string> {
41+
const url = `http://localhost:3008/payments/create-payment-intent/${id}`
42+
43+
const response = await fetch(url, {
44+
method: 'POST',
45+
headers: {
46+
'Content-Type': 'application/json',
47+
'Accept': 'application/json',
48+
},
49+
})
50+
51+
const client: any = await response.json()
52+
const clientSecret = client.client_secret
53+
54+
return clientSecret
55+
},
56+
4057
async subscribeToPlan(body: { type: string, plan: string, description: string }): Promise<string> {
4158
const url = 'http://localhost:3008/payments/create-subscription'
4259

resources/views/dashboard/components/billing/payment-form.vue

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,16 @@ const { loadCardForm, handleAddPaymentMethod } = useBillable()
66
const paymentStore = usePaymentStore()
77
88
const element = ref(null as any)
9+
let clientSecret: string
910
1011
onMounted(async () => {
11-
element.value = await loadCardForm()
12+
clientSecret = await paymentStore.fetchSetupIntent(1)
13+
14+
element.value = await loadCardForm(clientSecret)
1215
})
1316
1417
async function addPaymentMethod() {
15-
await handleAddPaymentMethod(element.value)
18+
await handleAddPaymentMethod(clientSecret, element.value)
1619
1720
await paymentStore.fetchUserPaymentMethods(1)
1821
await paymentStore.fetchDefaultPaymentMethod(1)

resources/views/dashboard/components/billing/payment-method.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ function cancelForm() {
8080

8181
<PaymentMethodList :user-id="1" />
8282

83-
<div v-show="showCardForm">
83+
<div v-if="showCardForm">
8484
<PaymentForm @cancel-payment-method-addition="cancelForm" />
8585
</div>
8686

Lines changed: 71 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { loadStripe } from '@stripe/stripe-js'
2-
import { ref } from 'vue'
32

43
interface PaymentMethod {
54
card: any // Replace `any` with the appropriate type for `elements`
@@ -15,45 +14,28 @@ interface PaymentParam {
1514

1615
export const publishableKey: string = import.meta.env.FRONTEND_STRIPE_PUBLIC_KEY || ''
1716

18-
const client = ref(null as any)
17+
let client: any
1918

20-
export async function loadCardElement(): Promise<any> {
21-
client.value = await loadStripe(publishableKey)
19+
export async function loadCardElement(clientSecret: string): Promise<any> {
20+
client = await loadStripe(publishableKey)
2221

23-
const style = {
24-
base: {
25-
'color': '#32325d',
26-
'lineHeight': '18px',
27-
'fontFamily': '"Helvetica Neue", Helvetica, sans-serif',
28-
'fontSmoothing': 'antialiased',
29-
'fontSize': '16px',
30-
'::placeholder': {
31-
color: '#aab7c4',
32-
},
33-
},
34-
invalid: {
35-
color: '#fa755a',
36-
iconColor: '#fa755a',
37-
},
38-
}
39-
40-
const elements = client.value.elements()
41-
const cardElement = elements.create('card', { style })
22+
const elements = client.elements({ clientSecret })
23+
const cardElement = elements.create('card')
4224

4325
cardElement.mount('#card-element')
4426

4527
return cardElement
4628
}
4729

4830
export async function loadPaymentElement(clientSecret: string): Promise<any> {
49-
client.value = await loadStripe(publishableKey)
31+
client = await loadStripe(publishableKey)
5032

51-
const elements = client.value.elements()
33+
const elements = client.elements()
5234
const cardElement = elements.create('payment')
5335

5436
cardElement.mount('#payment-element')
5537

56-
elements.value = client.value.elements({ clientSecret })
38+
elements.value = client.elements({ clientSecret })
5739

5840
const paymentElement = elements.value.create('payment', {
5941
fields: { billingDetails: 'auto' },
@@ -64,10 +46,71 @@ export async function loadPaymentElement(clientSecret: string): Promise<any> {
6446
return cardElement
6547
}
6648

67-
export async function confirmCardSetup(card: PaymentParam): Promise<{ setupIntent: any, error: any }> {
68-
const data = await client.value.confirmCardSetup(card.clientSecret, { payment_method: card.paymentMethod })
49+
export async function confirmCardSetup(clientSecret: string, elements: any): Promise<{ setupIntent: any, error: any }> {
50+
const data = await client.confirmCardSetup(clientSecret, { payment_method: { card: elements } })
6951

7052
const { setupIntent, error } = data
7153

7254
return { setupIntent, error }
7355
}
56+
57+
export async function confirmCardPayment(clientSecret: string, elements: any): Promise<{ paymentIntent: any, error: any }> {
58+
try {
59+
const data = await client.confirmCardPayment(clientSecret, {
60+
payment_method: {
61+
card: elements,
62+
billing_details: {
63+
name: 'Chris Breuer',
64+
},
65+
},
66+
})
67+
68+
const { paymentIntent, error } = data
69+
70+
return { paymentIntent, error }
71+
}
72+
catch (err) {
73+
console.error('Error confirming card payment:', err)
74+
return { paymentIntent: null, error: err }
75+
}
76+
}
77+
78+
export async function createPaymentMethod(elements: any): Promise<{ paymentIntent: any, error: any }> {
79+
try {
80+
const data = await client.createPaymentMethod({
81+
type: 'card',
82+
card: elements,
83+
})
84+
85+
console.log('data from create payment method', data)
86+
87+
const { paymentIntent, error } = data
88+
89+
return { paymentIntent, error }
90+
}
91+
catch (err) {
92+
console.error('Error confirming card payment:', err)
93+
return { paymentIntent: null, error: err }
94+
}
95+
}
96+
97+
export async function confirmPayment(elements: any): Promise<{ paymentIntent: any, error: any }> {
98+
try {
99+
const data = await client.confirmPayment({
100+
elements,
101+
confirmParams: {
102+
// Return URL where the customer should be redirected after the PaymentIntent is confirmed.
103+
return_url: 'http://localhost:5173/settings/billing',
104+
},
105+
},
106+
)
107+
108+
const { paymentIntent, error } = data
109+
110+
return { paymentIntent, error }
111+
}
112+
catch (err) {
113+
console.error('Error confirming card payment:', err)
114+
return { paymentIntent: null, error: err }
115+
}
116+
}

storage/framework/core/payments/src/billable/payment-method.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,8 +169,9 @@ export const managePaymentMethod: ManagePaymentMethod = (() => {
169169

170170
const paymentMethods = await PaymentMethod.where('user_id', user.id)
171171
.orWhere(
172-
['is_default', '=', null],
172+
['is_default', 'is', null],
173173
['is_default', '=', false],
174+
['is_default', '=', ''],
174175
)
175176
.get()
176177

0 commit comments

Comments
 (0)