module Main exposing (..) import Evt exposing (Evt) import Html exposing (..) import Http import Navigation exposing (Location) import Client import Route exposing (Route) import Routing import Session import Task -- TYPES type Page = Loading | Loaded Routing.PageModel | Failure Http.Error | NotFound type alias Model = { clientConfig : Client.Config , page : Page } init : Flags -> Maybe Route -> ( Model, Cmd Msg ) init flags route = ( { clientConfig = Client.config { backend = flags.backend, session = Nothing } , page = Loading } , Session.get |> Task.andThen (\session -> Task.succeed ( route, session )) |> Task.perform Initialized ) -- UPDATE type Msg = NoOp | Initialized ( Maybe Route, Maybe String ) | RouteTo (Maybe Route) | PageLoaded (Result Http.Error Routing.PageModel) | SignedIn String | SignedOut | RoutingPageMsg Routing.PageMsg update : Msg -> Model -> ( Model, Evt Msg, Cmd Msg ) update msg model = case msg of NoOp -> ( model, Evt.none, Cmd.none ) Initialized ( route, sessionID ) -> ( sessionID |> Maybe.map (\sid -> { model | clientConfig = Client.startSession sid model.clientConfig }) |> Maybe.withDefault model , Evt.evt (RouteTo route) , Cmd.none ) RouteTo (Just route) -> let hasSession = Client.hasSession model.clientConfig routeRequiresSession = Route.isSecure route loadCmd = if hasSession == routeRequiresSession then Task.attempt PageLoaded <| Routing.load model.clientConfig route else if hasSession then Route.redirectTo Route.secureEntry else Route.redirectTo Route.nonSecureEntry in ( model, Evt.none, loadCmd ) RouteTo Nothing -> ( { model | page = NotFound }, Evt.none, Cmd.none ) PageLoaded (Ok pageModel) -> ( { model | page = Loaded pageModel }, Evt.none, Cmd.none ) PageLoaded (Err err) -> case Debug.log "page load error: " err of Http.BadStatus resp -> if resp.status.code == 401 then update SignedOut model else ( { model | page = Failure err }, Evt.none, Cmd.none ) _ -> ( { model | page = Failure err }, Evt.none, Cmd.none ) SignedIn session -> ( { model | clientConfig = Client.startSession session model.clientConfig } , Evt.none , Cmd.batch [ Task.perform (always NoOp) (Session.set session) , Route.redirectTo Route.secureEntry ] ) SignedOut -> ( { model | clientConfig = Client.clearSession model.clientConfig } , Evt.none , Cmd.batch [ Task.perform (always NoOp) Session.clear , Route.redirectTo Route.nonSecureEntry ] ) RoutingPageMsg pgmsg -> case model.page of Loaded pgmod -> let ( pgmodnew, pgevt, pgcmd ) = Routing.update model.clientConfig (Evt.evt << SignedIn) pgmsg pgmod in ( { model | page = Loaded pgmodnew }, pgevt, Cmd.map RoutingPageMsg pgcmd ) _ -> ( model, Evt.none, Cmd.none ) -- SUBSCRIPTIONS subscriptions : Model -> Sub Msg subscriptions model = case model.page of Loaded pgmod -> Sub.map RoutingPageMsg <| Routing.subscriptions pgmod _ -> Sub.none -- VIEW view : Model -> Html Msg view model = case model.page of Loading -> text "loading" Loaded pageModel -> Routing.view pageModel { toMsg = RoutingPageMsg , onSignOut = SignedOut } Failure err -> text "failure" NotFound -> text "not found" -- MAIN type alias Flags = { backend : String } main : Program Flags Model Msg main = Navigation.programWithFlags (RouteTo << Route.route) { init = (\flags loc -> init flags (Route.route loc)) , update = Evt.update update , view = view , subscriptions = subscriptions }