mirror of
https://github.com/dillonkearns/elm-pages-v3-beta.git
synced 2024-12-26 13:21:42 +03:00
Add edit screen.
This commit is contained in:
parent
7f5e4f9266
commit
d2b794bfa5
@ -263,6 +263,7 @@ productView cart item =
|
||||
Html.li [ Attr.class "item" ]
|
||||
[ Html.div []
|
||||
[ Html.h3 [] [ Html.text item.name ]
|
||||
, Route.SmoothieId___Edit { smoothieId = uuidToString item.id } |> Route.link [] [ Html.text "Edit" ]
|
||||
, Html.p [] [ Html.text item.description ]
|
||||
, Html.p [] [ "$" ++ String.fromInt item.price |> Html.text ]
|
||||
]
|
||||
|
262
examples/smoothies/app/Route/SmoothieId_/Edit.elm
Normal file
262
examples/smoothies/app/Route/SmoothieId_/Edit.elm
Normal file
@ -0,0 +1,262 @@
|
||||
module Route.SmoothieId_.Edit exposing (ActionData, Data, Model, Msg, route)
|
||||
|
||||
import Api.Scalar exposing (Uuid(..))
|
||||
import Data.Smoothies as Smoothies exposing (Smoothie)
|
||||
import DataSource exposing (DataSource)
|
||||
import Dict
|
||||
import Dict.Extra
|
||||
import Effect exposing (Effect)
|
||||
import ErrorPage exposing (ErrorPage)
|
||||
import Form.Value
|
||||
import Graphql.SelectionSet as SelectionSet
|
||||
import Head
|
||||
import Head.Seo as Seo
|
||||
import Html exposing (Html)
|
||||
import Html.Attributes as Attr
|
||||
import MySession
|
||||
import Pages.Field as Field
|
||||
import Pages.Form
|
||||
import Pages.FormParser as FormParser
|
||||
import Pages.Msg
|
||||
import Pages.PageUrl exposing (PageUrl)
|
||||
import Pages.Url
|
||||
import Path exposing (Path)
|
||||
import Request.Hasura
|
||||
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
|
||||
import Shared
|
||||
import View exposing (View)
|
||||
|
||||
|
||||
type alias Model =
|
||||
{}
|
||||
|
||||
|
||||
type Msg
|
||||
= NoOp
|
||||
|
||||
|
||||
type alias RouteParams =
|
||||
{ smoothieId : String }
|
||||
|
||||
|
||||
type alias NewItem =
|
||||
{ name : String
|
||||
, description : String
|
||||
, price : Int
|
||||
, imageUrl : String
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
init :
|
||||
Maybe PageUrl
|
||||
-> Shared.Model
|
||||
-> StaticPayload Data ActionData RouteParams
|
||||
-> ( Model, Effect Msg )
|
||||
init maybePageUrl sharedModel static =
|
||||
( {}, Effect.none )
|
||||
|
||||
|
||||
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 )
|
||||
|
||||
|
||||
subscriptions : Maybe PageUrl -> RouteParams -> Path -> Shared.Model -> Model -> Sub Msg
|
||||
subscriptions maybePageUrl routeParams path sharedModel model =
|
||||
Sub.none
|
||||
|
||||
|
||||
pages : DataSource (List RouteParams)
|
||||
pages =
|
||||
DataSource.succeed []
|
||||
|
||||
|
||||
type alias Data =
|
||||
{ smoothie : Smoothie
|
||||
}
|
||||
|
||||
|
||||
type alias ActionData =
|
||||
{}
|
||||
|
||||
|
||||
data : RouteParams -> Request.Parser (DataSource (Response Data ErrorPage))
|
||||
data routeParams =
|
||||
Request.requestTime
|
||||
|> MySession.expectSessionDataOrRedirect (Session.get "userId")
|
||||
(\userId requestTime session ->
|
||||
((Smoothies.find (Uuid routeParams.smoothieId)
|
||||
|> Request.Hasura.dataSource requestTime
|
||||
)
|
||||
|> DataSource.map
|
||||
(\maybeSmoothie ->
|
||||
maybeSmoothie
|
||||
|> Maybe.map (Data >> Response.render)
|
||||
|> Maybe.withDefault (Response.errorPage ErrorPage.NotFound)
|
||||
)
|
||||
)
|
||||
|> DataSource.map (Tuple.pair session)
|
||||
)
|
||||
|
||||
|
||||
action : RouteParams -> Request.Parser (DataSource (Response ActionData ErrorPage))
|
||||
action routeParams =
|
||||
Request.skip "No action."
|
||||
|
||||
|
||||
head : StaticPayload Data ActionData RouteParams -> List Head.Tag
|
||||
head static =
|
||||
[]
|
||||
|
||||
|
||||
form : FormParser.HtmlForm String { name : String, description : String, price : Int, imageUrl : String } Data Msg
|
||||
form =
|
||||
FormParser.andThenNew
|
||||
(\name description price imageUrl ->
|
||||
FormParser.ok
|
||||
{ name = name.value
|
||||
, description = description.value
|
||||
, price = price.value
|
||||
, imageUrl = imageUrl.value
|
||||
}
|
||||
)
|
||||
(\info name description price imageUrl ->
|
||||
let
|
||||
errors field =
|
||||
info.errors
|
||||
|> Dict.get field.name
|
||||
|> Maybe.withDefault []
|
||||
|
||||
errorsView field =
|
||||
(if field.status == Pages.Form.Blurred || True then
|
||||
field
|
||||
|> errors
|
||||
|> List.map (\error -> Html.li [] [ Html.text error ])
|
||||
|
||||
else
|
||||
[]
|
||||
)
|
||||
|> Html.ul [ Attr.style "color" "red" ]
|
||||
|
||||
fieldView label field =
|
||||
Html.div []
|
||||
[ Html.label []
|
||||
[ Html.text (label ++ " ")
|
||||
, field |> FormParser.input []
|
||||
]
|
||||
, errorsView field
|
||||
]
|
||||
in
|
||||
( [ Attr.style "display" "flex"
|
||||
, Attr.style "flex-direction" "column"
|
||||
, Attr.style "gap" "20px"
|
||||
]
|
||||
, [ fieldView "Name" name
|
||||
, fieldView "Description" description
|
||||
, fieldView "Price" price
|
||||
, fieldView "Image" imageUrl
|
||||
, Html.button [] [ Html.text "Update" ]
|
||||
]
|
||||
)
|
||||
)
|
||||
|> FormParser.field "name"
|
||||
(Field.text
|
||||
|> Field.required "Required"
|
||||
|> Field.withInitialValue (\{ smoothie } -> Form.Value.string smoothie.name)
|
||||
)
|
||||
|> FormParser.field "description"
|
||||
(Field.text
|
||||
|> Field.required "Required"
|
||||
|> Field.withInitialValue (\{ smoothie } -> Form.Value.string smoothie.description)
|
||||
)
|
||||
|> FormParser.field "price"
|
||||
(Field.int { invalid = \_ -> "Invalid int" }
|
||||
|> Field.required "Required"
|
||||
|> Field.withInitialValue (\{ smoothie } -> Form.Value.int smoothie.price)
|
||||
)
|
||||
|> FormParser.field "imageUrl"
|
||||
(Field.text
|
||||
|> Field.required "Required"
|
||||
|> Field.withInitialValue (\{ smoothie } -> Form.Value.string smoothie.unsplashImage)
|
||||
)
|
||||
|
||||
|
||||
parseIgnoreErrors : ( Maybe parsed, FormParser.FieldErrors error ) -> Result (FormParser.FieldErrors error) parsed
|
||||
parseIgnoreErrors ( maybeParsed, fieldErrors ) =
|
||||
case maybeParsed of
|
||||
Just parsed ->
|
||||
Ok parsed
|
||||
|
||||
_ ->
|
||||
Err fieldErrors
|
||||
|
||||
|
||||
view :
|
||||
Maybe PageUrl
|
||||
-> Shared.Model
|
||||
-> Model
|
||||
-> StaticPayload Data ActionData RouteParams
|
||||
-> View (Pages.Msg.Msg Msg)
|
||||
view maybeUrl sharedModel model app =
|
||||
let
|
||||
pendingCreation : Result (FormParser.FieldErrors String) NewItem
|
||||
pendingCreation =
|
||||
form
|
||||
|> FormParser.runNew
|
||||
(app.pageFormState |> Dict.get "test" |> Maybe.withDefault Dict.empty)
|
||||
|> .result
|
||||
|> parseIgnoreErrors
|
||||
in
|
||||
{ title = "Update Item"
|
||||
, body =
|
||||
[ Html.h2 [] [ Html.text "Update item" ]
|
||||
, FormParser.renderHtml app form
|
||||
, pendingCreation
|
||||
|> Result.toMaybe
|
||||
|> Maybe.map pendingView
|
||||
|> Maybe.withDefault (Html.div [] [])
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
pendingView : NewItem -> Html (Pages.Msg.Msg Msg)
|
||||
pendingView item =
|
||||
Html.div [ Attr.class "item" ]
|
||||
[ Html.div []
|
||||
[ Html.h3 [] [ Html.text item.name ]
|
||||
, Html.p [] [ Html.text item.description ]
|
||||
, Html.p [] [ "$" ++ String.fromInt item.price |> Html.text ]
|
||||
]
|
||||
, Html.div []
|
||||
[ Html.img
|
||||
[ Attr.src (item.imageUrl ++ "?ixlib=rb-1.2.1&raw_url=true&q=80&fm=jpg&crop=entropy&cs=tinysrgb&auto=format&fit=crop&w=600&h=903") ]
|
||||
[]
|
||||
]
|
||||
]
|
@ -1,7 +1,8 @@
|
||||
module Data.Smoothies exposing (Smoothie, create, selection)
|
||||
module Data.Smoothies exposing (Smoothie, create, find, selection)
|
||||
|
||||
import Api.InputObject
|
||||
import Api.Mutation
|
||||
import Api.Object
|
||||
import Api.Object.Products
|
||||
import Api.Query
|
||||
import Api.Scalar exposing (Uuid(..))
|
||||
@ -21,14 +22,25 @@ type alias Smoothie =
|
||||
|
||||
selection : SelectionSet (List Smoothie) RootQuery
|
||||
selection =
|
||||
Api.Query.products identity
|
||||
(SelectionSet.map5 Smoothie
|
||||
Api.Object.Products.name
|
||||
Api.Object.Products.id
|
||||
Api.Object.Products.description
|
||||
Api.Object.Products.price
|
||||
Api.Object.Products.unsplash_image_id
|
||||
)
|
||||
Api.Query.products identity singleSelection
|
||||
|
||||
|
||||
singleSelection : SelectionSet Smoothie Api.Object.Products
|
||||
singleSelection =
|
||||
SelectionSet.map5 Smoothie
|
||||
Api.Object.Products.name
|
||||
Api.Object.Products.id
|
||||
Api.Object.Products.description
|
||||
Api.Object.Products.price
|
||||
Api.Object.Products.unsplash_image_id
|
||||
|
||||
|
||||
find : Uuid -> SelectionSet (Maybe Smoothie) RootQuery
|
||||
find id =
|
||||
Api.Query.products_by_pk
|
||||
{ id = id
|
||||
}
|
||||
singleSelection
|
||||
|
||||
|
||||
create :
|
||||
|
Loading…
Reference in New Issue
Block a user