(import-macros {:compile-html HTML} :macros)
(local lib (require :lib))
(local shop (require :shop))
(local dicts (require :dicts))
(local templates (require :templates))
(fn all-products [db filters authenticated?]
(local where-stmts [])
(local where-args [])
(var has-search-query? false)
(when (not authenticated?)
(table.insert where-stmts "products.published = true"))
(when filters.type
(table.insert where-stmts "products.type = ?")
(table.insert where-args filters.type))
(when filters.search
(table.insert where-stmts "products_search MATCH ?")
(table.insert where-args filters.search)
(set has-search-query? true))
(local where
(if (< 0 (# where-stmts))
(.. "WHERE " (table.concat where-stmts " AND\n"))
""))
(local from-sql
(if has-search-query?
"products_search INNER JOIN products ON products_search.name = products.name"
"products"))
(_G.must
(luna.db.query-assoc db
(..
"SELECT products.name,
products.title,
products.published,
products.short_description as \"short-description\",
products.price_per AS \"price-per\",
products.volume,
products.stock,
products.packaging,
products.type,
products.region,
products.image1,
products.image2,
products.image3,
products.image4,
products.image5
FROM " from-sql " "
where
" ORDER BY products.position ASC,
products.creation_time DESC"
(if has-search-query? ", rank" ""))
where-args)))
(fn item-template [product basket]
(local item-url (.. "/shop/" product.name))
(local images [])
(for [i 2 5]
(table.insert images (. product (.. "image" i))))
(HTML
[:section {:class (.. "shop-item"
(if (not product.published)
" shop-item-not-published" ""))}
[:a {:href item-url}
[:div {:class "shop-item-imgs"}
[:img {:class "shop-item-img"
:src (.. "/static/files/" (. product.image1) "-thumbnail.jpg")}]
(table.concat
(let [without-videos
(icollect [_ v (ipairs images)]
(if (lib.ends-with? (_G.must (luna.utf8.lower v)) ".webm")
nil
v))]
(icollect [idx image (ipairs without-videos)]
(HTML
[:img {:class "shop-item-img" :src (.. "/static/files/" image "-thumbnail.jpg")
:loading "lazy"
:style (.. "z-index: " (+ idx 2) ";"
"width: calc(100% / " (# without-videos) ");"
"left: calc(100% / " (# without-videos) " * " (- idx 1) ")")}]))))]]
[:a {:href item-url}
[:h3 {:class "shop-item-title"} product.title]]
[:div {:class "shop-item-price"}
(templates.add-to-basket-form product basket "" "/shop")]
(templates.product-overview product "mb-0-25 font-size-0-875")
[:div {} product.short-description]]))
(fn content [db products filters basket authenticated?]
[(HTML
[:aside {}
(templates.header "/shop" authenticated?)
(if (< 0 (# basket)) (templates.basket basket "/shop") "")
[:section {}
[:h2 {} "Условия"]
[:p {} ""]]])
(HTML
[:div {:class "content"}
[:div {:class "back"} [:a {:href "/"} "⟵ Обратно на главную"]]
[:h2 {:class "product-page-title"} "Магазин"]
(if authenticated?
(HTML
[:div {:class "mb-1" :style "margin-top: -0.5rem"}
[:a {:style "white-space: nowrap"
:href (.. "/shop/add")} "+ Добавить"]
[:a {:style "white-space: nowrap; margin-left: 1rem;"
:href (.. "/shop/order/list")} "☰ Список заказов"]])
"")
[:form {:class "d-flex gap-0-5 mb-1"}
[:input {:name "search" :type "search"
:placeholder "Поиск" :value (or filters.search "")}]
[:select {:name "type"}
[:option {:value ""} "Все товары"]
(table.concat
(icollect [_ v (ipairs dicts.product-type)]
(HTML [:option (fn [] {:value v.value
:selected (= filters.type v.value)})
v.label])))]
[:button {:type "submit"} "Применить"]]
[:div {:class "shop-items"}
(if (< 0 (# products))
(table.concat
(icollect [_ v (ipairs products)]
(item-template v basket)))
(HTML [:em {} "Пока что здесь ничего нет!"]))]])])
(fn render [request db authenticated?]
(let [order-id (shop.order-id request)
basket (if order-id (shop.basket db order-id) [])
type (if (and request.query.type
(not (lib.empty? (. request.query.type 1))))
(. request.query.type 1)
nil)
search (if (and request.query.search
(not (lib.empty? (. request.query.search 1))))
(. request.query.search 1)
nil)
filters { : type : search }
products (all-products db filters authenticated?)]
(values 200 {} (templates.base
(content db products filters basket authenticated?)))))
{: render}