@@ -1,13 +1,43 @@ | |||||
<template> | <template> | ||||
<div> | <div> | ||||
<h4>hello</h4> | |||||
<h4>Billing</h4> | |||||
<div id="payment-element"></div> | |||||
<div id="message"></div> | |||||
<button @click="submit" class="btn btn-primary">Submit</button> | |||||
</div> | </div> | ||||
</template> | </template> | ||||
<script setup> | <script setup> | ||||
import { ref } from "vue" | |||||
import { ref, onMounted } from "vue" | |||||
let stripe = Stripe(process.env.STRIPE_KEY) | |||||
const props = defineProps(["sub"]) | |||||
const stripe = Stripe(process.env.STRIPE_KEY) | |||||
const options = { clientSecret: props.sub.clientSecret } | |||||
const elements = stripe.elements(options) | |||||
const payEl = elements.create("payment") | |||||
function submit() { | |||||
let result = stripe.confirmPayment({ | |||||
//`Elements` instance that was used to create the Payment Element | |||||
elements, | |||||
confirmParams: { | |||||
return_url: "https://skouter.net/register", | |||||
} | |||||
}) | |||||
} | |||||
onMounted(() => { | |||||
checkPayment() | |||||
payEl.mount("#payment-element") | |||||
}) | |||||
</script> | </script> | ||||
<style scoped> | |||||
button.btn { | |||||
margin: 10px auto; | |||||
display: block; | |||||
min-width: 90px; | |||||
} | |||||
</style> |
@@ -0,0 +1,19 @@ | |||||
<template> | |||||
<section> | |||||
<h4 v-if="status == 'succeeded'">Payment succeeded!</h4> | |||||
<h4 v-if="status == 'processing'">Payment still processing. Try again later.</h4> | |||||
</section> | |||||
</template> | |||||
<script setup> | |||||
import { ref, onMounted } from "vue" | |||||
const props = defineProps(["status"]) | |||||
</script> | |||||
<style> | |||||
h4 { | |||||
text-align: center; | |||||
} | |||||
</style> |
@@ -1,8 +1,9 @@ | |||||
<template> | <template> | ||||
<section class="shadowbox"> | <section class="shadowbox"> | ||||
<h2>Register</h2> | <h2>Register</h2> | ||||
<account v-if="!step" :err="err" @submit="create" /> | |||||
<billing v-if="step" :err="err" @submit="create" /> | |||||
<account v-if="step == 1" :err="err" @submit="create" /> | |||||
<billing v-if="step == 2" :err="err" :sub="sub"/> | |||||
<completed v-if="step == 3" :err="err" :status="sub.paymentStatus"/> | |||||
</section> | </section> | ||||
</template> | </template> | ||||
@@ -10,10 +11,18 @@ | |||||
import { ref, onMounted } from "vue" | import { ref, onMounted } from "vue" | ||||
import Account from "./account.vue" | import Account from "./account.vue" | ||||
import Billing from "./billing.vue" | import Billing from "./billing.vue" | ||||
import Completed from "./completed.vue" | |||||
let err = ref("") | let err = ref("") | ||||
const step = ref(0) | |||||
const stripe = Stripe(process.env.STRIPE_KEY) | |||||
const step = ref(1) | |||||
const token = ref("") | const token = ref("") | ||||
const user = ref(null) | |||||
const sub = ref(null) | |||||
const clientSecret = new URLSearchParams(window.location.search).get( | |||||
'payment_intent_client_secret' | |||||
); | |||||
function getCookie(name) { | function getCookie(name) { | ||||
var re = new RegExp(name + "=([^;]+)") | var re = new RegExp(name + "=([^;]+)") | ||||
@@ -68,9 +77,17 @@ function intent(user) { | |||||
}, | }, | ||||
}).then(resp => { | }).then(resp => { | ||||
if (resp.ok) { | if (resp.ok) { | ||||
return resp.json().then(u => { | |||||
resp.json().then(s => { | |||||
err.value = "" | err.value = "" | ||||
console.log(u) | |||||
console.log(s) | |||||
sub.value = s | |||||
step.value++ | |||||
if (["processing", "succeeded"].includes(s.paymentStatus) && | |||||
clientSecret == s.clientSecret) { | |||||
step.value++ | |||||
} else { | |||||
step.value = 0 | |||||
} | |||||
}) | }) | ||||
} else { | } else { | ||||
resp.text().then( e => err.value = e) | resp.text().then( e => err.value = e) | ||||
@@ -80,7 +97,7 @@ function intent(user) { | |||||
onMounted(() => { | onMounted(() => { | ||||
getUser().then( u => { | getUser().then( u => { | ||||
if (u) intent(u) | |||||
if (u) { user.value = u; intent(u) } | |||||
}) | }) | ||||
}) | }) | ||||
</script> | </script> | ||||
@@ -64,6 +64,7 @@ CREATE TABLE subscription ( | |||||
user_id INT, | user_id INT, | ||||
customer_id VARCHAR(255) NOT NULL, | customer_id VARCHAR(255) NOT NULL, | ||||
client_secret VARCHAR(255) NOT NULL, | client_secret VARCHAR(255) NOT NULL, | ||||
payment_status VARCHAR(50) NOT NULL, | |||||
current_period_end INT DEFAULT 0, | current_period_end INT DEFAULT 0, | ||||
current_period_start INT DEFAULT 0, | current_period_start INT DEFAULT 0, | ||||
PRIMARY KEY (`id`), | PRIMARY KEY (`id`), | ||||
@@ -72,6 +72,7 @@ type Subscription struct { | |||||
Start int `json:"start"` | Start int `json:"start"` | ||||
End int `json:"end"` | End int `json:"end"` | ||||
ClientSecret string `json:"clientSecret,omitempty"` | ClientSecret string `json:"clientSecret,omitempty"` | ||||
PaymentStatus string `json:"paymentStatus"` | |||||
} | } | ||||
type User struct { | type User struct { | ||||
@@ -1262,7 +1263,8 @@ func querySub(db *sql.DB, id int) (Subscription, error) { | |||||
customer_id, | customer_id, | ||||
current_period_end, | current_period_end, | ||||
current_period_start, | current_period_start, | ||||
client_secret | |||||
client_secret, | |||||
payment_status | |||||
FROM subscription WHERE id = ? | FROM subscription WHERE id = ? | ||||
` | ` | ||||
row := db.QueryRow(query, id) | row := db.QueryRow(query, id) | ||||
@@ -1274,6 +1276,7 @@ func querySub(db *sql.DB, id int) (Subscription, error) { | |||||
&s.End, | &s.End, | ||||
&s.Start, | &s.Start, | ||||
&s.ClientSecret, | &s.ClientSecret, | ||||
&s.PaymentStatus, | |||||
) | ) | ||||
return s, err | return s, err | ||||
@@ -1290,7 +1293,8 @@ func (user *User) querySub(db *sql.DB) error { | |||||
customer_id, | customer_id, | ||||
current_period_end, | current_period_end, | ||||
current_period_start, | current_period_start, | ||||
client_secret | |||||
client_secret, | |||||
payment_status | |||||
FROM subscription WHERE user_id = ? | FROM subscription WHERE user_id = ? | ||||
` | ` | ||||
row := db.QueryRow(query, user.Id) | row := db.QueryRow(query, user.Id) | ||||
@@ -1303,6 +1307,7 @@ func (user *User) querySub(db *sql.DB) error { | |||||
&user.Sub.End, | &user.Sub.End, | ||||
&user.Sub.Start, | &user.Sub.Start, | ||||
&user.Sub.ClientSecret, | &user.Sub.ClientSecret, | ||||
&user.Sub.PaymentStatus, | |||||
) | ) | ||||
return err | return err | ||||
@@ -1421,9 +1426,10 @@ func (sub *Subscription) insertSub(db *sql.DB) (error) { | |||||
customer_id, | customer_id, | ||||
current_period_end, | current_period_end, | ||||
current_period_start, | current_period_start, | ||||
client_secret | |||||
client_secret, | |||||
payment_status | |||||
) | ) | ||||
VALUES (?, ?, ?, ?, ?, ?) | |||||
VALUES (?, ?, ?, ?, ?, ?, ?) | |||||
RETURNING id | RETURNING id | ||||
` | ` | ||||
@@ -1434,18 +1440,19 @@ func (sub *Subscription) insertSub(db *sql.DB) (error) { | |||||
sub.End, | sub.End, | ||||
sub.Start, | sub.Start, | ||||
sub.ClientSecret, | sub.ClientSecret, | ||||
sub.PaymentStatus, | |||||
) | ) | ||||
err = row.Scan(&sub.Id) | err = row.Scan(&sub.Id) | ||||
return err | return err | ||||
} | } | ||||
func (sub *Subscription) updateSubSecret(db *sql.DB) error { | |||||
func (sub *Subscription) updateSub(db *sql.DB) error { | |||||
var query string | var query string | ||||
var err error | var err error | ||||
query = `UPDATE subscription SET | |||||
client_secret = ? | |||||
query = `UPDATE subscription | |||||
SET client_secret = ?, payment_status = ? | |||||
WHERE id = ? | WHERE id = ? | ||||
` | ` | ||||
@@ -1459,11 +1466,15 @@ func (sub *Subscription) updateSubSecret(db *sql.DB) error { | |||||
&stripe.PaymentIntentParams{}) | &stripe.PaymentIntentParams{}) | ||||
if err != nil { return err } | if err != nil { return err } | ||||
_, err = db.Exec(query, | _, err = db.Exec(query, | ||||
p.ClientSecret, | p.ClientSecret, | ||||
p.Status, | |||||
sub.Id, | sub.Id, | ||||
) | ) | ||||
if err != nil { return err } | |||||
sub.ClientSecret = p.ClientSecret | |||||
sub.PaymentStatus = string(p.Status) | |||||
return err | return err | ||||
} | } | ||||
@@ -2972,7 +2983,7 @@ func subscribe(w http.ResponseWriter, db *sql.DB, r *http.Request) { | |||||
return | return | ||||
} | } | ||||
} | } | ||||
if user.Sub.Id == 0 { | if user.Sub.Id == 0 { | ||||
s, err := createSubscription(user.CustomerId) | s, err := createSubscription(user.CustomerId) | ||||
if err != nil { | if err != nil { | ||||
@@ -2986,10 +2997,20 @@ func subscribe(w http.ResponseWriter, db *sql.DB, r *http.Request) { | |||||
user.Sub.End = int(s.CurrentPeriodEnd) | user.Sub.End = int(s.CurrentPeriodEnd) | ||||
user.Sub.Start = int(s.CurrentPeriodStart) | user.Sub.Start = int(s.CurrentPeriodStart) | ||||
user.Sub.ClientSecret = s.LatestInvoice.PaymentIntent.ClientSecret | user.Sub.ClientSecret = s.LatestInvoice.PaymentIntent.ClientSecret | ||||
user.Sub.PaymentStatus = string(s.LatestInvoice.PaymentIntent.Status) | |||||
user.Sub.insertSub(db) | |||||
err = user.Sub.insertSub(db) | |||||
if err != nil { | |||||
http.Error(w, err.Error(), 500) | |||||
return | |||||
} | |||||
json.NewEncoder(w).Encode(user.Sub) | json.NewEncoder(w).Encode(user.Sub) | ||||
} else { | } else { | ||||
err = user.Sub.updateSub(db) | |||||
if err != nil { | |||||
http.Error(w, err.Error(), 500) | |||||
return | |||||
} | |||||
json.NewEncoder(w).Encode(user.Sub) | json.NewEncoder(w).Encode(user.Sub) | ||||
} | } | ||||