1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
|
(import-macros {:compile-html HTML} :macros)
(local templates (require :templates))
(local lib (require :lib))
(local shop (require :shop))
(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.short_description AS \"short-description\",
products.description,
products.price_per AS \"price-per\",
products.type,
products.region,
products.stock,
products.volume,
products.packaging,
products.published,
products.year,
products.image1,
products.image2,
products.image3,
products.image4,
products.image5
FROM products
WHERE products.name = ?"
[name]))
1))
(fn content [product basket agreed-to-cookies? authenticated?]
(local redirect-url (.. "/shop/" product.name))
(local images [])
(for [i 1 5]
(table.insert images (. product (.. "image" i))))
[(HTML
[:aside {}
(templates.header "/shop" authenticated?)
(if (< 0 (# basket)) (templates.basket basket redirect-url) "")
(templates.conditions-block)
(templates.address-block)
(templates.contact-block)])
(HTML
[:div {:class "content"}
(if (not agreed-to-cookies?) (templates.cookies-agreement) "")
;; this method of going back to the list requires JS and is bug prone but
;; at the same time it's the simplest one. doing the same thing without
;; JS would require storing "back URL" in query parameter (which will make
;; URLs ugly and also hurt SEO) or in a cookie (which is brittle)
;; TODO: also add <noscript> version of this link
[:div {:class "back"} [:a {:href "#"
:onclick "history.length > 1
? history.back()
: location.assign('/shop')"}
"⟵ Обратно к списку"]]
[:div {:class "product-page-layout"}
[:section {}
[:div {:id "content"} ""]
[:h2 {:class "product-page-title"} product.title]
(if authenticated?
(HTML
[:div {:class "mb-1" :style "margin-top: -0.5rem;"}
[:a {:href (.. "/shop/" product.name "/edit")}
"% Редактировать"]])
"")
(templates.product-overview product "mb-0-5")
(templates.add-to-basket-form product basket "mb-1-5" redirect-url)
[:div {:class "mb-1"} product.short-description]
(let [link (.. "/static/files/" product.image1)]
(HTML [:a {:href link :target "_blank"}
[:img {:class "product-page-img-mobile mb-1"
:src (.. link "-thumbnail.jpg")}]]))
(if (not (lib.empty? product.description))
(HTML [:div {:class "product-page-delimiter mb-1"} "***"])
"")
(if (not (lib.empty? product.description))
(HTML [:div {} [:NO-ESCAPE (text->html product.description)]])
"")]
[:div {:class "product-page-imgs"}
(table.concat
(icollect [idx image (ipairs images)]
(let [link (.. "/static/files/" image)
video? (lib.ends-with? (_G.must (luna.utf8.lower image)) ".webm")]
(HTML
[:a {:href link :target "_blank"}
(if video?
(HTML [:video {:class "product-page-img" :autoplay true :loop true
:muted true}
[:source {:src (.. "/static/files/" image) :type "video/webm"}]])
(HTML [:img {:class "product-page-img" :src (.. link "-thumbnail.jpg")}]))]))))]]])])
(fn render [request db authenticated?]
(let [agreed-to-cookies? request.cookies.agreed-to-cookies
product (find-product db request.params._product)
order-id request.cookies.order
basket (if order-id (shop.basket db order-id) [])]
(if (and product (or product.published authenticated?))
(values 200 {}
(templates.base
(content product basket agreed-to-cookies? authenticated?)
product.title
(.. "Купить " product.title " в Омске: " product.short-description)))
(values 404 {} "not found"))))
{: render}
|