3 files changed,
89 insertions(+),
30 deletions(-)
Author:
Smirnov Oleksandr
ss2316544@gmail.com
Committed by:
GitHub
noreply@github.com
Committed at:
2025-06-21 14:53:11 +0300
Parent:
dfbb8b4
jump to
| M | web/src/Api/Auth.elm |
| M | web/src/Effect.elm |
| M | web/src/Pages/Auth.elm |
M
web/src/Api/Auth.elm
@@ -1,4 +1,4 @@
-module Api.Auth exposing (refreshToken, signin, signup) +module Api.Auth exposing (refreshToken, resendVerificationEmail, signin, signup) import Api import Data.Credentials as Credentials exposing (Credentials)@@ -75,3 +75,27 @@ , body = Http.jsonBody body
, onResponse = options.onResponse , decoder = Credentials.decode } + + +resendVerificationEmail : + { onResponse : Result Api.Error () -> msg + , email : String + , password : String + } + -> Effect msg +resendVerificationEmail options = + let + body : Encode.Value + body = + Encode.object + [ ( "email", Encode.string options.email ) + , ( "password", Encode.string options.password ) + ] + in + Effect.sendApiRequest + { endpoint = "/api/v1/auth/resend-verification-email" + , method = "POST" + , body = Http.jsonBody body + , onResponse = options.onResponse + , decoder = Decode.succeed () + }
M
web/src/Effect.elm
@@ -176,20 +176,22 @@ }
-> Effect msg sendApiRequest opts = let - onSuccess : value -> msg - onSuccess value = - opts.onResponse (Ok value) - onHttpError : Api.Error -> msg onHttpError err = opts.onResponse (Err err) + + decoder : Json.Decode.Decoder msg + decoder = + opts.decoder + |> Json.Decode.map Ok + |> Json.Decode.map opts.onResponse in SendApiRequest { endpoint = opts.endpoint , method = opts.method , body = opts.body , onHttpError = onHttpError - , decoder = Json.Decode.map onSuccess opts.decoder + , decoder = decoder }@@ -353,12 +355,20 @@ fromHttpResponseToCustomError : Json.Decode.Decoder msg -> Http.Response String -> Result Api.Error msg
fromHttpResponseToCustomError decoder response = case response of Http.GoodStatus_ _ body -> - case Json.Decode.decodeString decoder body of - Ok data -> - Ok data + case + Json.Decode.decodeString decoder + (if String.isEmpty body then + "\"\"" + + else + body + ) + of + Ok value -> + Ok value Err err -> - Err (Api.JsonDecodeError { message = "Something unexpected happened", reason = err }) + Err (Api.JsonDecodeError { message = "Failed to decode JSON response", reason = err }) Http.BadStatus_ { statusCode } body -> case Json.Decode.decodeString Data.Error.decode body of
M
web/src/Pages/Auth.elm
@@ -37,7 +37,8 @@ , password : String
, passwordAgain : String , isSubmittingForm : Bool , formVariant : Variant - , error : Maybe Api.Error + , gotSignedUp : Bool + , apiError : Maybe Api.Error }@@ -48,16 +49,14 @@ , email = ""
, password = "" , passwordAgain = "" , formVariant = SignIn - , error = Nothing + , apiError = Nothing + , gotSignedUp = False } , case shared.user of Auth.User.SignedIn _ -> Effect.pushRoutePath Route.Path.Home_ - Auth.User.NotSignedIn -> - Effect.none - - Auth.User.RefreshingTokens -> + _ -> Effect.none )@@ -70,8 +69,10 @@ type Msg
= UserUpdatedInput Field String | UserChangedFormVariant Variant | UserClickedSubmit + | UserClickedResendActivationEmail | ApiSignInResponded (Result Api.Error Credentials) | ApiSignUpResponded (Result Api.Error ()) + | ApiResendVerificationEmail (Result Api.Error ()) type Field@@ -89,7 +90,7 @@ update : Msg -> Model -> ( Model, Effect Msg )
update msg model = case msg of UserClickedSubmit -> - ( { model | isSubmittingForm = True } + ( { model | isSubmittingForm = True, apiError = Nothing } , case model.formVariant of SignIn -> Api.Auth.signin@@ -106,6 +107,15 @@ , password = model.password
} ) + UserClickedResendActivationEmail -> + ( model + , Api.Auth.resendVerificationEmail + { onResponse = ApiResendVerificationEmail + , email = model.email + , password = model.password + } + ) + UserChangedFormVariant variant -> ( { model | formVariant = variant }, Effect.none )@@ -119,19 +129,22 @@ UserUpdatedInput PasswordAgain passwordAgain ->
( { model | passwordAgain = passwordAgain }, Effect.none ) ApiSignInResponded (Ok credentials) -> - ( { model | isSubmittingForm = False } - , Effect.signin credentials - ) + ( { model | isSubmittingForm = False }, Effect.signin credentials ) ApiSignInResponded (Err error) -> - ( { model | isSubmittingForm = False, error = Just error }, Effect.none ) + ( { model | isSubmittingForm = False, apiError = Just error }, Effect.none ) ApiSignUpResponded (Ok ()) -> - -- TODO: show banner with that they have to activate account - ( { model | isSubmittingForm = False }, Effect.none ) + ( { model | isSubmittingForm = False, gotSignedUp = True }, Effect.none ) ApiSignUpResponded (Err error) -> - ( { model | isSubmittingForm = False, error = Just error }, Effect.none ) + ( { model | isSubmittingForm = False, apiError = Just error }, Effect.none ) + + ApiResendVerificationEmail (Ok ()) -> + ( { model | apiError = Nothing }, Effect.none ) + + ApiResendVerificationEmail (Err err) -> + ( { model | apiError = Just err }, Effect.none )@@ -153,7 +166,7 @@ { title = "Authentication"
, body = [ Html.div [ Attr.class "center" ] -- TODO: add oauth buttons - [ viewError model.error + [ viewBanner model.apiError model.gotSignedUp , viewChangeVariant model.formVariant , viewForm model , viewForgotPassword@@ -197,16 +210,28 @@ ]
) -viewError : Maybe Api.Error -> Html Msg -viewError maybeError = - case maybeError of - Just error -> +viewBanner : Maybe Api.Error -> Bool -> Html Msg +viewBanner maybeError gotSignedUp = + case ( maybeError, gotSignedUp ) of + ( Just error, _ ) -> Html.div [ Attr.class "box bad" ] [ Html.strong [ Attr.class "block titlebar" ] [ Html.text "Error" ] , Html.text (Api.errorMessage error) ] - Nothing -> + ( Nothing, True ) -> + Html.div [ Attr.class "box ok" ] + [ Html.strong [ Attr.class "block titlebar" ] [ Html.text "Successfully signed up!" ] + , Html.p [] + [ Html.text "Please check your email to activate your account." + , Html.text " If you don't see the email, please check your spam folder." + , Html.button [ Html.Events.onClick UserClickedResendActivationEmail ] + [ Html.text "Resend activation email" + ] + ] + ] + + ( Nothing, False ) -> Html.text ""