module Page.Home exposing (Model, Msg, init, subscriptions, toSession, update, view) {-| The homepage. You can get here via either the / or /#/ routes. -} import Article import Article.Feed as Feed import Article.FeedSources as FeedSources exposing (FeedSources, Source(..)) import Article.Tag as Tag exposing (Tag) import Html exposing (..) import Html.Attributes exposing (attribute, class, classList, href, id, placeholder) import Html.Events exposing (onClick) import Http import Loading import Log import Page import Session exposing (Session) import Task exposing (Task) import Time import Viewer.Cred as Cred exposing (Cred) -- MODEL type alias Model = { session : Session , timeZone : Time.Zone -- Loaded independently from server , tags : Status (List Tag) , feed : Status Feed.Model } type Status a = Loading | Loaded a | Failed init : Session -> ( Model, Cmd Msg ) init session = let feedSources = case Session.cred session of Just cred -> FeedSources.fromLists (YourFeed cred) [ GlobalFeed ] Nothing -> FeedSources.fromLists GlobalFeed [] loadTags = Tag.list |> Http.toTask in ( { session = session , timeZone = Time.utc , tags = Loading , feed = Loading } , Cmd.batch [ Feed.init session feedSources |> Task.attempt CompletedFeedLoad , Tag.list |> Http.send CompletedTagsLoad , Task.perform GotTimeZone Time.here ] ) -- VIEW view : Model -> { title : String, content : Html Msg } view model = { title = "Conduit" , content = div [ class "home-page" ] [ viewBanner , div [ class "container page" ] [ div [ class "row" ] [ div [ class "col-md-9" ] <| case model.feed of Loaded feed -> viewFeed model.timeZone feed Loading -> [ Loading.icon ] Failed -> [ Loading.error "feed" ] , div [ class "col-md-3" ] [ div [ class "sidebar" ] <| case model.tags of Loaded tags -> [ p [] [ text "Popular Tags" ] , viewTags tags ] Loading -> [ Loading.icon ] Failed -> [ Loading.error "tags" ] ] ] ] ] } viewBanner : Html msg viewBanner = div [ class "banner" ] [ div [ class "container" ] [ h1 [ class "logo-font" ] [ text "conduit" ] , p [] [ text "A place to share your knowledge." ] ] ] viewFeed : Time.Zone -> Feed.Model -> List (Html Msg) viewFeed timeZone feed = div [ class "feed-toggle" ] [ Feed.viewFeedSources feed |> Html.map GotFeedMsg ] :: (Feed.viewArticles timeZone feed |> List.map (Html.map GotFeedMsg)) viewTags : List Tag -> Html Msg viewTags tags = div [ class "tag-list" ] (List.map viewTag tags) viewTag : Tag -> Html Msg viewTag tagName = a [ class "tag-pill tag-default" , onClick (ClickedTag tagName) -- The RealWorld CSS requires an href to work properly. , href "" ] [ text (Tag.toString tagName) ] -- UPDATE type Msg = ClickedTag Tag | CompletedFeedLoad (Result Http.Error Feed.Model) | CompletedTagsLoad (Result Http.Error (List Tag)) | GotTimeZone Time.Zone | GotFeedMsg Feed.Msg | GotSession Session update : Msg -> Model -> ( Model, Cmd Msg ) update msg model = case msg of ClickedTag tagName -> let subCmd = Feed.selectTag (Session.cred model.session) tagName in ( model, Cmd.map GotFeedMsg subCmd ) CompletedFeedLoad (Ok feed) -> ( { model | feed = Loaded feed }, Cmd.none ) CompletedFeedLoad (Err error) -> ( { model | feed = Failed }, Cmd.none ) CompletedTagsLoad (Ok tags) -> ( { model | tags = Loaded tags }, Cmd.none ) CompletedTagsLoad (Err error) -> ( { model | tags = Failed } , Log.error ) GotFeedMsg subMsg -> case model.feed of Loaded feed -> let ( newFeed, subCmd ) = Feed.update (Session.cred model.session) subMsg feed in ( { model | feed = Loaded newFeed } , Cmd.map GotFeedMsg subCmd ) Loading -> ( model, Log.error ) Failed -> ( model, Log.error ) GotTimeZone tz -> ( { model | timeZone = tz }, Cmd.none ) GotSession session -> ( { model | session = session }, Cmd.none ) -- SUBSCRIPTIONS subscriptions : Model -> Sub Msg subscriptions model = Session.changes GotSession (Session.navKey model.session) -- EXPORT toSession : Model -> Session toSession model = model.session