Support Admins inviting users from the client
The title says it all.
This commit is contained in:
parent
a3d783025a
commit
1d5cf2e4b5
2 changed files with 139 additions and 1 deletions
|
@ -5,6 +5,7 @@ import Date
|
||||||
import Html exposing (..)
|
import Html exposing (..)
|
||||||
import Html.Attributes exposing (..)
|
import Html.Attributes exposing (..)
|
||||||
import Html.Events exposing (..)
|
import Html.Events exposing (..)
|
||||||
|
import Maybe.Extra as ME
|
||||||
import RemoteData
|
import RemoteData
|
||||||
import State
|
import State
|
||||||
import Tailwind
|
import Tailwind
|
||||||
|
@ -12,6 +13,59 @@ import UI
|
||||||
import Utils
|
import Utils
|
||||||
|
|
||||||
|
|
||||||
|
roleToggle : State.Model -> State.Role -> Html State.Msg
|
||||||
|
roleToggle model role =
|
||||||
|
div [ [ "px-1", "inline" ] |> Tailwind.use |> class ]
|
||||||
|
[ UI.toggleButton
|
||||||
|
{ toggled = model.inviteRole == Just role
|
||||||
|
, label = State.roleToString role
|
||||||
|
, handleEnable = State.UpdateInviteRole (Just role)
|
||||||
|
, handleDisable = State.UpdateInviteRole Nothing
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
inviteUser : State.Model -> Html State.Msg
|
||||||
|
inviteUser model =
|
||||||
|
div [ [ "pb-6" ] |> Tailwind.use |> class ]
|
||||||
|
[ UI.header 3 "Invite a user"
|
||||||
|
, UI.textField
|
||||||
|
{ handleInput = State.UpdateInviteEmail
|
||||||
|
, inputId = "invite-email"
|
||||||
|
, inputValue = model.inviteEmail
|
||||||
|
, pholder = "Email..."
|
||||||
|
}
|
||||||
|
, div [ [ "pt-4" ] |> Tailwind.use |> class ]
|
||||||
|
[ roleToggle model State.User
|
||||||
|
, roleToggle model State.Manager
|
||||||
|
, roleToggle model State.Admin
|
||||||
|
]
|
||||||
|
, UI.baseButton
|
||||||
|
{ enabled =
|
||||||
|
List.all
|
||||||
|
identity
|
||||||
|
[ String.length model.inviteEmail > 0
|
||||||
|
, ME.isJust model.inviteRole
|
||||||
|
]
|
||||||
|
, extraClasses = [ "my-4" ]
|
||||||
|
, label =
|
||||||
|
case model.inviteResponseStatus of
|
||||||
|
RemoteData.Loading ->
|
||||||
|
"Sending..."
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
"Send invitation"
|
||||||
|
, handleClick =
|
||||||
|
case model.inviteRole of
|
||||||
|
Nothing ->
|
||||||
|
State.DoNothing
|
||||||
|
|
||||||
|
Just role ->
|
||||||
|
State.AttemptInviteUser role
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
allTrips : State.Model -> Html State.Msg
|
allTrips : State.Model -> Html State.Msg
|
||||||
allTrips model =
|
allTrips model =
|
||||||
case model.trips of
|
case model.trips of
|
||||||
|
@ -124,7 +178,10 @@ render model =
|
||||||
]
|
]
|
||||||
, case model.adminTab of
|
, case model.adminTab of
|
||||||
State.Accounts ->
|
State.Accounts ->
|
||||||
allUsers model
|
div []
|
||||||
|
[ inviteUser model
|
||||||
|
, allUsers model
|
||||||
|
]
|
||||||
|
|
||||||
State.Trips ->
|
State.Trips ->
|
||||||
allTrips model
|
allTrips model
|
||||||
|
|
|
@ -40,6 +40,9 @@ type Msg
|
||||||
| ClearErrors
|
| ClearErrors
|
||||||
| ToggleLoginForm
|
| ToggleLoginForm
|
||||||
| PrintPage
|
| PrintPage
|
||||||
|
| UpdateInviteEmail String
|
||||||
|
| UpdateInviteRole (Maybe Role)
|
||||||
|
| ReceiveTodaysDate Date.Date
|
||||||
-- SPA
|
-- SPA
|
||||||
| LinkClicked Browser.UrlRequest
|
| LinkClicked Browser.UrlRequest
|
||||||
| UrlChanged Url.Url
|
| UrlChanged Url.Url
|
||||||
|
@ -52,6 +55,7 @@ type Msg
|
||||||
| AttemptDeleteAccount String
|
| AttemptDeleteAccount String
|
||||||
| AttemptCreateTrip Date.Date Date.Date
|
| AttemptCreateTrip Date.Date Date.Date
|
||||||
| AttemptDeleteTrip Trip
|
| AttemptDeleteTrip Trip
|
||||||
|
| AttemptInviteUser Role
|
||||||
-- Inbound network
|
-- Inbound network
|
||||||
| GotAccounts (WebData (List Account))
|
| GotAccounts (WebData (List Account))
|
||||||
| GotTrips (WebData (List Trip))
|
| GotTrips (WebData (List Trip))
|
||||||
|
@ -61,6 +65,7 @@ type Msg
|
||||||
| GotDeleteAccount (Result Http.Error String)
|
| GotDeleteAccount (Result Http.Error String)
|
||||||
| GotCreateTrip (Result Http.Error ())
|
| GotCreateTrip (Result Http.Error ())
|
||||||
| GotDeleteTrip (Result Http.Error ())
|
| GotDeleteTrip (Result Http.Error ())
|
||||||
|
| GotInviteUser (Result Http.Error ())
|
||||||
|
|
||||||
|
|
||||||
type Route
|
type Route
|
||||||
|
@ -121,6 +126,7 @@ type alias Model =
|
||||||
, url : Url.Url
|
, url : Url.Url
|
||||||
, key : Nav.Key
|
, key : Nav.Key
|
||||||
, session : Maybe Session
|
, session : Maybe Session
|
||||||
|
, todaysDate : Maybe Date.Date
|
||||||
, username : String
|
, username : String
|
||||||
, email : String
|
, email : String
|
||||||
, password : String
|
, password : String
|
||||||
|
@ -135,12 +141,16 @@ type alias Model =
|
||||||
, trips : WebData (List Trip)
|
, trips : WebData (List Trip)
|
||||||
, adminTab : AdminTab
|
, adminTab : AdminTab
|
||||||
, loginTab : LoginTab
|
, loginTab : LoginTab
|
||||||
|
, inviteEmail : String
|
||||||
|
, inviteRole : Maybe Role
|
||||||
|
, inviteResponseStatus : WebData ()
|
||||||
, loginError : Maybe Http.Error
|
, loginError : Maybe Http.Error
|
||||||
, logoutError : Maybe Http.Error
|
, logoutError : Maybe Http.Error
|
||||||
, signUpError : Maybe Http.Error
|
, signUpError : Maybe Http.Error
|
||||||
, deleteUserError : Maybe Http.Error
|
, deleteUserError : Maybe Http.Error
|
||||||
, createTripError : Maybe Http.Error
|
, createTripError : Maybe Http.Error
|
||||||
, deleteTripError : Maybe Http.Error
|
, deleteTripError : Maybe Http.Error
|
||||||
|
, inviteUserError : Maybe Http.Error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -151,6 +161,7 @@ allErrors model =
|
||||||
, ( model.signUpError, "Error attempting to create your account" )
|
, ( model.signUpError, "Error attempting to create your account" )
|
||||||
, ( model.deleteUserError, "Error attempting to delete a user" )
|
, ( model.deleteUserError, "Error attempting to delete a user" )
|
||||||
, ( model.createTripError, "Error attempting to create a trip" )
|
, ( model.createTripError, "Error attempting to create a trip" )
|
||||||
|
, ( model.inviteUserError, "Error attempting to invite a user" )
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -178,6 +189,19 @@ endpoint =
|
||||||
UrlBuilder.crossOrigin Shared.serverOrigin
|
UrlBuilder.crossOrigin Shared.serverOrigin
|
||||||
|
|
||||||
|
|
||||||
|
encodeRole : Role -> JE.Value
|
||||||
|
encodeRole x =
|
||||||
|
case x of
|
||||||
|
User ->
|
||||||
|
JE.string "user"
|
||||||
|
|
||||||
|
Manager ->
|
||||||
|
JE.string "manager"
|
||||||
|
|
||||||
|
Admin ->
|
||||||
|
JE.string "admin"
|
||||||
|
|
||||||
|
|
||||||
decodeRole : JD.Decoder Role
|
decodeRole : JD.Decoder Role
|
||||||
decodeRole =
|
decodeRole =
|
||||||
let
|
let
|
||||||
|
@ -254,6 +278,21 @@ signUp { username, email, password } =
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inviteUser : { email : String, role : Role } -> Cmd Msg
|
||||||
|
inviteUser { email, role } =
|
||||||
|
Utils.postWithCredentials
|
||||||
|
{ url = endpoint [ "invite" ] []
|
||||||
|
, body =
|
||||||
|
Http.jsonBody
|
||||||
|
(JE.object
|
||||||
|
[ ( "email", JE.string email )
|
||||||
|
, ( "role", encodeRole role )
|
||||||
|
]
|
||||||
|
)
|
||||||
|
, expect = Http.expectWhatever GotInviteUser
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
createTrip :
|
createTrip :
|
||||||
{ username : String
|
{ username : String
|
||||||
, destination : String
|
, destination : String
|
||||||
|
@ -424,6 +463,7 @@ prod _ url key =
|
||||||
, url = url
|
, url = url
|
||||||
, key = key
|
, key = key
|
||||||
, session = Nothing
|
, session = Nothing
|
||||||
|
, todaysDate = Nothing
|
||||||
, username = ""
|
, username = ""
|
||||||
, email = ""
|
, email = ""
|
||||||
, password = ""
|
, password = ""
|
||||||
|
@ -438,16 +478,21 @@ prod _ url key =
|
||||||
, endDatePicker = endDatePicker
|
, endDatePicker = endDatePicker
|
||||||
, adminTab = Accounts
|
, adminTab = Accounts
|
||||||
, loginTab = LoginForm
|
, loginTab = LoginForm
|
||||||
|
, inviteEmail = ""
|
||||||
|
, inviteRole = Nothing
|
||||||
|
, inviteResponseStatus = RemoteData.NotAsked
|
||||||
, loginError = Nothing
|
, loginError = Nothing
|
||||||
, logoutError = Nothing
|
, logoutError = Nothing
|
||||||
, signUpError = Nothing
|
, signUpError = Nothing
|
||||||
, deleteUserError = Nothing
|
, deleteUserError = Nothing
|
||||||
, createTripError = Nothing
|
, createTripError = Nothing
|
||||||
, deleteTripError = Nothing
|
, deleteTripError = Nothing
|
||||||
|
, inviteUserError = Nothing
|
||||||
}
|
}
|
||||||
, Cmd.batch
|
, Cmd.batch
|
||||||
[ Cmd.map UpdateTripStartDate startDatePickerCmd
|
[ Cmd.map UpdateTripStartDate startDatePickerCmd
|
||||||
, Cmd.map UpdateTripEndDate endDatePickerCmd
|
, Cmd.map UpdateTripEndDate endDatePickerCmd
|
||||||
|
, Date.today |> Task.perform ReceiveTodaysDate
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -632,6 +677,15 @@ update msg model =
|
||||||
PrintPage ->
|
PrintPage ->
|
||||||
( model, printPage () )
|
( model, printPage () )
|
||||||
|
|
||||||
|
UpdateInviteEmail x ->
|
||||||
|
( { model | inviteEmail = x }, Cmd.none )
|
||||||
|
|
||||||
|
UpdateInviteRole mRole ->
|
||||||
|
( { model | inviteRole = mRole }, Cmd.none )
|
||||||
|
|
||||||
|
ReceiveTodaysDate date ->
|
||||||
|
( { model | todaysDate = Just date }, Cmd.none )
|
||||||
|
|
||||||
LinkClicked urlRequest ->
|
LinkClicked urlRequest ->
|
||||||
case urlRequest of
|
case urlRequest of
|
||||||
Browser.Internal url ->
|
Browser.Internal url ->
|
||||||
|
@ -766,6 +820,33 @@ update msg model =
|
||||||
, sleepAndClearErrors
|
, sleepAndClearErrors
|
||||||
)
|
)
|
||||||
|
|
||||||
|
AttemptInviteUser role ->
|
||||||
|
( { model | inviteResponseStatus = RemoteData.Loading }
|
||||||
|
, inviteUser
|
||||||
|
{ email = model.inviteEmail
|
||||||
|
, role = role
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
GotInviteUser result ->
|
||||||
|
case result of
|
||||||
|
Ok _ ->
|
||||||
|
( { model
|
||||||
|
| inviteEmail = ""
|
||||||
|
, inviteRole = Nothing
|
||||||
|
, inviteResponseStatus = RemoteData.Success ()
|
||||||
|
}
|
||||||
|
, Cmd.none
|
||||||
|
)
|
||||||
|
|
||||||
|
Err x ->
|
||||||
|
( { model
|
||||||
|
| inviteUserError = Just x
|
||||||
|
, inviteResponseStatus = RemoteData.Failure x
|
||||||
|
}
|
||||||
|
, sleepAndClearErrors
|
||||||
|
)
|
||||||
|
|
||||||
-- POST /accounts
|
-- POST /accounts
|
||||||
AttemptSignUp ->
|
AttemptSignUp ->
|
||||||
( model
|
( model
|
||||||
|
|
Loading…
Reference in a new issue