1// ===== cart.go =====
2// Package main complete.go
3package main
4
5import (
6 "encoding/json"
7 "fmt"
8 "log"
9 "strconv"
10 "strings"
11 "syscall/js"
12)
13
14func updateCartDisplayWrapper(this js.Value, args []js.Value) interface{} {
15 updateCartDisplay()
16 return nil
17}
18
19func saveCart() {
20 cartJSON, err := json.Marshal(cart)
21 if err != nil {
22 log.Println(wasmName+":", "Error saving cart:", err)
23 return
24 }
25 js.Global().Get("localStorage").Call("setItem", "cartItems", string(cartJSON))
26 updateCartDisplay()
27}
28
29func addToCart(this js.Value, args []js.Value) any {
30 if len(args) < 2 {
31 return "Error: Missing arguments"
32 }
33 var cartItem item
34 index := -1
35 id := args[0].String()
36 qty := args[2].Int()
37 if qty == 0 {
38 qty = 1
39 }
40 amount := int(args[1].Float()) * qty
41 for i, _ := range cart {
42 if strings.Split(cart[i].ID, "|")[0] == strings.Split(id, "|")[0] {
43 index = i
44 }
45 }
46 if index > -1 {
47 // update shipping
48 if strings.Split(cart[index].ID, "|")[0] == "shipping-to" {
49 cart[index].ID = id
50 cart[index].Qty = 1
51 cart[index].Amount = amount
52 } else {
53 cart[index].Qty = cart[index].Qty + qty
54 cart[index].Amount = cart[index].Amount + amount
55 }
56 } else {
57 cartItem = item{
58 ID: id,
59 Amount: amount,
60 Qty: qty,
61 }
62 cart = append(cart, cartItem)
63 }
64 saveCart()
65 return nil
66}
67
68func addUnToCart(this js.Value, args []js.Value) interface{} {
69 if len(args) < 2 {
70 return "Error: Missing arguments"
71 }
72 id := args[0].String()
73 price := args[1].Float()
74 quantityInput := doc.Call("getElementById", fmt.Sprintf("qty-%s", id))
75 if !quantityInput.Truthy() {
76 log.Println(wasmName+":", "Error: Quantity input not found for item", id)
77 return nil
78 }
79 quantity, err := strconv.Atoi(quantityInput.Get("value").String())
80 if err != nil || quantity < 1 {
81 quantity = 1
82 }
83
84 addToCart(js.Value{}, []js.Value{
85 js.ValueOf(id),
86 js.ValueOf(int(price * 100)),
87 js.ValueOf(quantity),
88 })
89 return nil
90}
91
92func removeFromCart(this js.Value, inputs []js.Value) interface{} {
93 id := inputs[0].String()
94 newCart := []item{}
95 for _, m := range cart {
96 if m.ID != id {
97 newCart = append(newCart, m)
98 }
99 }
100 cart = newCart
101 saveCart()
102 return nil
103}
104
105func loadCart() {
106 storedCart := js.Global().Get("localStorage").Call("getItem", "cartItems")
107 if !storedCart.IsUndefined() && !storedCart.IsNull() {
108 err := json.Unmarshal([]byte(storedCart.String()), &cart)
109 if err != nil {
110 log.Println(`can't unmarshal cart from local storage`)
111 cart = []item{}
112 }
113 }
114}
115
116func emptyCart(this js.Value, inputs []js.Value) interface{} {
117 js.Global().Get("localStorage").Call("removeItem", "cartItems")
118 cart = []item{}
119 updateCartDisplay()
120 return nil
121}
122
123func clearAll(this js.Value, inputs []js.Value) interface{} {
124 js.Global().Get("localStorage").Call("clear")
125 cart = []item{}
126 updateCartDisplay()
127 return nil
128}
129
130func updateCartDisplay() {
131 cartContainer := doc.Call("getElementById", "cart-items")
132 totalPriceElement := doc.Call("getElementById", "total-price")
133 table := cartContainer.Call("querySelector", "table")
134 if table.IsNull() {
135 table = doc.Call("createElement", "table")
136 thead := doc.Call("createElement", "thead")
137 thead.Set("innerHTML", `<tr><th>Item</th><th>Price</th><th>Quantity</th><th>Actions</th></tr>`)
138 table.Call("appendChild", thead)
139 tbody := doc.Call("createElement", "tbody")
140 tbody.Set("id", "cart-tbody")
141 table.Call("appendChild", tbody)
142 cartContainer.Call("appendChild", table)
143 }
144 tbody := doc.Call("getElementById", "cart-tbody")
145 tbody.Set("innerHTML", "")
146
147 total := 0
148 hasShipping := false
149 for _, m := range cart {
150 total += m.Amount
151 row := doc.Call("createElement", "tr")
152
153 row.Set("innerHTML", fmt.Sprintf(`<td>%s</td><td>$%.2f</td><td>%s</td><td><button onclick='removeFromCart("%s")'>Remove</button></td>`,
154 func() string {
155 parts := strings.Split(m.ID, "|")
156 if len(parts) < 8 {
157 return m.ID
158 }
159 hasShipping = true
160 return fmt.Sprintf("%s:<br>%s<br>%s<br>%s, %s %s<br>%s<br>%s", parts[0], parts[1], parts[2], parts[3], parts[4], parts[5], parts[6], parts[7])
161 }(),
162 float64(m.Amount)/100,
163 func() string {
164 if len(strings.Split(m.ID, "|")) == 8 {
165 return ""
166 }
167 return fmt.Sprintf(`<input type='number' value='%d' min='1' onchange='updateItemQuantity("%s", this.value)'>`, m.Qty, m.ID)
168 }(),
169 m.ID,
170 ))
171 tbody.Call("appendChild", row)
172 }
173 totalPriceElement.Set("textContent", fmt.Sprintf("Total: $%.2f", float64(total)/100))
174
175 checkoutbutton := doc.Call("getElementById", "checkout-button")
176 if !checkoutbutton.Truthy() {
177 return
178 }
179
180 if len(cart) > 1 && hasShipping {
181 checkoutbutton.Call("removeAttribute", "disabled")
182 } else {
183 checkoutbutton.Call("setAttribute", "disabled", "true")
184 }
185}
186
187func updateItemQuantity(this js.Value, args []js.Value) interface{} {
188 id := args[0].String()
189 qty, err := strconv.Atoi(args[1].String())
190 if err != nil {
191 log.Println(err)
192 }
193 for i, _ := range cart {
194 if cart[i].ID == id {
195 unitPrice := cart[i].Amount / cart[i].Qty
196 cart[i].Qty = qty
197 cart[i].Amount = unitPrice * qty
198 break
199 }
200 }
201 saveCart()
202 return nil
203}
204
205
206// ===== checkout.go =====
207package main
208
209import (
210 "encoding/json"
211 "fmt"
212 "log"
213 "strconv"
214 "syscall/js"
215)
216
217func addShippingInfo(this js.Value, args []js.Value) interface{} {
218 event := args[0]
219 form := args[1]
220 event.Call("preventDefault")
221 getFormValue := func(name string) string {
222 return form.Call("querySelector", fmt.Sprintf("[name='%s']", name)).Get("value").String()
223 }
224 shippingInfo := fmt.Sprintf("shipping-to|%s|%s|%s|%s|%s|%s|%s",
225 getFormValue("shipping-name"),
226 getFormValue("shipping-address"),
227 getFormValue("shipping-city"),
228 getFormValue("shipping-state"),
229 getFormValue("shipping-zip"),
230 getFormValue("shipping-country"),
231 getFormValue("shipping-phone"),
232 )
233 priceStr := getFormValue("shipping-price")
234 price, err := strconv.ParseFloat(priceStr, 64)
235 if err != nil {
236 log.Println(wasmName+":", "Error: Failed to parse shipping price")
237 price = 0.0
238 }
239
240 addToCart(js.Value{}, []js.Value{
241 js.ValueOf(shippingInfo),
242 js.ValueOf(int(price * 100)),
243 js.ValueOf(1),
244 })
245 return false
246}
247
248var (
249 elements js.Value
250 stripeValue js.Value
251 stripe js.Value
252 checkoutButton = doc.Call("getElementById", "checkout-button")
253 checkoutDiv = doc.Call("getElementById", "checkout-container")
254 checkoutStripe = doc.Call("getElementById", "stripecheckout")
255)
256
257func goToCheckout(this js.Value, args []js.Value) any {
258 if stripeValue.IsUndefined() {
259 log.Println(`js.Global().Get("Stripe")`)
260 stripeValue = js.Global().Get("Stripe")
261 if stripeValue.IsUndefined() {
262 log.Println(`Stripe is undefined, attempting to load Stripe.js`)
263
264 doc := js.Global().Get("document")
265 head := doc.Call("querySelector", "head")
266 script := doc.Call("createElement", "script")
267 script.Set("src", "https://js.stripe.com/v3/")
268 script.Set("defer", true)
269
270 done := make(chan bool)
271 script.Call("addEventListener", "load", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
272 log.Println(wasmName+":", "Stripe.js script has been loaded")
273 done <- true
274 return nil
275 }))
276
277 head.Call("appendChild", script)
278
279 <-done
280
281 stripeValue = js.Global().Get("Stripe")
282 if stripeValue.IsUndefined() {
283 log.Println(wasmName+":", "Failed to load Stripe.js")
284 return nil
285 }
286 }
287 }
288
289 log.Println(wasmName+":", "Stripe.js loaded successfully")
290
291 if stripe.IsUndefined() {
292 log.Println(wasmName+":", "Invoking Stripe")
293 stripe = stripeValue.Invoke(stripePK)
294 if stripe.IsUndefined() {
295 log.Println(wasmName+":", "Failed to invoke Stripe")
296 return nil
297 }
298 }
299
300 log.Println(wasmName+":", "Stripe initialized")
301 checkoutStripe = doc.Call("getElementById", "stripecheckout")
302 if checkoutStripe.IsUndefined() {
303 log.Println(wasmName+":", "element with ID stripecheckout not found")
304 }
305
306 checkoutStripe.Call("showModal")
307 log.Println(wasmName+":", "initializePayment()")
308 initializePayment()
309
310 return nil
311}
312
313func cancelCheckout(this js.Value, args []js.Value) any {
314 log.Println(wasmName+":", "Cancelling checkout ; closing dialog")
315 checkoutStripe.Call("close")
316 updateCartDisplay()
317 return nil
318}
319
320func initializePayment() {
321 type cItem struct {
322 ID string `json:"id"`
323 Amount int `json:"amount"`
324 }
325 type checkout struct {
326 Items []cItem `json:"items"`
327 }
328 payload := checkout{
329 Items: func() []cItem {
330 var items []cItem
331 for _, it := range cart {
332 items = append(items, cItem{ID: it.ID + " X " + strconv.Itoa(it.Qty), Amount: it.Amount})
333 }
334 return items
335 }(),
336 }
337 payloadJSON, err := json.Marshal(payload)
338 if err != nil {
339 log.Println(wasmName+":", "Error marshaling JSON:", err)
340 return
341 }
342 fetchInit := map[string]interface{}{
343 "method": "POST",
344 "headers": map[string]interface{}{
345 "Content-Type": "application/json",
346 },
347 "body": string(payloadJSON),
348 }
349
350 log.Println(wasmName+":", "fetch /create-payment-intent")
351 js.Global().Call("fetch", "/create-payment-intent", js.ValueOf(fetchInit)).
352 Call("then", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
353 response := args[0]
354 log.Println(wasmName+":", "got response from fetch /create-payment-intent")
355 if !response.Get("ok").Bool() {
356 log.Println(wasmName+":", "Fetch request failed with status:", response.Get("status").Int())
357 showMessage("Failed to create payment intent: " + response.Get("status").String())
358 return nil
359 }
360 response.Call("json").Call("then", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
361 clientSecret := args[0].Get("clientSecret").String()
362 log.Println(wasmName+":", "Client secret received:", clientSecret)
363 setupStripeElements(clientSecret)
364 return nil
365 })).Call("catch", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
366 log.Println(wasmName+":", "Error parsing JSON response:", args[0])
367 showMessage("Failed to parse payment intent response.")
368 return nil
369 }))
370 return nil
371 })).
372 Call("catch", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
373 log.Println(wasmName+":", "Error in fetch request:", args[0])
374 showMessage("Failed to communicate with the server.")
375 return nil
376 }))
377}
378
379func setupStripeElements(clientSecret string) {
380 elements = stripe.Call("elements", map[string]interface{}{
381 "clientSecret": clientSecret,
382 })
383 if elements.IsUndefined() {
384 log.Println(wasmName+":", "Failed to initialize Stripe Elements")
385 showMessage("Failed to initialize payment elements.")
386 return
387 }
388 paymentElement := elements.Call("create", "payment", map[string]interface{}{
389 "layout": "tabs",
390 })
391 if paymentElement.IsUndefined() {
392 log.Println(wasmName+":", "Failed to create payment element")
393 showMessage("Failed to create payment element.")
394 return
395 }
396 paymentElement.Call("mount", "#payment-element")
397 submitButton := doc.Call("getElementById", "submit")
398 submitButton.Call("addEventListener", "click", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
399 args[0].Call("preventDefault")
400 showSpinner(true)
401 confirmPayment(clientSecret)
402 return nil
403 }))
404}
405
406func confirmPayment(clientSecret string) {
407
408 windowLocation := js.Global().Get("window").Get("location")
409 protocol := windowLocation.Get("protocol").String()
410 hostname := windowLocation.Get("hostname").String()
411 port := windowLocation.Get("port").String()
412
413 baseURL := protocol + "//" + hostname
414 if port != "" {
415 baseURL += ":" + port
416 }
417 // path := windowLocation.Get("pathname").String()
418 // baseURL += strings.Split(path, "?")[0]
419 // log.Println(wasmName+":","return url ", baseURL)
420
421 returnURL := baseURL + "/complete"
422 returnURL += "?payment_intent=" + clientSecret // + "#complete"
423 log.Println(wasmName+":", "Return URL for payment:", returnURL)
424
425 stripe.Call("confirmPayment", map[string]interface{}{
426 "elements": elements,
427 "confirmParams": map[string]interface{}{
428 "return_url": returnURL,
429 },
430 }).Call("then", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
431 result := args[0]
432 if result.Get("error").IsUndefined() {
433 log.Println(wasmName+":", "Payment successful:", result)
434 showMessage("Payment successful! Thank you for your order.")
435 } else {
436 log.Println(wasmName+":", "Payment error:", result.Get("error").Get("message").String())
437 showMessage("Payment failed: " + result.Get("error").Get("message").String())
438 }
439
440 showSpinner(false)
441 return nil
442 }))
443}
444
445func showMessage(message string) {
446 messageElement := doc.Call("getElementById", "payment-message")
447 messageElement.Set("innerText", message)
448 messageElement.Set("className", "")
449}
450
451func showSpinner(isLoading bool) {
452 spinner := doc.Call("getElementById", "spinner")
453 buttonText := doc.Call("getElementById", "button-text")
454
455 if isLoading {
456 spinner.Set("className", "")
457 buttonText.Set("className", "hidden")
458 } else {
459 spinner.Set("className", "hidden")
460 buttonText.Set("className", "")
461 }
462}
463
464
465// ===== complete.go =====
466// Package main complete.go
467package main
468
469import (
470 "encoding/json"
471 "log"
472 "syscall/js"
473)
474
475func completeLogic() {
476 initializeStripe()
477}
478
479func initializeStripe() {
480 if stripeValue.IsUndefined() {
481 log.Println(`js.Global().Get("Stripe")`)
482 stripeValue = js.Global().Get("Stripe")
483 if stripeValue.IsUndefined() {
484 log.Println(`Stripe is undefined, attempting to load Stripe.js`)
485
486 doc := js.Global().Get("document")
487 head := doc.Call("querySelector", "head")
488 script := doc.Call("createElement", "script")
489 script.Set("src", "https://js.stripe.com/v3/")
490 script.Set("defer", true)
491
492 done := make(chan bool)
493 script.Call("addEventListener", "load", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
494 log.Println(wasmName+":", "Stripe.js script has been loaded")
495 done <- true
496 return nil
497 }))
498
499 head.Call("appendChild", script)
500
501 <-done
502
503 stripeValue = js.Global().Get("Stripe")
504 if stripeValue.IsUndefined() {
505 log.Println(wasmName+":", "Failed to load Stripe.js")
506 return
507 }
508 }
509 }
510
511 log.Println(wasmName+":", "Stripe.js loaded successfully")
512
513 if stripe.IsUndefined() {
514 log.Println(wasmName+":", "Invoking Stripe")
515 stripe = stripeValue.Invoke(stripePK)
516 if stripe.IsUndefined() {
517 log.Println(wasmName+":", "Failed to invoke Stripe")
518 return
519 }
520 }
521
522 log.Println(wasmName+":", "Stripe initialized")
523 checkStatus()
524}
525
526var (
527 successIcon = `<svg width="16" height="14" viewBox="0 0 16 14" fill="none" xmlns="http://www.w3.org/2000/svg">
528 <path fill-rule="evenodd" clip-rule="evenodd" d="M15.4695 0.232963C15.8241 0.561287 15.8454 1.1149 15.5171 1.46949L6.14206 11.5945C5.97228 11.7778 5.73221 11.8799 5.48237 11.8748C5.23253 11.8698 4.99677 11.7582 4.83452 11.5681L0.459523 6.44311C0.145767 6.07557 0.18937 5.52327 0.556912 5.20951C0.924454 4.89575 1.47676 4.93936 1.79051 5.3069L5.52658 9.68343L14.233 0.280522C14.5613 -0.0740672 15.1149 -0.0953599 15.4695 0.232963Z" fill="white"/>
529 </svg>`
530
531 errorIcon = `<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
532 <path fill-rule="evenodd" clip-rule="evenodd" d="M1.25628 1.25628C1.59799 0.914573 2.15201 0.914573 2.49372 1.25628L8 6.76256L13.5063 1.25628C13.848 0.914573 14.402 0.914573 14.7437 1.25628C15.0854 1.59799 15.0854 2.15201 14.7437 2.49372L9.23744 8L14.7437 13.5063C15.0854 13.848 15.0854 14.402 14.7437 14.7437C14.402 15.0854 13.848 15.0854 13.5063 14.7437L8 9.23744L2.49372 14.7437C2.15201 15.0854 1.59799 15.0854 1.25628 14.7437C0.914573 14.402 0.914573 13.848 1.25628 13.5063L6.76256 8L1.25628 2.49372C0.914573 2.15201 0.914573 1.59799 1.25628 1.25628Z" fill="white"/>
533 </svg>`
534
535 infoIcon = `<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
536 <path fill-rule="evenodd" clip-rule="evenodd" d="M10 1.5H4C2.61929 1.5 1.5 2.61929 1.5 4V10C1.5 11.3807 2.61929 12.5 4 12.5H10C11.3807 12.5 12.5 11.3807 12.5 10V4C12.5 2.61929 11.3807 1.5 10 1.5ZM4 0C1.79086 0 0 1.79086 0 4V10C0 12.2091 1.79086 14 4 14H10C12.2091 14 14 12.2091 14 10V4C14 1.79086 12.2091 0 10 0H4Z" fill="white"/>
537 <path fill-rule="evenodd" clip-rule="evenodd" d="M5.25 7C5.25 6.58579 5.58579 6.25 6 6.25H7.25C7.66421 6.25 8 6.58579 8 7V10.5C8 10.9142 7.66421 11.25 7.25 11.25C6.83579 11.25 6.5 10.9142 6.5 10.5V7.75H6C5.58579 7.75 5.25 7.41421 5.25 7Z" fill="white"/>
538 <path d="M5.75 4C5.75 3.31075 6.31075 2.75 7 2.75C7.68925 2.75 8.25 3.31075 8.25 4C8.25 4.68925 7.68925 5.25 7 5.25C6.31075 5.25 5.75 4.68925 5.75 4Z" fill="white"/>
539 </svg>`
540)
541
542func setErrorState() {
543 js.Global().Get("document").Call("querySelector", "#status-icon").Set("style", map[string]interface{}{"backgroundColor": "#DF1B41"})
544 js.Global().Get("document").Call("querySelector", "#status-icon").Set("innerHTML", errorIcon)
545 js.Global().Get("document").Call("querySelector", "#status-text").Set("textContent", "Something went wrong, please try again.")
546 js.Global().Get("document").Call("querySelector", "#details-table").Call("classList").Call("add", "hidden")
547 js.Global().Get("document").Call("querySelector", "#view-details").Call("classList").Call("add", "hidden")
548}
549
550func checkStatus() {
551 clientSecret := js.Global().Get("URLSearchParams").New(js.Global().Get("window").Get("location").Get("search")).Call("get", "payment_intent_client_secret").String()
552
553 if clientSecret == "" {
554 setErrorState()
555 return
556 }
557
558 if stripe.IsUndefined() {
559 log.Println(wasmName+":", "Stripe is not initialized")
560 setErrorState()
561 return
562 }
563
564 stripe.Call("retrievePaymentIntent", clientSecret).Call("then", js.FuncOf(func(this js.Value, p []js.Value) interface{} {
565 paymentIntent := p[0].Get("paymentIntent")
566 setPaymentDetails(paymentIntent)
567 return nil
568 })).Call("catch", js.FuncOf(func(this js.Value, p []js.Value) interface{} {
569 setErrorState()
570 return nil
571 }))
572}
573
574func getAllLocalStorageData() map[string]interface{} {
575 localStorage := js.Global().Get("localStorage")
576 keys := js.Global().Get("Object").Call("keys", localStorage)
577 data := make(map[string]interface{})
578
579 for i := 0; i < keys.Length(); i++ {
580 key := keys.Index(i).String()
581 value := localStorage.Call("getItem", key).String()
582 var parsedValue interface{}
583 err := json.Unmarshal([]byte(value), &parsedValue)
584 if err != nil {
585 parsedValue = value // If not JSON, store raw value
586 }
587 data[key] = parsedValue
588 }
589 return data
590}
591
592func submitOrder(localStorageData map[string]interface{}, paymentIntentId string) {
593 orderData := map[string]interface{}{
594 "localStorageData": localStorageData,
595 "paymentIntentId": paymentIntentId,
596 }
597
598 body, err := json.Marshal(orderData)
599 if err != nil {
600 log.Println(wasmName+":", "Error marshalling order data:", err)
601 return
602 }
603
604 fetch := js.Global().Get("fetch")
605 if fetch.IsUndefined() {
606 log.Println(wasmName+":", "Fetch API is not available")
607 return
608 }
609
610 options := map[string]interface{}{
611 "method": "POST",
612 "headers": map[string]interface{}{
613 "Content-Type": "application/json",
614 },
615 "body": string(body),
616 }
617
618 fetch.Invoke("/submit-order", js.ValueOf(options)).Call("then", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
619 response := args[0]
620 if !response.Get("ok").Bool() {
621 response.Call("text").Call("then", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
622 errText := args[0].String()
623 log.Println(wasmName+":", "Order submit failed:", errText)
624 js.Global().Call("alert", "Order submission failed:\n"+errText)
625 return nil
626 }))
627 return nil
628 }
629 response.Call("json").Call("then", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
630 data := args[0]
631 log.Println(wasmName+":", "Order submitted successfully:", data)
632 return nil
633 }))
634 return nil
635 }))
636}
637
638func setPaymentDetails(intent js.Value) {
639 var statusText, iconColor, icon string
640 statusText = "Something went wrong, please try again."
641 iconColor = "#DF1B41"
642 icon = errorIcon
643
644 if !intent.IsUndefined() {
645 intentStatus := intent.Get("status").String()
646 intentID := intent.Get("id").String()
647
648 allLocalStorageData := getAllLocalStorageData()
649
650 switch intentStatus {
651 case "succeeded":
652 statusText = "Payment succeeded"
653 iconColor = "#30B130"
654 icon = successIcon
655 if len(allLocalStorageData) > 0 {
656 submitOrder(allLocalStorageData, intentID)
657 } else {
658 log.Println(wasmName+":", "No data found in localStorage; order not submitted.")
659 }
660 case "processing":
661 statusText = "Your payment is processing."
662 iconColor = "#6D6E78"
663 icon = infoIcon
664 if len(allLocalStorageData) > 0 {
665 submitOrder(allLocalStorageData, intentID)
666 } else {
667 log.Println(wasmName+":", "No data found in localStorage; order not submitted.")
668 }
669 case "requires_payment_method":
670 statusText = "Your payment was not successful, please try again."
671 default:
672 statusText = "Unknown payment status."
673 }
674
675 // Update the status icon, text, and links
676 js.Global().Get("document").Call("querySelector", "#status-icon").Set("style", map[string]interface{}{"backgroundColor": iconColor})
677 js.Global().Get("document").Call("querySelector", "#status-icon").Set("innerHTML", icon)
678 js.Global().Get("document").Call("querySelector", "#status-text").Set("textContent", statusText)
679 js.Global().Get("document").Call("querySelector", "#intent-id").Set("textContent", intentID)
680 js.Global().Get("document").Call("querySelector", "#intent-status").Set("textContent", intentStatus)
681 js.Global().Get("document").Call("querySelector", "#view-details").Set("href", "https://dashboard.stripe.com/payments/"+intentID)
682
683 // Update the "Order Details" link with the paymentIntent ID
684 orderDetailsLink := js.Global().Get("document").Call("querySelector", "#order-details-link")
685 orderDetailsLink.Set("href", "/order/"+intentID)
686 orderDetailsLink.Set("onclick", nil) // Allow default behavior (navigation)
687
688 } else {
689 setErrorState()
690 }
691}
692
693
694// ===== main.go =====
695package main
696
697import (
698 "log"
699 "syscall/js"
700)
701
702// set client pk on compile
703var stripePK string
704
705type item struct {
706 ID string `json:"id"`
707 Amount int `json:"amount"`
708 Qty int `json:"quantity"`
709}
710
711var (
712 wasmName string
713 doc = js.Global().Get("document")
714 body = doc.Call("querySelector", "body")
715 bodystring = body.Get("innerHTML").String()
716 cart []item
717)
718
719func main() {
720 ready := make(chan struct{})
721
722 document := js.Global().Get("document")
723 readyState := document.Get("readyState").String()
724 if readyState == "interactive" || readyState == "complete" {
725 log.Println(wasmName+":", "WASM: DOM already fully loaded")
726 close(ready)
727 } else {
728 cb := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
729 log.Println(wasmName+":", "WASM: DOM fully loaded and parsed")
730 close(ready)
731 return nil
732 })
733 defer cb.Release()
734
735 document.Call("addEventListener", "DOMContentLoaded", cb)
736 log.Println(wasmName+":", "WASM: waiting for DOM to load")
737 }
738
739 <-ready
740
741 c := make(chan struct{}, 0)
742 if stripePK == "" {
743 log.Fatal("Stripe PK not found!")
744 }
745 window := js.Global().Get("window")
746 location := window.Get("location")
747 pathname := location.Get("pathname").String()
748
749 switch pathname {
750 case "/complete":
751 completeLogic()
752 default:
753 defaultLogic()
754 }
755 <-c
756}
757
758func defaultLogic() {
759 js.Global().Set("addToCart", js.FuncOf(addUnToCart))
760 js.Global().Set("clearStorage", js.FuncOf(clearAll))
761 js.Global().Set("emptyCart", js.FuncOf(emptyCart))
762 js.Global().Set("updateItemQuantity", js.FuncOf(updateItemQuantity))
763 js.Global().Set("removeFromCart", js.FuncOf(removeFromCart))
764 js.Global().Set("addShippingInfo", js.FuncOf(addShippingInfo))
765 js.Global().Set("goToCheckout", js.FuncOf(goToCheckout))
766 js.Global().Set("cancelCheckout", js.FuncOf(cancelCheckout))
767 js.Global().Set("callUpdateCartDisplay", js.FuncOf(updateCartDisplayWrapper))
768 loadCart()
769 updateCartDisplay()
770}
771
772