diff --git a/features/fakepay/api.go b/features/fakepay/api.go new file mode 100644 index 0000000..070e133 --- /dev/null +++ b/features/fakepay/api.go @@ -0,0 +1,13 @@ +package features_fakepay + +import ( + "github.com/gofiber/fiber/v2" +) + +func PostApiPay(c *fiber.Ctx) error { + return c.Redirect("/fakepay/complete") +} + +func SetupApi(app *fiber.App) { + app.Post("/api/fakepay/pay", PostApiPay) +} diff --git a/features/fakepay/db.go b/features/fakepay/db.go new file mode 100644 index 0000000..3b488aa --- /dev/null +++ b/features/fakepay/db.go @@ -0,0 +1,9 @@ +package features_fakepay + +import ( +// "MY/webapp/data" +// _ "github.com/mattn/go-sqlite3" +// sq "github.com/Masterminds/squirrel" +) + + diff --git a/features/fakepay/init.go b/features/fakepay/init.go new file mode 100644 index 0000000..c96dea7 --- /dev/null +++ b/features/fakepay/init.go @@ -0,0 +1,10 @@ +package features_fakepay + +import ( + "github.com/gofiber/fiber/v2" +) + +func Setup(app *fiber.App) { + SetupApi(app) + SetupViews(app) +} diff --git a/features/fakepay/views.go b/features/fakepay/views.go new file mode 100644 index 0000000..4614a2a --- /dev/null +++ b/features/fakepay/views.go @@ -0,0 +1,11 @@ +package features_fakepay + +import ( + "github.com/gofiber/fiber/v2" + . "MY/webapp/common" +) + +func SetupViews(app *fiber.App) { + err := ConfigViews(app, "views/fakepay") + if err != nil { panic(err) } +} diff --git a/features/init.go b/features/init.go index 08322d3..a283162 100644 --- a/features/init.go +++ b/features/init.go @@ -5,10 +5,12 @@ import ( "MY/webapp/features/email" "MY/webapp/features/paypal" "MY/webapp/features/shopping" + "MY/webapp/features/fakepay" ) func Setup(app *fiber.App) { features_email.Setup(app) features_paypal.Setup(app) features_shopping.Setup(app) + features_fakepay.Setup(app) } diff --git a/features/shopping/api.go b/features/shopping/api.go index fed790a..299de2b 100644 --- a/features/shopping/api.go +++ b/features/shopping/api.go @@ -16,13 +16,16 @@ func GetApiProducts(c *fiber.Ctx) error { return data.SelectJson[data.Product](c, err, sql, args...) } - func GetApiCart(c *fiber.Ctx) error { - return c.JSON(fiber.Map{}) } +func GetApiCartRemove(c *fiber.Ctx) error { + return c.Redirect("/shopping/checkout") +} + func SetupApi(app *fiber.App) { app.Get("/api/shopping/products", GetApiProducts) app.Get("/api/shopping/cart", GetApiCart) + app.Get("/api/shopping/cart/remove/:item_id", GetApiCartRemove) } diff --git a/static/input_style.css b/static/input_style.css index 71aa6c0..1ee8c62 100644 --- a/static/input_style.css +++ b/static/input_style.css @@ -237,6 +237,14 @@ hr { visibility: hidden; } +form { + @apply flex flex-col; +} + +form > button-group { + @apply flex text-gray-50 p-3 justify-stretch *:flex-1 gap-2; +} + select { @apply text-red-50 bg-gray-800 rounded-lg border-1 border-gray-600 p-1; } diff --git a/static/js/code.js b/static/js/code.js index f6ccf53..0d9755b 100644 --- a/static/js/code.js +++ b/static/js/code.js @@ -8,6 +8,7 @@ class PaginateTable { } async contents() { + console.log("CONTENTS RUN"); if(this.page < 0) this.page = 0; let url = `${this.url}?page=${this.page}`; @@ -45,6 +46,8 @@ class ForeverScroll { const items = await resp.json(); if(items) this.items = items; + + return items; } async load() { diff --git a/static/js/jzed.js b/static/js/jzed.js new file mode 100644 index 0000000..9ace06c --- /dev/null +++ b/static/js/jzed.js @@ -0,0 +1,233 @@ +const $boot = (cb) => { + document.addEventListener("DOMContentLoaded", cb); +} + +const $sanitize = (badHTML) => { + // this Option hack courtesy of stackoverflow + return new Option(badHTML).innerHTML; +} + +const validate_sanitized = (sanitized) => { + const check = JSON.stringify(sanitized); + console.assert(!check.includes("<"), + "YOU BEEN HACKED! Send Zed this:", sanitized); +} + +const $sanitize_data = (data) => { + const sanitized = $sanitize(JSON.stringify(data)); + validate_sanitized(sanitized); + return JSON.parse(sanitized); +} + +const $render = (template, data) => { + const sanitized = $sanitize_data(data); + + const args = Object.keys(sanitized); + const values = Object.values(sanitized) + + const render_func = new Function(...args, + `return \`${template.innerHTML}\``) + + const text = render_func(...values); + + return $html(text); +} + +const $render_data = (template_id, target_id, data) => { + const target = $id(target_id); + const template = $id(template_id); + let new_data = []; + + if(Array.isArray(data)) { + new_data = data.map((item, i) => { + return $render(template, {i, item}); + }); + } else if(data instanceof Object) { + console.log("object rendering", data); + new_data.push($render(template, data)); + } else { + console.error("$render only works with {} or [] data", data); + new_data.push($html("ERROR LOOK IN CONSOLE")); + } + + $replace_with(target, new_data); +} + +const $get = (name, inChildren) => { + if(inChildren) { + return inChildren.querySelector(name); + } else { + return document.querySelector(name); + } +} + +const $all = (name, inChildren) => { + if(inChildren) { + return inChildren.querySelectorAll(name); + } else { + return document.querySelectorAll(name); + } +} + +const $id = (name, inChildren) => { + if(inChildren) { + return inChildren.children.namedItem(name); + } else { + return document.getElementById(name); + } +} + +const $class = (name) => { + return document.getElementsByClassName(name); +} + +const $name = (name) => { + return document.getElementsByTagName(name); +} + +const $filter = (nodes, fn) => { + return Array.prototype.filter.call(nodes, fn); +} + +const $next = (node) => { + return node.nextElementSibling; +} + +const $previous = (node) => { + return node.previousElementSibling; +} + +const $siblings = (node) => { + return $filter(node.parentNode.children, + child => { return child !== node; }); +} + +const $style_toggle = (node, className) => { + node.classList.toggle(className); +} + +const $style_add = (node, className) => { + node.classList.add(className); +} + +const $style_del = (node, className) => { + node.classList.remove(className); +} + +const $style_of = (node, ruleName) => { + return getComputedStyle(node)[ruleName] +} + +const $new = (tag, id, html) => { + let new_tag = document.createElement(tag); + new_tag.id = id; + new_tag.innerHTML = html; + return new_tag.cloneNode(true); +} + +const $append = (parent, child) => { + parent.appendChild(child); +} + +const $prepend = (parent, node) => { + parent.insertBefore(node, parent.firstChild); +} + +const $remove = (parent, child) => { + parent.removeChild(child); +} + +const $clone = (node) => { + return node.cloneNode(true); +} + +const $contains = (node, child) => { + return node !== child && node.contains(child); +} + +const $has = (node, selector) => { + return node.querySelector(selector) !== null; +} + +const $empty = (node) => { + return node.innerHTML == ''; +} + +const $attribute_of = (node, name) => { + return node.getAttribute(name); +} + +const $attribute = (node, name, value) => { + return node.setAttribute(name, value); +} + +const $contents_of = (node) => { + return node.innerHTML; +} + +const $contents = (node, newhtml) => { + node.innerHTML = newhtml; +} + +const $has_class = (node, className) => { + return node.classList.contains(className); +} + +const $outer_html = (node) => { + return node.outerHTML; +} + +const $replace_with = (node, newNodes) => { + node.replaceChildren(...newNodes); +} + +const $matches = (node, selector) => { + return node.matches(selector); +} + +const $parent = (node) => { + return node.parentNode; +} + +const $text_of = (node) => { + return node.textContent; +} + +const $text = (node, newtext) => { + node.textContent = newtext; +} + +const $off = (node, eventName, eventHandler) => { + node.removeEventListener(eventName, eventHandler); +} + +const $on = (node, eventName, eventHandler) => { + node.addEventListener(eventName, eventHandler); +} + +const $now = () => { + return Date.now(); +} + +const $html = (htmlString) => { + const temp = document.createElement('template'); + temp.innerHTML = htmlString; + return temp.content; +} + +const $observe = (node_id, cb) => { + const options = { + root: document, + rootMargin: "0px", + scrollMargin: "0px", + threshold: 1.0, + delay: 200, + }; + + const callback = (entries, observer) => { + cb(); + } + + const observer = new IntersectionObserver(callback, options); + observer.observe($id(node_id)); +} diff --git a/tests/fakepay/example_test.go b/tests/fakepay/example_test.go new file mode 100644 index 0000000..f7318b7 --- /dev/null +++ b/tests/fakepay/example_test.go @@ -0,0 +1,14 @@ +package tests + +import ( + "testing" + "github.com/stretchr/testify/require" +) + +func TestLogin(t *testing.T) { + assert.Equal(true, false) +} + +func TestMain(m *testing.M) { + m.Run() +} diff --git a/views/fakepay/complete.html b/views/fakepay/complete.html new file mode 100644 index 0000000..9a7da7f --- /dev/null +++ b/views/fakepay/complete.html @@ -0,0 +1,6 @@ +

Thank You!

+ +

Your payment has been accepted and you should receive an email with your receipt.

+ +

Log In To Your Account

+ diff --git a/views/fakepay/index.html b/views/fakepay/index.html new file mode 100644 index 0000000..c1bde3d --- /dev/null +++ b/views/fakepay/index.html @@ -0,0 +1,29 @@ + + + +

FakePay

+
+ +
+ + + + + + + + + + + + + + + + + + + +
+
+
diff --git a/views/layouts/main.html b/views/layouts/main.html index 76e0231..1ac27fa 100644 --- a/views/layouts/main.html +++ b/views/layouts/main.html @@ -13,6 +13,7 @@ + Go Web Dev Starter Kit diff --git a/views/shopping/checkout.html b/views/shopping/checkout.html index 416cd19..b542a98 100644 --- a/views/shopping/checkout.html +++ b/views/shopping/checkout.html @@ -5,7 +5,7 @@
Price: $100.00
- +
@@ -16,6 +16,5 @@ - - + diff --git a/views/shopping/index.html b/views/shopping/index.html index 23bdb5f..7f47489 100644 --- a/views/shopping/index.html +++ b/views/shopping/index.html @@ -1,24 +1,104 @@ + +

Products

-

I have these products for you:

- - - + + + + + +
+