Skip to content

Commit 4390ca8

Browse files
chore: wip
1 parent bdaee96 commit 4390ca8

File tree

7 files changed

+89
-35
lines changed

7 files changed

+89
-35
lines changed
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import type { RequestInstance } from '@stacksjs/types'
2+
import { Action } from '@stacksjs/actions'
3+
import User from '../../../storage/framework/orm/src/models/User.ts'
4+
5+
export default new Action({
6+
name: 'StorePaymentMethodAction',
7+
description: 'Store the customers payment methods',
8+
method: 'POST',
9+
async handle(request: RequestInstance) {
10+
const userId = Number(request.getParam('id'))
11+
const user = await User.find(userId)
12+
const paymentIntent = request.get('setupIntent') as string
13+
14+
const paymentMethod = await user?.addPaymentMethod(paymentIntent)
15+
16+
return paymentMethod
17+
},
18+
})

resources/functions/billing/payments.ts

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -45,19 +45,19 @@ export function useBillable() {
4545
card: elements,
4646
billing_details: { name: 'Chris Breuer' },
4747
},
48-
};
49-
50-
51-
// const { setupIntent, error } =
52-
await confirmCardSetup(param)
53-
54-
// if (error) {
55-
// console.error(error.message)
56-
// } // Display or handle error for the user
57-
// else {
58-
// if (!paymentStore.hasPaymentMethods)
59-
// await paymentStore.setDefaultPaymentMethod(setupIntent.payment_method)
60-
// }
48+
}
49+
50+
const { setupIntent, error } = await confirmCardSetup(param)
51+
52+
if (error) {
53+
console.error(error.message)
54+
} // Display or handle error for the user
55+
else {
56+
if (!paymentStore.hasPaymentMethods)
57+
await paymentStore.setDefaultPaymentMethod(setupIntent.payment_method)
58+
else
59+
await paymentStore.storePaymentMethod(setupIntent.payment_method)
60+
}
6161
}
6262

