Support Admins inviting users from the client

The title says it all.
This commit is contained in:
William Carroll 2020-08-02 18:02:15 +01:00
parent a3d783025a
commit 1d5cf2e4b5
2 changed files with 139 additions and 1 deletions

View file

@ -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

View file

@ -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