diff --git a/part10/ElmHub.elm b/part10/ElmHub.elm
deleted file mode 100644
index 6275b46..0000000
--- a/part10/ElmHub.elm
+++ /dev/null
@@ -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
diff --git a/part10/Main.elm b/part10/Main.elm
index a5576be..cb7af06 100644
--- a/part10/Main.elm
+++ b/part10/Main.elm
@@ -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 )
diff --git a/part10/Page.elm b/part10/Page.elm
index 8b17668..0ed0b1f 100644
--- a/part10/Page.elm
+++ b/part10/Page.elm
@@ -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)
]
diff --git a/part10/Pages/Home.elm b/part10/Page/Home.elm
similarity index 86%
rename from part10/Pages/Home.elm
rename to part10/Page/Home.elm
index 827d921..4392ae7 100644
--- a/part10/Pages/Home.elm
+++ b/part10/Page/Home.elm
@@ -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" ]
diff --git a/part10/Page/Repository.elm b/part10/Page/Repository.elm
new file mode 100644
index 0000000..6e02cd1
--- /dev/null
+++ b/part10/Page/Repository.elm
@@ -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 )
diff --git a/part10/Pages/Repository.elm b/part10/Pages/Repository.elm
deleted file mode 100644
index 075ee09..0000000
--- a/part10/Pages/Repository.elm
+++ /dev/null
@@ -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 )
diff --git a/part10/README.md b/part10/README.md
index 5dbc3c7..97faaca 100644
--- a/part10/README.md
+++ b/part10/README.md
@@ -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).
diff --git a/part10/index.html b/part10/index.html
index 67af708..0e6f8e9 100644
--- a/part10/index.html
+++ b/part10/index.html
@@ -7,7 +7,7 @@
-
+