6363
function isEmpty(object: any) {

resources/stores/payment.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,25 @@ export const usePaymentStore = defineStore('payment', {
9494
return res
9595
},
9696

97+
async storePaymentMethod(setupIntent: string): Promise<string> {
98+
const url = 'http://localhost:3008/stripe/payment-method/1'
99+
100+
const body = { setupIntent }
101+
102+
const response = await fetch(url, {
103+
method: 'POST',
104+
headers: {
105+
'Content-Type': 'application/json',
106+
'Accept': 'application/json',
107+
},
108+
body: JSON.stringify(body),
109+
})
110+
111+
const res: any = await response.json()
112+
113+
return res
114+
},
115+
97116
openPlans() {
98117
this.planState = true
99118
},

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

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@ onMounted( async () => {
1414
})
1515
1616
async function addPaymentMethod() {
17-
// console.log(paymentIntent.value)
18-
// console.log(element.value)
1917
await handleAddPaymentMethod(paymentIntent.value, element.value)
2018
}
2119
</script>
@@ -27,7 +25,7 @@ async function addPaymentMethod() {
2725
>
2826
<div id="link-authentication-element" />
2927
<div id="card-element" />
30-
<button @click="addPaymentMethod" type="button" class="rounded bg-indigo-600 w-full px-2 py-1 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600">Save Payment Method</button>
28+
<button @click="addPaymentMethod" type="button" class="rounded bg-indigo-600 w-full px-2 py-1 mt-4 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600">Save Payment Method</button>
3129
</form>
3230
</div>
3331
</template>

routes/api.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ route.group({ prefix: '/payments' }, async () => {
3636
route.delete('/delete-payment-method/{id}', 'Actions/Payment/DeleteDefaultPaymentAction')
3737
route.put('/update-default-payment-method/{id}', 'Actions/Payment/UpdateDefaultPaymentMethodAction')
3838
route.post('/set-default-payment-method/{id}', 'Actions/Payment/SetDefaultPaymentAction')
39+
route.post('/payment-method/{id}', 'Actions/Payment/StorePaymentMethodAction')
3940
route.post('/create-payment-intent/{id}', 'Actions/Payment/CreatePaymentIntentAction')
4041
route.post('/create-subscription/{id}', 'Actions/Payment/CreateSubscriptionAction')
4142
route.post('/update-subscription/{id}', 'Actions/Payment/UpdateSubscriptionAction')

storage/framework/core/browser/src/utils/billlable.ts

Lines changed: 3 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -21,22 +21,7 @@ export async function loadCardElement(clientSecret: string): Promise<any> {
2121
client.value = await loadStripe(publishableKey)
2222

2323
const elements = client.value.elements()
24-
const cardElement = elements.create('card', {
25-
style: {
26-
base: {
27-
color: '#32325d',
28-
fontFamily: '"Poppins", sans-serif',
29-
fontSize: '16px',
30-
fontWeight: '500',
31-
'::placeholder': {
32-
color: '#aab7c4',
33-
},
34-
},
35-
invalid: {
36-
color: '#fa755a',
37-
},
38-
},
39-
})
24+
const cardElement = elements.create('card')
4025

4126
cardElement.mount('#card-element')
4227

@@ -63,9 +48,9 @@ export async function loadPaymentElement(clientSecret: string): Promise<any> {
6348
}
6449

6550
export async function confirmCardSetup(card: PaymentParam): Promise<{ setupIntent: any, error: any }> {
66-
console.log(card)
51+
const data = await client.value.confirmCardSetup(card.clientSecret, { payment_method: card.paymentMethod })
6752

68-
const { setupIntent, error } = await client.value.confirmCardSetup(card.clientSecret, { payment_method: card.paymentMethod })
53+
const { setupIntent, error } = data
6954

7055
return { setupIntent, error }
7156
}

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

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export interface ManagePaymentMethod {
88
addPaymentMethod: (user: UserModel, paymentMethod: string | Stripe.PaymentMethod) => Promise<Stripe.Response<Stripe.PaymentMethod>>
99
updatePaymentMethod: (user: UserModel, paymentMethodId: string, updateParams?: Stripe.PaymentMethodUpdateParams) => Promise<Stripe.Response<Stripe.PaymentMethod>>
1010
setDefaultPaymentMethod: (user: UserModel, paymentMethodId: string) => Promise<Stripe.Response<Stripe.Customer>>
11+
storePaymentMethod: (user: UserModel, paymentMethodId: string) => Promise<PaymentMethodModel>
1112
deletePaymentMethod: (user: UserModel, paymentMethodId: string) => Promise<Stripe.Response<Stripe.PaymentMethod>>
1213
retrievePaymentMethod: (user: UserModel, paymentMethodId: number) => Promise<PaymentMethodModel | undefined>
1314
retrieveDefaultPaymentMethod: (user: UserModel) => Promise<PaymentMethodModel | undefined>
@@ -35,6 +36,8 @@ export const managePaymentMethod: ManagePaymentMethod = (() => {
3536
})
3637
}
3738

39+
storePaymentMethod(user, stripePaymentMethod.id)
40+
3841
return stripePaymentMethod as Stripe.Response<Stripe.PaymentMethod>
3942
}
4043

@@ -57,9 +60,39 @@ export const managePaymentMethod: ManagePaymentMethod = (() => {
5760
},
5861
})
5962

63+
storePaymentMethod(user, paymentMethodId)
64+
6065
return updatedCustomer
6166
}
6267

68+
async function storePaymentMethod(user: UserModel, paymentMethodId: string): Promise<PaymentMethodModel> {
69+
if (!user.hasStripeId()) {
70+
throw new Error('Customer does not exist in Stripe')
71+
}
72+
73+
const paymentMethod = await stripe.paymentMethod.retrieve(paymentMethodId)
74+
75+
const method = {
76+
type: 'card',
77+
last_four: Number(paymentMethod.card?.last4),
78+
brand: paymentMethod.card?.brand,
79+
exp_year: paymentMethod.card?.exp_year,
80+
exp_month: paymentMethod.card?.exp_month,
81+
user_id: user.id,
82+
provider_id: paymentMethod.id
83+
}
84+
85+
if (paymentMethod.customer !== user.stripe_id) {
86+
await stripe.paymentMethod.attach(paymentMethod.id, {
87+
customer: user.stripe_id || '',
88+
})
89+
}
90+
91+
const model = await PaymentMethod.create(method)
92+
93+
return model
94+
}
95+
6396
async function deletePaymentMethod(user: UserModel, paymentMethodId: string): Promise<Stripe.Response<Stripe.PaymentMethod>> {
6497
if (!user.hasStripeId()) {
6598
throw new Error('Customer does not exist in Stripe')
@@ -124,5 +157,5 @@ export const managePaymentMethod: ManagePaymentMethod = (() => {
124157
return paymentMethod
125158
}
126159

127-
return { addPaymentMethod, deletePaymentMethod, retrieveDefaultPaymentMethod, updatePaymentMethod, listPaymentMethods, setDefaultPaymentMethod, retrievePaymentMethod }
160+
return { addPaymentMethod, deletePaymentMethod, retrieveDefaultPaymentMethod, updatePaymentMethod, listPaymentMethods, setDefaultPaymentMethod, storePaymentMethod, retrievePaymentMethod }
128161
})()

0 commit comments

Comments
 (0)