Creating front end page for plans

This commit is contained in:
vinchent 2024-08-11 22:08:55 +02:00
parent a564ecb342
commit 16e5845559
9 changed files with 134 additions and 11 deletions

View File

@ -260,3 +260,20 @@ func (app *application) ChargeOnce(w http.ResponseWriter, r *http.Request) {
app.errorLog.Println(err) app.errorLog.Println(err)
} }
} }
func (app *application) BronzePlan(w http.ResponseWriter, r *http.Request) {
widget, err := app.DB.GetWidget(2)
if err != nil {
app.errorLog.Println(err)
return
}
data := make(map[string]interface{})
data["widget"] = widget
if err := app.renderTemplate(w, r, "bronze-plan", &templateData{
Data: data,
}); err != nil {
app.errorLog.Println(err)
}
}

View File

@ -19,6 +19,8 @@ func (app *application) routes() http.Handler {
mux.Get("/receipt", app.Receipt) mux.Get("/receipt", app.Receipt)
mux.Post("/payment-succeeded", app.PaymentSucceeded) mux.Post("/payment-succeeded", app.PaymentSucceeded)
mux.Get("/plans/bronze", app.BronzePlan)
fileServer := http.FileServer(http.Dir("./static")) fileServer := http.FileServer(http.Dir("./static"))
mux.Handle("/static/*", http.StripPrefix("/static", fileServer)) mux.Handle("/static/*", http.StripPrefix("/static", fileServer))

View File

@ -46,7 +46,7 @@
<a class="dropdown-item" href="/widget/1">Buy one widget</a> <a class="dropdown-item" href="/widget/1">Buy one widget</a>
</li> </li>
<li> <li>
<a class="dropdown-item" href="#">Subscription</a> <a class="dropdown-item" href="/plans/bronze">Subscription</a>
</li> </li>
</ul> </ul>
</li> </li>

View File

@ -0,0 +1,96 @@
{{ template "base" . }}
{{ define "title" }}
Bronze Plan
{{ end }}
{{ define "content" }}
{{$widget := index .Data "widget"}}
<h2 class="mt-3 text-center">Bronze Plan: {{formatCurrency $widget.Price}}</h2>
<hr>
<div class="alert alert-danger text-center d-none" id="card-messages"></div>
<form action="/payment-succeeded-temp"
method="post"
name="charge_form"
id="charge_form"
class="d-blick needs-validation charge-form"
autocomplete="off"
novalidate="">
<input type="hidden" name="product_id" value="{{$widget.ID}}">
<input type="hidden" id="amount" name="amount" value="{{$widget.Price}}">
<p class="mt-2 mb-3 text-center">{{$widget.Description}}</p>
<hr>
<div class="mb-3">
<label for="first-name" class="form-label">First Name</label>
<input type="text"
id="first-name"
name="first_name"
autocomplete="first-name-new"
required=""
class="form-control">
</div>
<div class="mb-3">
<label for="last-name" class="form-label">Last Name</label>
<input type="text"
id="last-name"
name="last_name"
autocomplete="last-name-new"
required=""
class="form-control">
</div>
<div class="mb-3">
<label for="cardholder-email" class="form-label">Email</label>
<input type="text"
id="cardholder-email"
name="cardholder_email"
autocomplete="cardholder-email-new"
required=""
class="form-control">
<div class="mb-3">
<label for="cardholder-name" class="form-label">Name on card</label>
<input type="text"
id="cardholder-name"
name="cardholder_name"
autocomplete="cardholder-name-new"
required=""
class="form-control">
</div>
</div>
<!-- card number will be built by stripe -->
<div class="mb-3">
<label for="card-element" class="form-label">Credit Card</label>
<div class="form-control" id="card-element"></div>
<div class="alert-danger text-center" id="card-errors" role="alert"></div>
<div class="alert-success text-center" id="card-success" role="alert"></div>
</div>
<hr>
<a href="javascript:void(0)"
id="pay-button"
class="btn btn-primary"
onclick="val({{.API}})">Pay {{formatCurrency $widget.Price}}/month</a>
<div class="text-center d-none" id="processing-payment">
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">Loading...</span>
</div>
</div>
<input id="payment_intent"
type="hidden"
name="payment_intent"
value="payment_intent">
<input id="payment_method"
type="hidden"
name="payment_method"
value="payment_method">
<input id="payment_amount"
type="hidden"
name="payment_amount"
value="payment_amount">
<input id="payment_currency"
type="hidden"
name="payment_currency"
value="payment_currency">
</form>
{{ end }}
{{ define "js" }}
<script src="https://js.stripe.com/v3/"></script>
<script src="/static/js/stripe.js"></script>
<script>stripeInit('{{.StripePubKey}}');</script>
{{ end }}

View File

@ -48,15 +48,15 @@ Buy one widget
autocomplete="cardholder-email-new" autocomplete="cardholder-email-new"
required="" required=""
class="form-control"> class="form-control">
<div class="mb-3"> <div class="mb-3">
<label for="cardholder-name" class="form-label">Name on card</label> <label for="cardholder-name" class="form-label">Name on card</label>
<input type="text" <input type="text"
id="cardholder-name" id="cardholder-name"
name="cardholder_name" name="cardholder_name"
autocomplete="cardholder-name-new" autocomplete="cardholder-name-new"
required="" required=""
class="form-control"> class="form-control">
</div> </div>
</div> </div>
<!-- card number will be built by stripe --> <!-- card number will be built by stripe -->
<div class="mb-3"> <div class="mb-3">

View File

@ -15,4 +15,3 @@ Payment Succedded!
<p>Bank Return Code: {{ $txn.BankReturnCode }}</p> <p>Bank Return Code: {{ $txn.BankReturnCode }}</p>
<p>Expiry Date: {{ $txn.ExpiryMonth }}/{{$txn.ExpiryYear}}</p> <p>Expiry Date: {{ $txn.ExpiryMonth }}/{{$txn.ExpiryYear}}</p>
{{ end }} {{ end }}

View File

@ -33,6 +33,8 @@ type Widget struct {
CreatedAt time.Time `json:"-"` CreatedAt time.Time `json:"-"`
UpdatedAt time.Time `json:"-"` UpdatedAt time.Time `json:"-"`
Image string `json:"image"` Image string `json:"image"`
IsRecurring bool `json:"is_recurring"`
PlanID string `json:"plan_id"`
} }
// Order is the type for all orders // Order is the type for all orders
@ -109,6 +111,7 @@ func (m *DBModel) GetWidget(id int) (Widget, error) {
query := `SELECT id, name, description, inventory_level, price, query := `SELECT id, name, description, inventory_level, price,
coalesce(image, ''), coalesce(image, ''),
is_recurring, plan_id,
created_at, updated_at created_at, updated_at
FROM widgets WHERE id = ?;` FROM widgets WHERE id = ?;`
@ -120,6 +123,8 @@ func (m *DBModel) GetWidget(id int) (Widget, error) {
&widget.InventoryLevel, &widget.InventoryLevel,
&widget.Price, &widget.Price,
&widget.Image, &widget.Image,
&widget.IsRecurring,
&widget.PlanID,
&widget.CreatedAt, &widget.CreatedAt,
&widget.UpdatedAt, &widget.UpdatedAt,
) )

View File

@ -0,0 +1,2 @@
drop_column("widgets", "is_recurring")
drop_column("widgets", "plan_id")

View File

@ -0,0 +1,2 @@
add_column("widgets", "is_recurring", "bool", {"default": 0})
add_column("widgets", "plan_id", "string", {"default": ""})