module Route.Signup exposing (ActionData, Data, Model, Msg, route) import DataSource exposing (DataSource) import Dict import Effect exposing (Effect) import ErrorPage exposing (ErrorPage) import Form.Field as Field import Form.FieldView import Form.Validation as Validation import Form.Value import Head import Head.Seo as Seo import Html exposing (Html) import Html.Attributes as Attr import Http import MySession import Pages.Form as Form import Pages.Msg import Pages.PageUrl exposing (PageUrl) import Pages.Url import Path exposing (Path) import Route import RouteBuilder exposing (StatefulRoute, StatelessRoute, StaticPayload) import Server.Request as Request import Server.Response as Response exposing (Response) import Server.Session as Session exposing (Session) import Shared import View exposing (View) type alias Model = {} type Msg = NoOp | GotResponse (Result Http.Error ActionData) type alias RouteParams = {} route : StatefulRoute RouteParams Data ActionData Model Msg route = RouteBuilder.serverRender { head = head , data = data , action = action } |> RouteBuilder.buildWithLocalState { view = view , update = update , subscriptions = subscriptions , init = init } action : RouteParams -> Request.Parser (DataSource (Response ActionData ErrorPage)) action _ = MySession.withSession (Request.formParserResultNew [ form ] |> Request.map (Result.mapError (\error -> "Errors")) |> Request.andThen Request.fromResult ) (\( first, email ) maybeSession -> let session : Session session = maybeSession |> Result.toMaybe |> Maybe.andThen identity |> Maybe.withDefault Session.empty in validate session { email = email , first = first } |> DataSource.succeed ) validate : Session -> { first : String, email : String } -> ( Session, Response ActionData ErrorPage ) validate session { first, email } = if first /= "" && email /= "" then ( session |> Session.withFlash "message" ("Success! You're all signed up " ++ first) , Route.redirectTo Route.Signup ) else ( session , ValidationErrors { errors = [ "Cannot be blank?" ] , fields = [ ( "first", first ) , ( "email", email ) ] } |> Response.render ) init : Maybe PageUrl -> Shared.Model -> StaticPayload Data ActionData RouteParams -> ( Model, Effect Msg ) init maybePageUrl sharedModel static = ( {} , --static.submit -- { headers = [] -- , fields = -- -- TODO when you run a Fetcher and get back a Redirect, how should that be handled? Maybe instead of `Result Http.Error ActionData`, -- -- it should be `FetcherResponse ActionData`, with Redirect as one of the possibilities? -- --[ ( "first", "Jane" ) -- --, ( "email", "jane@example.com" ) -- --] -- [ ( "first", "" ) -- , ( "email", "" ) -- ] -- } -- |> Effect.SubmitFetcher -- |> Effect.map GotResponse Effect.none ) fieldView : Form.Context String data -> String -> Form.ViewField String parsed Pages.FieldView.Input -> Html msg fieldView formState label field = Html.div [] [ Html.label [] [ Html.text (label ++ " ") , field |> Pages.FieldView.input [] ] , errorsForField formState field ] errorsForField : Form.Context String data -> Form.ViewField String parsed kind -> Html msg errorsForField formState field = (if True then field.errors |> List.map (\error -> Html.li [] [ Html.text error ]) else [] ) |> Html.ul [ Attr.style "color" "red" ] form : Form.HtmlForm String ( String, String ) data msg form = Form.init (\first email -> Validation.succeed Tuple.pair |> Validation.andMap first |> Validation.andMap email ) (\info first email -> [ first |> fieldView info "First" , email |> fieldView info "Email" , Html.button [] [ Html.text "Sign Up" ] ] ) |> Form.field "first" (Field.text |> required |> Field.withInitialValue (\_ -> Form.Value.string "Jane")) |> Form.field "email" (Field.text |> required |> Field.withInitialValue (\_ -> Form.Value.string "jane@example.com")) required field = field |> Field.required "Required" update : PageUrl -> Shared.Model -> StaticPayload Data ActionData RouteParams -> Msg -> Model -> ( Model, Effect Msg ) update pageUrl sharedModel static msg model = case msg of NoOp -> ( model, Effect.none ) GotResponse result -> let _ = Debug.log "GotResponse" result in ( model, Effect.none ) subscriptions : Maybe PageUrl -> RouteParams -> Path -> Shared.Model -> Model -> Sub Msg subscriptions maybePageUrl routeParams path sharedModel model = Sub.none type alias Data = { flashMessage : Maybe (Result String String) } type ActionData = Success { email : String, first : String } | ValidationErrors { errors : List String , fields : List ( String, String ) } data : RouteParams -> Request.Parser (DataSource (Response Data ErrorPage)) data routeParams = MySession.withSession (Request.succeed ()) (\() sessionResult -> let session : Session session = sessionResult |> Result.toMaybe |> Maybe.andThen identity |> Maybe.withDefault Session.empty flashMessage : Maybe String flashMessage = session |> Session.get "message" in ( Session.empty , Response.render { flashMessage = flashMessage |> Maybe.map Ok } ) |> DataSource.succeed ) head : StaticPayload Data ActionData RouteParams -> List Head.Tag head static = [] view : Maybe PageUrl -> Shared.Model -> Model -> StaticPayload Data ActionData RouteParams -> View (Pages.Msg.Msg Msg) view maybeUrl sharedModel model static = { title = "Signup" , body = [ Html.p [] [ case static.action of Just (Success { email, first }) -> Html.text <| "Hello " ++ first ++ "!" Just (ValidationErrors { errors }) -> errors |> List.map (\error -> Html.li [] [ Html.text error ]) |> Html.ul [] _ -> Html.text "" ] , flashView static.data.flashMessage , form |> Form.toDynamicTransition "test1" |> Form.renderHtml [] static () ] } flashView : Maybe (Result String String) -> Html msg flashView message = Html.p [ Attr.style "background-color" "rgb(163 251 163)" ] [ Html.text <| case message of Nothing -> "" Just (Ok okMessage) -> okMessage Just (Err error) -> "Something went wrong: " ++ error ]