module Example exposing (..) import Browser import Html exposing (..) import Html.Attributes exposing (..) import Html.Events exposing (..) import Http import Json.Decode as Decode exposing (Decoder) import Json.Encode as Encode -- MODEL type alias Model = { users : List User , inputText : String , error : Maybe String } type alias User = { id : Int , name : String , email : String } init : () -> (Model, Cmd Msg) init _ = ( { users = [] , inputText = "" , error = Nothing } , fetchUsers ) -- UPDATE type Msg = GotUsers (Result Http.Error (List User)) | InputChanged String | AddUser | UserAdded (Result Http.Error User) update : Msg -> Model -> (Model, Cmd Msg) update msg model = case msg of GotUsers result -> case result of Ok users -> ( { model | users = users, error = Nothing } , Cmd.none ) Err _ -> ( { model | error = Just "Failed to fetch users" } , Cmd.none ) InputChanged text -> ( { model | inputText = text } , Cmd.none ) AddUser -> ( model , addUser model.inputText ) UserAdded result -> case result of Ok user -> ( { model | users = user :: model.users , inputText = "" , error = Nothing } , Cmd.none ) Err _ -> ( { model | error = Just "Failed to add user" } , Cmd.none ) -- HTTP fetchUsers : Cmd Msg fetchUsers = Http.get { url = "/api/users" , expect = Http.expectJson GotUsers usersDecoder } addUser : String -> Cmd Msg addUser name = Http.post { url = "/api/users" , body = Http.jsonBody (userEncoder name) , expect = Http.expectJson UserAdded userDecoder } -- JSON userEncoder : String -> Encode.Value userEncoder name = Encode.object [ ("name", Encode.string name) ] userDecoder : Decoder User userDecoder = Decode.map3 User (Decode.field "id" Decode.int) (Decode.field "name" Decode.string) (Decode.field "email" Decode.string) usersDecoder : Decoder (List User) usersDecoder = Decode.list userDecoder -- VIEW view : Model -> Html Msg view model = div [] [ h1 [] [ text "User Management" ] , viewError model.error , viewInput model.inputText , viewUsers model.users ] viewError : Maybe String -> Html Msg viewError maybeError = case maybeError of Just error -> div [ class "error" ] [ text error ] Nothing -> text "" viewInput : String -> Html Msg viewInput inputText = div [] [ input [ value inputText , onInput InputChanged , placeholder "Enter user name" ] [] , button [ onClick AddUser ] [ text "Add User" ] ] viewUsers : List User -> Html Msg viewUsers users = div [] [ h2 [] [ text "Users" ] , ul [] (List.map viewUser users) ] viewUser : User -> Html Msg viewUser user = li [] [ text (user.name ++ " (" ++ user.email ++ ")") ] -- MAIN main : Program () Model Msg main = Browser.element { init = init , update = update , view = view , subscriptions = \_ -> Sub.none }