mirror of
https://github.com/dillonkearns/elm-pages.git
synced 2024-09-11 09:05:28 +03:00
Decode into nicer custom type.
This commit is contained in:
parent
d05bb257e2
commit
49078902ff
@ -17,7 +17,7 @@ import RouteBuilder exposing (StatefulRoute, StatelessRoute, StaticPayload)
|
||||
import Server.Request as Request
|
||||
import Server.Response as Response exposing (Response)
|
||||
import Shared
|
||||
import Story exposing (Story)
|
||||
import Story exposing (Item)
|
||||
import Url.Builder
|
||||
import View exposing (View)
|
||||
|
||||
@ -81,7 +81,7 @@ pages =
|
||||
|
||||
|
||||
type alias Data =
|
||||
{ stories : List Story }
|
||||
{ stories : List Item }
|
||||
|
||||
|
||||
data : RouteParams -> Request.Parser (DataSource (Response Data ErrorPage))
|
||||
@ -119,7 +119,7 @@ data routeParams =
|
||||
[ Url.Builder.string "page" (maybePage |> Maybe.withDefault "1")
|
||||
]
|
||||
|
||||
getStories : DataSource (List Story)
|
||||
getStories : DataSource (List Item)
|
||||
getStories =
|
||||
DataSource.Http.get getStoriesUrl
|
||||
(Story.decoder |> Json.Decode.list)
|
||||
|
@ -15,7 +15,7 @@ import RouteBuilder exposing (StatefulRoute, StatelessRoute, StaticPayload)
|
||||
import Server.Request as Request
|
||||
import Server.Response as Response exposing (Response)
|
||||
import Shared
|
||||
import Story exposing (Story)
|
||||
import Story exposing (Entry(..), Item(..))
|
||||
import View exposing (View)
|
||||
|
||||
|
||||
@ -78,7 +78,7 @@ pages =
|
||||
|
||||
|
||||
type alias Data =
|
||||
{ story : Story
|
||||
{ story : Item
|
||||
}
|
||||
|
||||
|
||||
@ -129,8 +129,8 @@ view maybeUrl sharedModel model static =
|
||||
}
|
||||
|
||||
|
||||
storyView : Story -> Html msg
|
||||
storyView story =
|
||||
storyView : Item -> Html msg
|
||||
storyView (Item story entry) =
|
||||
Html.div
|
||||
[ Attr.class "item-view"
|
||||
]
|
||||
@ -138,7 +138,7 @@ storyView story =
|
||||
[ Attr.class "item-view-header"
|
||||
]
|
||||
[ Html.a
|
||||
[ Attr.href (story.url |> Maybe.withDefault "")
|
||||
[ Attr.href story.url
|
||||
, Attr.target "_blank"
|
||||
, Attr.rel "noreferrer"
|
||||
]
|
||||
@ -150,20 +150,24 @@ storyView story =
|
||||
, Html.p
|
||||
[ Attr.class "meta"
|
||||
]
|
||||
[ case story.points of
|
||||
Just points ->
|
||||
Html.text <| (String.fromInt points ++ " points | ")
|
||||
((case entry of
|
||||
Story { points, user } ->
|
||||
[ Html.text <| (String.fromInt points ++ " points | ")
|
||||
, Html.text "by "
|
||||
, Html.a
|
||||
[ Attr.href <|
|
||||
"/users/"
|
||||
++ user
|
||||
]
|
||||
[ Html.text user
|
||||
]
|
||||
]
|
||||
|
||||
Nothing ->
|
||||
Html.text ""
|
||||
, Html.text "by "
|
||||
, Html.a
|
||||
[ Attr.href <| "/users/" ++ (story.user |> Maybe.withDefault "")
|
||||
]
|
||||
[ Html.text (story.user |> Maybe.withDefault "")
|
||||
]
|
||||
, Html.text <| " " ++ story.time_ago ++ " ago"
|
||||
]
|
||||
_ ->
|
||||
[]
|
||||
)
|
||||
++ [ Html.text <| " " ++ story.time_ago ++ " ago" ]
|
||||
)
|
||||
]
|
||||
, Html.div
|
||||
[ Attr.class "item-view-comments"
|
||||
|
@ -3,100 +3,113 @@ module Story exposing (..)
|
||||
import Html exposing (Html)
|
||||
import Html.Attributes as Attr
|
||||
import Json.Decode exposing (Decoder)
|
||||
import Json.Decode.Pipeline exposing (optional, required)
|
||||
import Json.Decode.Pipeline exposing (hardcoded, optional, required)
|
||||
import Route
|
||||
|
||||
|
||||
type alias Story =
|
||||
type alias StoryRecord =
|
||||
{ points : Int
|
||||
, user : String
|
||||
, type_ : String
|
||||
}
|
||||
|
||||
|
||||
type alias Common =
|
||||
{ title : String
|
||||
, points : Maybe Int
|
||||
, user : Maybe String
|
||||
, url : Maybe String
|
||||
, url : String
|
||||
, domain : String
|
||||
, time_ago : String
|
||||
, comments_count : Int
|
||||
, type_ : String
|
||||
, id : Int
|
||||
}
|
||||
|
||||
|
||||
view : Story -> Html msg
|
||||
view story =
|
||||
type Item
|
||||
= Item Common Entry
|
||||
|
||||
|
||||
type Entry
|
||||
= Story StoryRecord
|
||||
| Job
|
||||
|
||||
|
||||
view : Item -> Html msg
|
||||
view (Item story entry) =
|
||||
Html.li
|
||||
[ Attr.class "news-item"
|
||||
]
|
||||
[ Html.span
|
||||
[ Attr.class "score"
|
||||
]
|
||||
[ Html.text
|
||||
(story.points
|
||||
|> Maybe.map String.fromInt
|
||||
|> Maybe.withDefault ""
|
||||
)
|
||||
[ case entry of
|
||||
Story { points } ->
|
||||
Html.text (String.fromInt points)
|
||||
|
||||
_ ->
|
||||
Html.text ""
|
||||
]
|
||||
, Html.span
|
||||
[ Attr.class "title"
|
||||
]
|
||||
(case ( story.url, story.url |> Maybe.withDefault "" |> String.startsWith "item?id=" ) of
|
||||
( Just url, False ) ->
|
||||
(case story.url |> String.startsWith "item?id=" of
|
||||
False ->
|
||||
[ Html.a
|
||||
[ Attr.href url
|
||||
[ Attr.href story.url
|
||||
, Attr.target "_blank"
|
||||
, Attr.rel "noreferrer"
|
||||
]
|
||||
[ Html.text story.title ]
|
||||
, Html.text " "
|
||||
, domainView story.domain
|
||||
]
|
||||
|
||||
( Nothing, _ ) ->
|
||||
_ ->
|
||||
[ Route.Stories__Id_ { id = String.fromInt story.id }
|
||||
|> Route.link
|
||||
[-- TODO decode into custom type here? --Attr.href ("/item/" ++ story.id)
|
||||
]
|
||||
[ Html.text story.title ]
|
||||
]
|
||||
|
||||
_ ->
|
||||
[ Html.text story.title ]
|
||||
)
|
||||
, Html.br []
|
||||
[]
|
||||
, Html.span
|
||||
[ Attr.class "meta"
|
||||
]
|
||||
(if story.type_ == "job" then
|
||||
[ Route.Stories__Id_ { id = String.fromInt story.id }
|
||||
|> Route.link
|
||||
[]
|
||||
[ Html.text story.time_ago
|
||||
]
|
||||
]
|
||||
|
||||
else
|
||||
[ Html.text "by "
|
||||
, Html.a [ Attr.href "TODO user page link" ]
|
||||
[ story.user |> Maybe.withDefault "" |> Html.text
|
||||
(case entry of
|
||||
Job ->
|
||||
[ Route.Stories__Id_ { id = String.fromInt story.id }
|
||||
|> Route.link
|
||||
[]
|
||||
[ Html.text story.time_ago
|
||||
]
|
||||
]
|
||||
, Html.text (" " ++ story.time_ago ++ " | ")
|
||||
, Route.Stories__Id_ { id = String.fromInt story.id }
|
||||
|> Route.link
|
||||
[]
|
||||
[ if story.comments_count > 0 then
|
||||
Html.text (String.fromInt story.comments_count ++ " comments")
|
||||
|
||||
else
|
||||
Html.text "discuss"
|
||||
Story record ->
|
||||
[ Html.text "by "
|
||||
, Html.a [ Attr.href "TODO user page link" ]
|
||||
[ record.user |> Html.text
|
||||
]
|
||||
]
|
||||
)
|
||||
, if story.type_ /= "link" then
|
||||
Html.span
|
||||
[ Attr.class "label"
|
||||
]
|
||||
[ Html.text <| " " ++ story.type_ ]
|
||||
, Html.text (" " ++ story.time_ago ++ " | ")
|
||||
, Route.Stories__Id_ { id = String.fromInt story.id }
|
||||
|> Route.link
|
||||
[]
|
||||
[ if story.comments_count > 0 then
|
||||
Html.text (String.fromInt story.comments_count ++ " comments")
|
||||
|
||||
else
|
||||
Html.text ""
|
||||
else
|
||||
Html.text "discuss"
|
||||
]
|
||||
, if record.type_ /= "link" then
|
||||
Html.span
|
||||
[ Attr.class "label"
|
||||
]
|
||||
[ Html.text <| " " ++ record.type_ ]
|
||||
|
||||
else
|
||||
Html.text ""
|
||||
]
|
||||
)
|
||||
]
|
||||
|
||||
|
||||
@ -114,15 +127,29 @@ domainView domain =
|
||||
]
|
||||
|
||||
|
||||
decoder : Decoder Story
|
||||
decoder : Decoder Item
|
||||
decoder =
|
||||
Json.Decode.succeed Story
|
||||
|> required "title" Json.Decode.string
|
||||
|> required "points" (Json.Decode.nullable Json.Decode.int)
|
||||
|> required "user" (Json.Decode.nullable Json.Decode.string)
|
||||
|> required "url" (Json.Decode.nullable Json.Decode.string)
|
||||
|> optional "domain" Json.Decode.string ""
|
||||
|> required "time_ago" Json.Decode.string
|
||||
|> required "comments_count" Json.Decode.int
|
||||
|> required "type" Json.Decode.string
|
||||
|> required "id" Json.Decode.int
|
||||
Json.Decode.map2 Item
|
||||
(Json.Decode.succeed Common
|
||||
|> required "title" Json.Decode.string
|
||||
|> required "url" Json.Decode.string
|
||||
|> optional "domain" Json.Decode.string ""
|
||||
|> required "time_ago" Json.Decode.string
|
||||
|> required "comments_count" Json.Decode.int
|
||||
|> required "id" Json.Decode.int
|
||||
)
|
||||
(Json.Decode.field "type" Json.Decode.string
|
||||
|> Json.Decode.andThen entryDecoder
|
||||
)
|
||||
|
||||
|
||||
entryDecoder type_ =
|
||||
if type_ == "job" then
|
||||
Json.Decode.succeed Job
|
||||
|
||||
else
|
||||
Json.Decode.succeed StoryRecord
|
||||
|> required "points" Json.Decode.int
|
||||
|> required "user" Json.Decode.string
|
||||
|> hardcoded type_
|
||||
|> Json.Decode.map Story
|
||||
|
Loading…
Reference in New Issue
Block a user