Flesh out part10

This commit is contained in:
Richard Feldman
2016-09-02 22:21:10 -07:00
parent 5fd5863b53
commit 6ec25f4f57
8 changed files with 221 additions and 86 deletions

View File

@@ -1,19 +0,0 @@
module ElmHub exposing (..)
import Json.Decode exposing (Decoder)
import Json.Decode.Pipeline exposing (..)
type alias SearchResult =
{ id : Int
, name : String
, stars : Int
}
searchResultDecoder : Decoder SearchResult
searchResultDecoder =
decode SearchResult
|> required "id" Json.Decode.int
|> required "full_name" Json.Decode.string
|> required "stargazers_count" Json.Decode.int

View File

@@ -1,7 +1,7 @@
module Main exposing (..)
import Pages.Home
import Pages.Repository
import Page.Home
import Page.Repository
import Navigation
import Page exposing (Page(..))
import Tuple2
@@ -11,13 +11,14 @@ import Html.App as Html
type Model
= Home Pages.Home.Model
| Repository Pages.Repository.Model
= Home Page.Home.Model
| Repository Page.Repository.Model
| NotFound
type Msg
= HomeMsg Pages.Home.Msg
| RepositoryMsg Pages.Repository.Msg
= HomeMsg Page.Home.Msg
| RepositoryMsg Page.Repository.Msg
main : Program Never
@@ -35,17 +36,37 @@ subscriptions : Model -> Sub Msg
subscriptions model =
case model of
Home pageModel ->
Pages.Home.subscriptions pageModel
-- TODO use Sub.map to translate from Page.Home.subscriptions
Page.Home.subscriptions pageModel
|> Sub.map HomeMsg
Repository pageModel ->
-- Repository has no subscriptions, so there's nothing to translate!
Sub.none
NotFound ->
-- NotFound has no subscriptions, so there's nothing to translate!
Sub.none
init : Result String Page -> ( Model, Cmd Msg )
init result =
Home (fst Pages.Home.init)
|> urlUpdate result
case result of
Ok (Page.Home) ->
-- TODO use Html.map to translate from Page.Home.view
Page.Home.init
|> Tuple2.mapEach Home (Cmd.map HomeMsg)
Ok (Page.Repository repoOwner repoName) ->
-- TODO use Html.map to translate from Page.Repository.view
Page.Repository.init repoOwner repoName
|> Tuple2.mapEach Repository (Cmd.map RepositoryMsg)
Ok (Page.NotFound) ->
( NotFound, Cmd.none )
Err err ->
( NotFound, Cmd.none )
view : Model -> Html Msg
@@ -53,13 +74,18 @@ view model =
withHeader <|
case model of
Home pageModel ->
Pages.Home.view pageModel
-- TODO use Html.map to translate from Page.Home.view
Page.Home.view pageModel
|> Html.map HomeMsg
Repository pageModel ->
Pages.Repository.view pageModel
-- TODO use Html.map to translate from Page.Repository.view
Page.Repository.view pageModel
|> Html.map RepositoryMsg
NotFound ->
h1 [] [ text "Page Not Found" ]
withHeader : Html msg -> Html msg
withHeader innerContent =
@@ -76,14 +102,20 @@ update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case ( msg, model ) of
( HomeMsg pageMsg, Home pageModel ) ->
Pages.Home.update pageMsg pageModel
-- TODO use Tuple2.mapEach and (Cmd.map HomeMsg)
-- to translate from Page.Home.update
--
-- mapEach : (a -> newA) -> (b -> newB) -> ( a, b ) -> ( newA, newB )
Page.Home.update pageMsg pageModel
|> Tuple2.mapEach Home (Cmd.map HomeMsg)
( RepositoryMsg pageMsg, Repository pageModel ) ->
Pages.Repository.update pageMsg pageModel
-- TODO use Tuple2.mapEach and (Cmd.map RepositoryMsg)
-- to translate from Page.Repository.update
Page.Repository.update pageMsg pageModel
|> Tuple2.mapEach Repository (Cmd.map RepositoryMsg)
( _, _ ) ->
_ ->
( model, Cmd.none )
@@ -91,15 +123,23 @@ urlUpdate : Result String Page -> Model -> ( Model, Cmd Msg )
urlUpdate result model =
case result of
Ok (Page.Home) ->
Pages.Home.init
-- TODO use Tuple2.mapEach and (Cmd.map HomeMsg)
-- to translate from Page.Home.init
--
-- mapEach : (a -> newA) -> (b -> newB) -> ( a, b ) -> ( newA, newB )
Page.Home.init
|> Tuple2.mapEach Home (Cmd.map HomeMsg)
Ok (Page.Repository id) ->
Pages.Repository.init id
Ok (Page.Repository repoOwner repoName) ->
-- TODO use Tuple2.mapEach and (Cmd.map RepositoryMsg)
-- to translate from Page.Repository.init
--
-- HINT: Page.Repository.init is a function that takes 2 arguments.
Page.Repository.init repoOwner repoName
|> Tuple2.mapEach Repository (Cmd.map RepositoryMsg)
Ok NotFound ->
( model, Cmd.none )
Ok (Page.NotFound) ->
( NotFound, Cmd.none )
Err _ ->
( model, Navigation.modifyUrl "/" )
Err err ->
( NotFound, Cmd.none )

View File

@@ -7,7 +7,7 @@ import String
type Page
= Home
| Repository Int
| Repository String String
| NotFound
@@ -15,7 +15,7 @@ pageParser : Parser (Page -> a) a
pageParser =
UrlParser.oneOf
[ format Home (s "")
, format Repository (s "repositories" </> int)
, format Repository (s "repositories" </> string </> string)
]

View File

