aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAkshay <[email protected]>2020-12-24 16:33:04 +0000
committerAkshay <[email protected]>2020-12-24 16:33:04 +0000
commit7c6006e1abc6094b5922ab69ccfa5449b8dbbc99 (patch)
tree75107603b63203fcd41de43fbfabf8d606be9747
parentb00a1e55ed5fa01cb881c387c8e112249070d8ae (diff)
add filters to catalog
-rw-r--r--frontend/src/Catalog.elm132
-rw-r--r--frontend/src/Utils.elm15
2 files changed, 139 insertions, 8 deletions
diff --git a/frontend/src/Catalog.elm b/frontend/src/Catalog.elm
index 80e5e38..6882c73 100644
--- a/frontend/src/Catalog.elm
+++ b/frontend/src/Catalog.elm
@@ -8,8 +8,15 @@ import Html.Events exposing (..)
8import Http 8import Http
9import Json.Decode as D 9import Json.Decode as D
10import Json.Encode as Encode 10import Json.Encode as Encode
11import Tuple exposing (..)
11import Url 12import Url
12import Url.Parser as P exposing ((</>), Parser, int, oneOf, s, string) 13import Url.Parser as P exposing ((</>), Parser, int, oneOf, s, string)
14import Utils exposing (..)
15
16
17type Order
18 = Rating
19 | Price
13 20
14 21
15type alias Product = 22type alias Product =
@@ -18,12 +25,25 @@ type alias Product =
18 , kind : Maybe String 25 , kind : Maybe String
19 , price : Float 26 , price : Float
20 , description : Maybe String 27 , description : Maybe String
28 , averageRating : Maybe Float
21 } 29 }
22 30
23 31
32type alias Filters =
33 { price : ( Float, Float )
34 , rating : ( Float, Float )
35 }
36
37
38defaultFilters : Filters
39defaultFilters =
40 Filters ( -1, 10000 ) ( 0, 5 )
41
42
24type alias Model = 43type alias Model =
25 { pageStatus : Status 44 { pageStatus : Status
26 , products : List Product 45 , products : List Product
46 , filters : Filters
27 } 47 }
28 48
29 49
@@ -36,11 +56,15 @@ type Status
36type Msg 56type Msg
37 = ProductsLoaded (Result Http.Error (List Product)) 57 = ProductsLoaded (Result Http.Error (List Product))
38 | FetchProducts 58 | FetchProducts
59 | ChangePriceLower Float
60 | ChangePriceUpper Float
61 | ChangeRatingLower Float
62 | ChangeRatingUpper Float
39 63
40 64
41init : Model 65init : Model
42init = 66init =
43 Model NotLoaded [] 67 Model NotLoaded [] defaultFilters
44 68
45 69
46update : Msg -> Model -> ( Model, Cmd Msg ) 70update : Msg -> Model -> ( Model, Cmd Msg )
@@ -61,15 +85,56 @@ update msg model =
61 FetchProducts -> 85 FetchProducts ->
62 ( { model | pageStatus = Loading }, fetchProducts ) 86 ( { model | pageStatus = Loading }, fetchProducts )
63 87
88 ChangePriceLower v ->
89 let
90 fs =
91 model.filters
92
93 nfs =
94 { fs | price = mapFirst (always v) fs.price }
95 in
96 ( { model | filters = nfs }, Cmd.none )
97
98 ChangePriceUpper v ->
99 let
100 fs =
101 model.filters
102
103 nfs =
104 { fs | price = mapSecond (always v) fs.price }
105 in
106 ( { model | filters = nfs }, Cmd.none )
107
108 ChangeRatingLower v ->
109 let
110 fs =
111 model.filters
112
113 nfs =
114 { fs | rating = mapFirst (always v) fs.rating }
115 in
116 ( { model | filters = nfs }, Cmd.none )
117
118 ChangeRatingUpper v ->
119 let
120 fs =
121 model.filters
122
123 nfs =
124 { fs | rating = mapSecond (always v) fs.rating }
125 in
126 ( { model | filters = nfs }, Cmd.none )
127
64 128
65decodeProduct : D.Decoder Product 129decodeProduct : D.Decoder Product
66decodeProduct = 130decodeProduct =
67 D.map5 Product 131 D.map6 Product
68 (D.field "id" D.int) 132 (D.field "id" D.int)
69 (D.field "name" D.string) 133 (D.field "name" D.string)
70 (D.field "kind" (D.nullable D.string)) 134 (D.field "kind" (D.nullable D.string))
71 (D.field "price" D.float) 135 (D.field "price" D.float)
72 (D.field "description" (D.nullable D.string)) 136 (D.field "description" (D.nullable D.string))
137 (D.field "average_rating" (D.nullable D.float))
73 138
74 139
75decodeResponse : D.Decoder (List Product) 140decodeResponse : D.Decoder (List Product)
@@ -105,14 +170,63 @@ viewStatus s =
105viewProduct : Product -> Html Msg 170viewProduct : Product -> Html Msg
106viewProduct p = 171viewProduct p =
107 div [] 172 div []
108 [ text p.name 173 [ div [] [ text p.name ]
109 , text <| Maybe.withDefault "" p.kind 174 , div [] [ text <| Maybe.withDefault "" p.kind ]
110 , text <| Maybe.withDefault "" p.description 175 , div [] [ text <| Maybe.withDefault "" p.description ]
111 , text <| String.fromFloat p.price 176 , div [] [ text <| String.fromFloat p.price ]
112 , a [ href ("/product/" ++ String.fromInt p.id) ] [ text "View Product" ] 177 , case p.averageRating of
178 Just v ->
179 text <| "Avg Rating: " ++ String.fromFloat v
180
181 Nothing ->
182 text "No Ratings"
183 , div [] [ a [ href ("/product/" ++ String.fromInt p.id) ] [ text "View Product" ] ]
113 ] 184 ]
114 185
115 186
187viewFilters : Model -> Html Msg
188viewFilters model =
189 let
190 priceRange =
191 range 0 50000 5000
192
193 ratingRange =
194 List.range 1 5
195
196 viewRange =
197 List.map (\i -> option [] [ text <| String.fromInt i ])
198
199 inp =
200 Maybe.withDefault 0 << String.toFloat
201 in
202 div []
203 [ div []
204 [ text "Price"
205 , select [ onInput (ChangePriceLower << inp) ] (viewRange priceRange)
206 , text "to"
207 , select [ onInput (ChangePriceUpper << inp) ] (viewRange priceRange)
208 ]
209 , div []
210 [ text "Rating"
211 , select [ onInput (ChangeRatingLower << inp) ] (viewRange ratingRange)
212 , text "to"
213 , select [ onInput (ChangeRatingUpper << inp) ] (viewRange ratingRange)
214 ]
215 ]
216
217
218filterProducts : Model -> List Product
219filterProducts model =
220 model.products
221 |> List.filter (between model.filters.price << .price)
222 |> List.filter
223 (\p ->
224 p.averageRating
225 |> Maybe.withDefault 5.0
226 |> between model.filters.rating
227 )
228
229
116view : Model -> Html Msg 230view : Model -> Html Msg
117view model = 231view model =
118 case model.pageStatus of 232 case model.pageStatus of
@@ -121,5 +235,7 @@ view model =
121 235
122 _ -> 236 _ ->
123 div [] 237 div []
124 [ ul [] (List.map viewProduct model.products) 238 [ div [] [ viewFilters model ]
239 , ul []
240 (filterProducts model |> List.map viewProduct)
125 ] 241 ]
diff --git a/frontend/src/Utils.elm b/frontend/src/Utils.elm
new file mode 100644
index 0000000..825e4b7
--- /dev/null
+++ b/frontend/src/Utils.elm
@@ -0,0 +1,15 @@
1module Utils exposing (..)
2
3
4between : ( Float, Float ) -> Float -> Bool
5between ( l, u ) v =
6 v >= l && v <= u
7
8
9range : Int -> Int -> Int -> List Int
10range start stop step =
11 if start >= stop then
12 []
13
14 else
15 start :: range (start + step) stop step