aboutsummaryrefslogtreecommitdiff
path: root/frontend/src/Main.elm
diff options
context:
space:
mode:
Diffstat (limited to 'frontend/src/Main.elm')
-rw-r--r--frontend/src/Main.elm339
1 files changed, 339 insertions, 0 deletions
diff --git a/frontend/src/Main.elm b/frontend/src/Main.elm
new file mode 100644
index 0000000..bf1583c
--- /dev/null
+++ b/frontend/src/Main.elm
@@ -0,0 +1,339 @@
1module Main exposing (Model, Msg(..), init, main, subscriptions, update, view, viewLink)
2
3import Browser
4import Browser.Navigation as Nav
5import Cart
6import Catalog
7import Html exposing (..)
8import Html.Attributes exposing (..)
9import Html.Events exposing (..)
10import Http
11import Json.Encode as Encode
12import Login
13import Product
14import Signup
15import Url
16import Url.Parser as P exposing ((</>), Parser, int, oneOf, s, string)
17
18
19
20-- MAIN
21
22
23main : Program () Model Msg
24main =
25 Browser.application
26 { init = init
27 , view = view
28 , update = update
29 , subscriptions = subscriptions
30 , onUrlChange = UrlChanged
31 , onUrlRequest = LinkClicked
32 }
33
34
35
36-- MODEL
37
38
39type Route
40 = LoginPage
41 | SignupPage
42 | HomePage
43 | CatalogPage
44 | CartPage
45 | ProductPage Int
46 | NotFoundPage
47
48
49parseRoute : Parser (Route -> a) a
50parseRoute =
51 oneOf
52 [ P.map LoginPage (P.s "login")
53 , P.map HomePage P.top
54 , P.map CatalogPage (P.s "catalog")
55 , P.map CartPage (P.s "cart")
56 , P.map SignupPage (P.s "signup")
57 , P.map ProductPage (P.s "product" </> P.int)
58
59 --, P.map ProductPage (P.s "product" </> int)
60 ]
61
62
63type alias Model =
64 { key : Nav.Key
65 , url : Url.Url
66 , location : Route
67 , loginModel : Login.Model
68 , catalogModel : Catalog.Model
69 , productModel : Product.Model
70 , signupModel : Signup.Model
71 , cartModel : Cart.Model
72 }
73
74
75init : () -> Url.Url -> Nav.Key -> ( Model, Cmd Msg )
76init flags url key =
77 let
78 start =
79 HomePage
80
81 login =
82 Login.init
83
84 catalog =
85 Catalog.init
86
87 product =
88 Product.init
89
90 signup =
91 Signup.init
92
93 cart =
94 Cart.init
95 in
96 ( Model key url start login catalog product signup cart, Cmd.none )
97
98
99
100-- UPDATE
101
102
103type Msg
104 = LinkClicked Browser.UrlRequest
105 | UrlChanged Url.Url
106 | LoginMessage Login.Msg
107 | CatalogMessage Catalog.Msg
108 | ProductMessage Product.Msg
109 | SignupMessage Signup.Msg
110 | CartMessage Cart.Msg
111 | LogoutPressed
112 | LogoutSuccess (Result Http.Error ())
113
114
115update : Msg -> Model -> ( Model, Cmd Msg )
116update msg model =
117 case msg of
118 LinkClicked urlRequest ->
119 case urlRequest of
120 Browser.Internal url ->
121 ( model, Nav.pushUrl model.key (Url.toString url) )
122
123 Browser.External href ->
124 ( model, Nav.load href )
125
126 LogoutPressed ->
127 ( model, tryLogout )
128
129 LogoutSuccess _ ->
130 ( model, Nav.replaceUrl model.key "/login" )
131
132 UrlChanged url ->
133 let
134 parsedUrl =
135 P.parse parseRoute url
136 in
137 case parsedUrl of
138 Just CatalogPage ->
139 ( { model | location = CatalogPage }, Cmd.map CatalogMessage Catalog.fetchProducts )
140
141 Just (ProductPage id) ->
142 let
143 cmds =
144 List.map (Cmd.map ProductMessage)
145 [ Product.fetchListing id
146 , Product.fetchRatings id
147 ]
148 in
149 ( { model | location = ProductPage id }, Cmd.batch cmds )
150
151 Just CartPage ->
152 let
153 cmd =
154 Cmd.map CartMessage Cart.fetchCartItems
155 in
156 ( { model | location = CartPage }, cmd )
157
158 Just p ->
159 ( { model | location = p }, Cmd.none )
160
161 Nothing ->
162 ( { model | location = NotFoundPage }, Cmd.none )
163
164 LoginMessage lm ->
165 let
166 ( lmn, cmd ) =
167 Login.update lm model.loginModel
168
169 redir =
170 case lmn.loginStatus of
171 Login.LoggedIn ->
172 Nav.replaceUrl model.key "/catalog"
173
174 _ ->
175 Cmd.none
176 in
177 ( { model | loginModel = lmn }, Cmd.batch [ Cmd.map LoginMessage cmd, redir ] )
178
179 SignupMessage sm ->
180 let
181 ( smn, cmd ) =
182 Signup.update sm model.signupModel
183
184 redir =
185 case smn.status of
186 Signup.CreatedSuccessfully ->
187 Nav.replaceUrl model.key "/login"
188
189 _ ->
190 Cmd.none
191 in
192 ( { model | signupModel = smn }, Cmd.batch [ Cmd.map SignupMessage cmd, redir ] )
193
194 CatalogMessage cm ->
195 let
196 ( cmn, cmd ) =
197 Catalog.update cm model.catalogModel
198 in
199 ( { model | catalogModel = cmn }, Cmd.map CatalogMessage cmd )
200
201 CartMessage cm ->
202 let
203 ( cmn, cmd ) =
204 Cart.update cm model.cartModel
205 in
206 ( { model | cartModel = cmn }, Cmd.map CartMessage cmd )
207
208 ProductMessage pm ->
209 let
210 ( pmn, cmd ) =
211 Product.update pm model.productModel
212
213 redir =
214 case pm of
215 Product.AddToCartSuccess _ ->
216 Nav.replaceUrl model.key "/cart"
217
218 _ ->
219 Cmd.none
220 in
221 ( { model | productModel = pmn }, Cmd.batch [ Cmd.map ProductMessage cmd, redir ] )
222
223
224tryLogout : Cmd Msg
225tryLogout =
226 Http.riskyRequest
227 { method = "POST"
228 , headers = []
229 , url = "http://127.0.0.1:7878/user/logout"
230 , body = Http.emptyBody
231 , expect = Http.expectWhatever LogoutSuccess
232 , timeout = Nothing
233 , tracker = Nothing
234 }
235
236
237
238-- SUBSCRIPTIONS
239
240
241subscriptions : Model -> Sub Msg
242subscriptions _ =
243 Sub.none
244
245
246
247-- VIEW
248
249
250view : Model -> Browser.Document Msg
251view model =
252 case model.location of
253 LoginPage ->
254 { title = "Login"
255 , body = [ Html.map LoginMessage (Login.view model.loginModel) ]
256 }
257
258 SignupPage ->
259 { title = "Signup"
260 , body = [ Html.map SignupMessage (Signup.view model.signupModel) ]
261 }
262
263 HomePage ->
264 { title = "URL Interceptor"
265 , body =
266 [ text "The current URL is: "
267 , b [] [ text (Url.toString model.url) ]
268 , ul []
269 [ viewLink "/login"
270 , viewLink "/catalog"
271 , viewLink "/cart"
272 , viewLink "/signup"
273 ]
274 ]
275 }
276
277 NotFoundPage ->
278 { title = "404 - Not Found"
279 , body =
280 [ text "404 - Not Found"
281 , a [ href "/" ] [ text "Go back >" ]
282 ]
283 }
284
285 CatalogPage ->
286 { title = "Catalog"
287 , body = pageWrap model (Html.map CatalogMessage (Catalog.view model.catalogModel))
288 }
289
290 CartPage ->
291 { title = "Cart"
292 , body = pageWrap model (Html.map CartMessage (Cart.view model.cartModel))
293 }
294
295 ProductPage item ->
296 { title = "Product " ++ String.fromInt item
297 , body = pageWrap model (Html.map ProductMessage (Product.view model.productModel))
298 }
299
300
301viewHeader : Model -> Html Msg
302viewHeader model =
303 let
304 links =
305 [ ( "Home", "/" )
306 , ( "Catalog", "/catalog" )
307 , ( "Cart", "/cart" )
308 ]
309 in
310 div []
311 [ List.map
312 (\( name, loc ) ->
313 li []
314 [ a [ href loc ] [ text name ]
315 ]
316 )
317 links
318 ++ [ if model.loginModel.loginStatus /= Login.LoggedIn then
319 li [] [ a [ href "/login" ] [ text "Login" ] ]
320
321 else
322 button [ onClick LogoutPressed ] [ text "Logout" ]
323 ]
324 |> ul []
325 ]
326
327
328pageWrap : Model -> Html Msg -> List (Html Msg)
329pageWrap model page =
330 [ div []
331 [ viewHeader model
332 , page
333 ]
334 ]
335
336
337viewLink : String -> Html msg
338viewLink path =
339 li [] [ a [ href path ] [ text path ] ]