@@ -1,14 +1,29 @@
port module Pages.Home exposing (..)
port module Page.Home exposing (..)
import Html exposing (..)
import Html.Attributes exposing (class, target, href, property, defaultValue)
import Html.Events exposing (..)
import Auth
import Json.Decode exposing (Decoder)
import ElmHub exposing (SearchResult)
import Json.Decode.Pipeline exposing (decode, required)
import Navigation
type alias SearchResult =
{ id : Int
, name : String
, stars : Int
}
searchResultDecoder : Decoder SearchResult
searchResultDecoder =
decode SearchResult
|> required "id" Json.Decode.int
|> required "full_name" Json.Decode.string
|> required "stargazers_count" Json.Decode.int
getQueryString : String -> String
getQueryString query =
-- See https://developer.github.com/v3/search/#example for how to customize!
@@ -21,7 +36,7 @@ getQueryString query =
responseDecoder : Decoder (List SearchResult)
responseDecoder =
Json.Decode.at [ "items" ] (Json.Decode.list ElmHub.searchResultDecoder)
Json.Decode.at [ "items" ] (Json.Decode.list searchResultDecoder)
type alias Model =
@@ -70,7 +85,7 @@ viewSearchResult : SearchResult -> Html Msg
viewSearchResult result =
li []
[ span [ class "star-count" ] [ text (toString result.stars) ]
, a [ onClick (Visit ("/repositories/" ++ toString result.id)) ]
, a [ onClick (Visit ("/repositories/" ++ result.name)) ]
[ text result.name ]
, button [ class "hide-result", onClick (DeleteById result.id) ]
[ text "X" ]

136
part10/Page/Repository.elm Normal file
View File

@@ -0,0 +1,136 @@
module Page.Repository exposing (..)
import Html exposing (..)
import Html.Attributes exposing (class, target, href, property, defaultValue, src)
import Auth
import Http
import Task
import Json.Decode exposing (Decoder, int, string, list)
import Json.Decode.Pipeline exposing (decode, required)
type alias Model =
{ repoOwner : String
, repoName : String
, repository : Maybe Repository
}
type alias Repository =
{ id : Int
, issues : Int
, forks : Int
, watchers : Int
, owner : User
, description : String
}
type alias User =
{ id : Int
, username : String
, avatarUrl : String
, profileUrl : String
}
userDecoder : Decoder User
userDecoder =
decode User
|> required "id" int
|> required "login" string
|> required "avatar_url" string
|> required "url" string
repoDecoder : Decoder Repository
repoDecoder =
decode Repository
|> required "id" int
|> required "open_issues_count" int
|> required "forks" int
|> required "watchers" int
|> required "owner" userDecoder
|> required "description" string
init : String -> String -> ( Model, Cmd Msg )
init repoOwner repoName =
( { repoOwner = repoOwner
, repoName = repoName
, repository = Nothing
}
, getRepoInfo repoOwner repoName
)
view : Model -> Html Msg
view model =
let
ownerUrl =
"https://github.com/" ++ model.repoOwner
repoUrl =
ownerUrl ++ "/" ++ model.repoName
details =
model.repository
|> Maybe.map viewDetails
|> Maybe.withDefault (text "")
in
div []
[ h1 []
[ a [ href repoUrl ] [ text model.repoName ] ]
, details
]
viewDetails : Repository -> Html Msg
viewDetails repo =
div []
[ p [] [ text repo.description ]
, h2 []
[ a [ href repo.owner.profileUrl ]
[ img [ class "profile-photo", src repo.owner.avatarUrl ] []
, text repo.owner.username
]
]
, table []
[ tbody []
[ tr [] [ th [] [ text "issues" ], td [] [ text (toString repo.issues) ] ]
, tr [] [ th [] [ text "forks" ], td [] [ text (toString repo.forks) ] ]
, tr [] [ th [] [ text "watchers" ], td [] [ text (toString repo.watchers) ] ]
]
]
]
type Msg
= HandleRepoError Http.Error
| HandleRepoResponse Repository
getRepoInfo : String -> String -> Cmd Msg
getRepoInfo repoOwner repoName =
let
url =
"https://api.github.com/repos/"
++ repoOwner
++ "/"
++ repoName
++ "?access_token="
++ Auth.token
|> Debug.log "getRepoInfo"
in
Http.get repoDecoder url
|> Task.perform HandleRepoError HandleRepoResponse
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
HandleRepoError err ->
( model, Cmd.none )
HandleRepoResponse repository ->
( { model | repository = Just repository }, Cmd.none )

View File

@@ -1,37 +0,0 @@
module Pages.Repository exposing (..)
import Html exposing (..)
import Html.Attributes exposing (class, target, href, property, defaultValue)
import ElmHub exposing (SearchResult)
type alias Model =
SearchResult
init : Int -> ( Model, Cmd Msg )
init id =
( { id = id
, name = ""
, stars = id
}
, Cmd.none
)
view : Model -> Html Msg
view model =
div []
[ div [] [ text ("repo" ++ toString model.stars) ]
]
type Msg
= NoOp
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
NoOp ->
( model, Cmd.none )

View File

@@ -1,5 +1,5 @@
Part 8
======
Part 10
=======
The instructor will paste notes from the lesson, including code examples from
Q&A, in [this document](https://docs.google.com/document/d/1ApuSOk9DP0YsQrxhW7-WE8UOEAV4PPnLDDeqUOL2o5k/edit?usp=sharing).

View File

@@ -7,7 +7,7 @@
<script type="text/javascript" src="/github.js"></script>
<script type="text/javascript" src="/elm.js"></script>
<link rel="stylesheet" href="/style.css">
<link rel="icon" type="image/png" href="elm-hub.png">
<link rel="icon" type="image/png" href="/elm-hub.png">
</head>
<body>