summaryrefslogtreecommitdiff
path: root/pages/shop/_product
diff options
context:
space:
mode:
authorunwox <me@unwox.com>2025-08-31 17:51:57 +0600
committerunwox <me@unwox.com>2025-09-04 20:14:11 +0600
commit66c51b0e714fa8a1c80784108191270babc8525e (patch)
tree0640549f522092096d83c78b9be9b1fa4a03929e /pages/shop/_product
parentd8039a77d582f696ab98b2a6d02ce924fbacfa41 (diff)
implement shop
Diffstat (limited to 'pages/shop/_product')
-rw-r--r--pages/shop/_product/edit.fnl75
-rw-r--r--pages/shop/_product/index.fnl83
2 files changed, 158 insertions, 0 deletions
diff --git a/pages/shop/_product/edit.fnl b/pages/shop/_product/edit.fnl
new file mode 100644
index 0000000..9465d94
--- /dev/null
+++ b/pages/shop/_product/edit.fnl
@@ -0,0 +1,75 @@
+(import-macros {:compile-html <>} :macros)
+(local templates (require :templates))
+(local {: product-form} (require :pages.shop.add))
+(local forms (require :forms))
+(local lib (require :lib))
+
+(fn find-product [db name]
+ (.
+ (_G.must
+ (luna.db.query-assoc
+ db
+ "SELECT products.published,
+ products.name,
+ products.title,
+ products.position,
+ products.short_description,
+ products.stock,
+ products.type,
+ products.packaging,
+ products.description,
+ products.price_per,
+ products.stock,
+ products.vendor,
+ products.vendor_article,
+ products.vendor_description,
+ products.vendor_price_per,
+ products.vendor_product_link,
+ products.image1,
+ products.image2,
+ products.image3,
+ products.image4,
+ products.image5
+ FROM products
+ WHERE products.name = ?"
+ [name]))
+ 1))
+
+(fn update-product [tx form data where]
+ (let [sql-and-args (forms.form-update-sql-statement "products" form data {} where)]
+ (if sql-and-args
+ (_G.must (luna.db.exec-tx tx (table.unpack sql-and-args)))
+ (error "empty data for insert SQL-statement"))))
+
+(fn content [form data errors authenticated?]
+ [(<>
+ [:div {:class "side"}
+ (templates.header "/shop" authenticated?)])
+ (<>
+ [:div {:class "content"}
+ [:div {:class "mb-1"}
+ [:a {:href (.. "/shop/" data.name)} "⟵ Обратно к товару"]]
+ [:h2 {} "Редактировать товар"]
+ (forms.render-form form data errors)])])
+
+(fn render [request db authenticated?]
+ (if (not authenticated?)
+ (values 302 {:Location "/shop"} "")
+ (if request.form
+ (let [data (forms.convert-values-from-html product-form request.form db)
+ errors (forms.validate-form product-form data)
+ has-errors? (not (lib.empty-table? errors))]
+ (if has-errors?
+ (values 400 {} (templates.base (content product-form data errors
+ authenticated?)))
+ (do
+ (lib.with-tx db
+ (fn [tx] (update-product tx product-form data
+ {:name request.params._product})))
+ (values 302 {:Location (.. "/shop/" data.name)} ""))))
+ (values 200 {}
+ (templates.base
+ (content product-form (find-product db request.params._product) {}
+ authenticated?))))))
+
+{: render }
diff --git a/pages/shop/_product/index.fnl b/pages/shop/_product/index.fnl
new file mode 100644
index 0000000..722c952
--- /dev/null
+++ b/pages/shop/_product/index.fnl
@@ -0,0 +1,83 @@
+(import-macros {:compile-html <>} :macros)
+(local templates (require :templates))
+(local dicts (require :dicts))
+(local lib (require :lib))
+
+(fn text->html [text]
+ (assert (= (type text) "string"))
+ (var result "")
+ (var from 1)
+ (var to (text:find "\n%s*\n%s*" from))
+ (while to
+ (set result (.. result "<p>" (text:sub from (- to 1)) "</p>\n"))
+ (set from (+ to 2))
+ (set to (text:find "\n%s*\n%s*" from)))
+ (.. result "<p>" (text:sub from) "</p>"))
+
+(fn find-product [db name]
+ (.
+ (_G.must
+ (luna.db.query-assoc
+ db
+ "SELECT products.name,
+ products.title,
+ products.description,
+ products.price_per AS \"price-per\",
+ products.type,
+ products.stock,
+ products.published,
+ products.image1,
+ products.image2,
+ products.image3,
+ products.image4,
+ products.image5
+ FROM products
+ WHERE products.name = ?"
+ [name]))
+ 1))
+
+(fn content [product authenticated?]
+ (local images [])
+ (for [i 1 5]
+ (table.insert images (. product (.. "image" i))))
+
+ [(<>
+ [:div {:class "side"}
+ (templates.header "/shop" authenticated?)])
+ (<>
+ [:div {:class "content"}
+ [:div {:class "mb-1"} [:a {:href "/shop"} "⟵ Обратно к списку"]]
+
+ (let [link (.. "/static/files/" product.image1)]
+ (<> [:a {:href link :target "_blank"}
+ [:img {:class "product-page-img-mobile mb-1-5"
+ :src (.. link "-thumbnail.jpg")}]]))
+ [:div {:class "product-page-layout"}
+ [:div {}
+ [:h2 {:class "product-page-title mb-1"} product.title]
+ [:section {:class "mb-2"}
+ (if authenticated?
+ (<> [:div {:class "mb-0-5"}
+ [:a {:href (.. "/shop/" product.name "/edit")}
+ "✎ Редактировать"]])
+ "")
+ [:div {:class "mb-0-5" :style "font-style: italic;"}
+ (or (dicts.label dicts.tea-type product.type) product.type) ", "
+ [:strong {} (* 50 product.price-per) "₽ за 50 грамм "]
+ (.. "(" product.price-per "₽ за 1 грамм)")]]
+ [:div {:class "mb-2"} "~~~"]
+ [:NO-ESCAPE (text->html product.description)]]
+ [:div {:class "product-page-imgs"}
+ (table.concat
+ (icollect [idx image (ipairs images)]
+ (let [link (.. "/static/files/" image)]
+ (<> [:a {:href link :target "_blank"}
+ [:img {:class "product-page-img" :src (.. link "-thumbnail.jpg")}]]))))]]])])
+
+(fn render [request db authenticated?]
+ (let [product (find-product db request.params._product)]
+ (if (and product (or product.published authenticated?))
+ (values 200 {} (templates.base (content product authenticated?)))
+ (values 404 {} "not found"))))
+
+{: render}