mirror of
https://github.com/dillonkearns/elm-pages-v3-beta.git
synced 2024-12-26 13:21:42 +03:00
Add new smoothie route.
This commit is contained in:
parent
a35f51600a
commit
7f5e4f9266
264
examples/smoothies/app/Route/New.elm
Normal file
264
examples/smoothies/app/Route/New.elm
Normal file
@ -0,0 +1,264 @@
|
||||
module Route.New exposing (ActionData, Data, Model, Msg, route)
|
||||
|
||||
import Api.Scalar exposing (Uuid(..))
|
||||
import Data.Smoothies as Smoothies
|
||||
import DataSource exposing (DataSource)
|
||||
import Dict
|
||||
import Dict.Extra
|
||||
import Effect exposing (Effect)
|
||||
import ErrorPage exposing (ErrorPage)
|
||||
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 =
|
||||
{}
|
||||
|
||||
|
||||
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
|
||||
|
||||
|
||||
type alias Data =
|
||||
{}
|
||||
|
||||
|
||||
type alias ActionData =
|
||||
{}
|
||||
|
||||
|
||||
data : RouteParams -> Request.Parser (DataSource (Response Data ErrorPage))
|
||||
data routeParams =
|
||||
Request.succeed (DataSource.succeed (Response.render Data))
|
||||
|
||||
|
||||
action : RouteParams -> Request.Parser (DataSource (Response ActionData ErrorPage))
|
||||
action routeParams =
|
||||
Request.map2 Tuple.pair
|
||||
(Request.formParserResultNew form)
|
||||
Request.requestTime
|
||||
|> MySession.expectSessionDataOrRedirect (Session.get "userId" >> Maybe.map Uuid)
|
||||
(\userId ( parsed, requestTime ) session ->
|
||||
case parsed of
|
||||
Ok okParsed ->
|
||||
Smoothies.create okParsed
|
||||
|> Request.Hasura.mutationDataSource requestTime
|
||||
|> DataSource.map
|
||||
(\_ ->
|
||||
( session
|
||||
, Route.redirectTo Route.Index
|
||||
)
|
||||
)
|
||||
|
||||
Err errors ->
|
||||
DataSource.succeed
|
||||
-- TODO need to render errors here
|
||||
( session, Response.render {} )
|
||||
)
|
||||
|
||||
|
||||
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 "Create" ]
|
||||
]
|
||||
)
|
||||
)
|
||||
|> FormParser.field "name" (Field.text |> Field.required "Required")
|
||||
|> FormParser.field "description" (Field.text |> Field.required "Required")
|
||||
|> FormParser.field "price" (Field.int { invalid = \_ -> "Invalid int" } |> Field.required "Required")
|
||||
|> FormParser.field "imageUrl" (Field.text |> Field.required "Required")
|
||||
|
||||
|
||||
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 = "New Item"
|
||||
, body =
|
||||
[ Html.h2 [] [ Html.text "New item" ]
|
||||
, FormParser.renderHtml app form
|
||||
, pendingCreation
|
||||
|> Debug.log "pendingCreation"
|
||||
|> Result.toMaybe
|
||||
|> Maybe.map pendingView
|
||||
|> Maybe.withDefault (Html.div [] [])
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
type alias NewItem =
|
||||
{ name : String, description : String, price : Int, imageUrl : String }
|
||||
|
||||
|
||||
toResult : ( Maybe parsed, FormParser.FieldErrors error ) -> Result (FormParser.FieldErrors error) parsed
|
||||
toResult ( maybeParsed, fieldErrors ) =
|
||||
let
|
||||
isEmptyDict : Bool
|
||||
isEmptyDict =
|
||||
if Dict.isEmpty fieldErrors then
|
||||
True
|
||||
|
||||
else
|
||||
fieldErrors
|
||||
|> Dict.Extra.any (\_ errors -> List.isEmpty errors)
|
||||
in
|
||||
case ( maybeParsed, isEmptyDict ) of
|
||||
( Just parsed, True ) ->
|
||||
Ok parsed
|
||||
|
||||
_ ->
|
||||
Err fieldErrors
|
||||
|
||||
|
||||
parseIgnoreErrors : ( Maybe parsed, FormParser.FieldErrors error ) -> Result (FormParser.FieldErrors error) parsed
|
||||
parseIgnoreErrors ( maybeParsed, fieldErrors ) =
|
||||
case maybeParsed of
|
||||
Just parsed ->
|
||||
Ok parsed
|
||||
|
||||
_ ->
|
||||
Err fieldErrors
|
||||
|
||||
|
||||
pendingView : NewItem -> Html (Pages.Msg.Msg Msg)
|
||||
pendingView item =
|
||||
Html.div [ Attr.class "item" ]
|
||||
[ Html.h2 [] [ Html.text "Preview" ]
|
||||
, 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,9 +1,12 @@
|
||||
module Data.Smoothies exposing (Smoothie, selection)
|
||||
module Data.Smoothies exposing (Smoothie, create, selection)
|
||||
|
||||
import Api.InputObject
|
||||
import Api.Mutation
|
||||
import Api.Object.Products
|
||||
import Api.Query
|
||||
import Api.Scalar exposing (Uuid(..))
|
||||
import Graphql.Operation exposing (RootQuery)
|
||||
import Graphql.Operation exposing (RootMutation, RootQuery)
|
||||
import Graphql.OptionalArgument exposing (OptionalArgument(..))
|
||||
import Graphql.SelectionSet as SelectionSet exposing (SelectionSet)
|
||||
|
||||
|
||||
@ -26,3 +29,23 @@ selection =
|
||||
Api.Object.Products.price
|
||||
Api.Object.Products.unsplash_image_id
|
||||
)
|
||||
|
||||
|
||||
create :
|
||||
{ name : String, description : String, price : Int, imageUrl : String }
|
||||
-> SelectionSet () RootMutation
|
||||
create item =
|
||||
Api.Mutation.insert_products_one identity
|
||||
{ object =
|
||||
Api.InputObject.buildProducts_insert_input
|
||||
(\opts ->
|
||||
{ opts
|
||||
| name = Present item.name
|
||||
, description = Present item.description
|
||||
, price = Present item.price
|
||||
, unsplash_image_id = Present item.imageUrl
|
||||
}
|
||||
)
|
||||
}
|
||||
SelectionSet.empty
|
||||
|> SelectionSet.nonNullOrFail
|
||||
|
@ -152,6 +152,7 @@ type CompleteParser error parsed
|
||||
= CompleteParser
|
||||
|
||||
|
||||
input : List (Html.Attribute msg) -> RawField -> Html msg
|
||||
input attrs rawField =
|
||||
Html.input
|
||||
(attrs
|
||||
|
Loading…
Reference in New Issue
Block a user