(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}