Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
F
frontend
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
vicotor
frontend
Commits
64946979
Commit
64946979
authored
Sep 17, 2024
by
tom
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
connect email and code screens to API
parent
e2abc9e5
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
257 additions
and
28 deletions
+257
-28
resources.ts
lib/api/resources.ts
+9
-0
getErrorMessage.ts
lib/errors/getErrorMessage.ts
+6
-0
AuthModalFieldEmail.tsx
ui/snippets/auth/fields/AuthModalFieldEmail.tsx
+38
-0
AuthModalFieldOtpCode.tsx
ui/snippets/auth/fields/AuthModalFieldOtpCode.tsx
+36
-0
AuthModalScreenEmail.tsx
ui/snippets/auth/screens/AuthModalScreenEmail.tsx
+61
-10
AuthModalScreenOtpCode.tsx
ui/snippets/auth/screens/AuthModalScreenOtpCode.tsx
+98
-18
types.ts
ui/snippets/auth/types.ts
+9
-0
No files found.
lib/api/resources.ts
View file @
64946979
...
@@ -217,6 +217,15 @@ export const RESOURCES = {
...
@@ -217,6 +217,15 @@ export const RESOURCES = {
needAuth
:
true
,
needAuth
:
true
,
},
},
// AUTH
auth_send_otp
:
{
path
:
'
/api/account/v2/send_otp
'
,
},
auth_confirm_otp
:
{
path
:
'
/api/account/v2/confirm_otp
'
,
},
// STATS MICROSERVICE API
// STATS MICROSERVICE API
stats_counters
:
{
stats_counters
:
{
path
:
'
/api/v1/counters
'
,
path
:
'
/api/v1/counters
'
,
...
...
lib/errors/getErrorMessage.ts
0 → 100644
View file @
64946979
import
getErrorObj
from
'
./getErrorObj
'
;
export
default
function
getErrorMessage
(
error
:
Error
|
undefined
):
string
|
undefined
{
const
errorObj
=
getErrorObj
(
error
);
return
errorObj
&&
'
message
'
in
errorObj
&&
typeof
errorObj
.
message
===
'
string
'
?
errorObj
.
message
:
undefined
;
}
ui/snippets/auth/fields/AuthModalFieldEmail.tsx
0 → 100644
View file @
64946979
import
{
chakra
,
FormControl
,
Input
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
{
useController
,
useFormContext
}
from
'
react-hook-form
'
;
import
type
{
EmailFormFields
}
from
'
../types
'
;
import
{
EMAIL_REGEXP
}
from
'
lib/validations/email
'
;
import
InputPlaceholder
from
'
ui/shared/InputPlaceholder
'
;
interface
Props
{
className
?:
string
;
}
const
AuthModalFieldEmail
=
({
className
}:
Props
)
=>
{
const
{
control
}
=
useFormContext
<
EmailFormFields
>
();
const
{
field
,
fieldState
,
formState
}
=
useController
<
EmailFormFields
,
'
email
'
>
({
control
,
name
:
'
email
'
,
rules
:
{
required
:
true
,
pattern
:
EMAIL_REGEXP
},
});
const
isDisabled
=
formState
.
isSubmitting
;
return
(
<
FormControl
className=
{
className
}
variant=
"floating"
isDisabled=
{
isDisabled
}
isRequired
size=
"md"
>
<
Input
{
...
field
}
required
isInvalid=
{
Boolean
(
fieldState
.
error
)
}
isDisabled=
{
isDisabled
}
autoComplete=
"off"
/>
<
InputPlaceholder
text=
"Email"
error=
{
fieldState
.
error
}
/>
</
FormControl
>
);
};
export
default
React
.
memo
(
chakra
(
AuthModalFieldEmail
));
ui/snippets/auth/fields/AuthModalFieldOtpCode.tsx
0 → 100644
View file @
64946979
import
{
FormControl
,
Input
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
{
useController
,
useFormContext
}
from
'
react-hook-form
'
;
import
type
{
OtpCodeFormFields
}
from
'
../types
'
;
import
InputPlaceholder
from
'
ui/shared/InputPlaceholder
'
;
const
AuthModalFieldOtpCode
=
()
=>
{
const
{
control
}
=
useFormContext
<
OtpCodeFormFields
>
();
const
{
field
,
fieldState
,
formState
}
=
useController
<
OtpCodeFormFields
,
'
code
'
>
({
control
,
name
:
'
code
'
,
rules
:
{
required
:
true
,
minLength
:
6
,
maxLength
:
6
},
});
const
isDisabled
=
formState
.
isSubmitting
;
return
(
<
FormControl
variant=
"floating"
isDisabled=
{
isDisabled
}
isRequired
size=
"md"
>
<
Input
{
...
field
}
required
isInvalid=
{
Boolean
(
fieldState
.
error
)
}
isDisabled=
{
isDisabled
}
type=
"number"
minLength=
{
6
}
maxLength=
{
6
}
autoComplete=
"one-time-code"
/>
<
InputPlaceholder
text=
"Confirmation code"
error=
{
fieldState
.
error
}
/>
</
FormControl
>
);
};
export
default
React
.
memo
(
AuthModalFieldOtpCode
);
ui/snippets/auth/screens/AuthModalScreenEmail.tsx
View file @
64946979
import
{
Box
,
Button
,
Input
,
Text
}
from
'
@chakra-ui/react
'
;
import
{
chakra
,
Button
,
Text
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
import
type
{
SubmitHandler
}
from
'
react-hook-form
'
;
import
{
FormProvider
,
useForm
}
from
'
react-hook-form
'
;
import
type
{
Screen
}
from
'
../types
'
;
import
type
{
EmailFormFields
,
Screen
}
from
'
../types
'
;
import
useApiFetch
from
'
lib/api/useApiFetch
'
;
import
getErrorMessage
from
'
lib/errors/getErrorMessage
'
;
import
useToast
from
'
lib/hooks/useToast
'
;
import
FormFieldReCaptcha
from
'
ui/shared/forms/fields/FormFieldReCaptcha
'
;
import
AuthModalFieldEmail
from
'
../fields/AuthModalFieldEmail
'
;
interface
Props
{
interface
Props
{
onSubmit
:
(
screen
:
Screen
)
=>
void
;
onSubmit
:
(
screen
:
Screen
)
=>
void
;
...
@@ -9,16 +18,58 @@ interface Props {
...
@@ -9,16 +18,58 @@ interface Props {
const
AuthModalScreenEmail
=
({
onSubmit
}:
Props
)
=>
{
const
AuthModalScreenEmail
=
({
onSubmit
}:
Props
)
=>
{
const
handleSubmitClick
=
React
.
useCallback
(()
=>
{
const
apiFetch
=
useApiFetch
();
onSubmit
({
type
:
'
otp_code
'
,
email
:
'
tom@ohhhh.me
'
});
const
toast
=
useToast
();
},
[
onSubmit
]);
const
formApi
=
useForm
<
EmailFormFields
>
({
mode
:
'
onBlur
'
,
defaultValues
:
{
email
:
''
,
},
});
const
onFormSubmit
:
SubmitHandler
<
EmailFormFields
>
=
React
.
useCallback
((
formData
)
=>
{
return
apiFetch
(
'
auth_send_otp
'
,
{
fetchParams
:
{
method
:
'
POST
'
,
body
:
{
email
:
formData
.
email
,
recaptcha_response
:
formData
.
reCaptcha
,
},
},
})
.
then
(()
=>
{
onSubmit
({
type
:
'
otp_code
'
,
email
:
formData
.
email
});
})
.
catch
((
error
)
=>
{
toast
({
status
:
'
error
'
,
title
:
'
Error
'
,
description
:
getErrorMessage
(
error
)
||
'
Something went wrong
'
,
});
});
},
[
apiFetch
,
onSubmit
,
toast
]);
return
(
return
(
<
Box
>
<
FormProvider
{
...
formApi
}
>
<
Text
>
Account email, used for transaction notifications from your watchlist.
</
Text
>
<
chakra
.
form
<
Input
placeholder=
"Email"
mt=
{
6
}
/>
noValidate
<
Button
mt=
{
6
}
onClick=
{
handleSubmitClick
}
>
Send a code
</
Button
>
onSubmit=
{
formApi
.
handleSubmit
(
onFormSubmit
)
}
</
Box
>
>
<
Text
>
Account email, used for transaction notifications from your watchlist.
</
Text
>
<
AuthModalFieldEmail
mt=
{
6
}
mb=
{
3
}
/>
<
FormFieldReCaptcha
/>
<
Button
mt=
{
6
}
type=
"submit"
isDisabled=
{
formApi
.
formState
.
isSubmitting
||
!
formApi
.
formState
.
isValid
}
isLoading=
{
formApi
.
formState
.
isSubmitting
}
loadingText=
"Send a code"
>
Send a code
</
Button
>
</
chakra
.
form
>
</
FormProvider
>
);
);
};
};
...
...
ui/snippets/auth/screens/AuthModalScreenOtpCode.tsx
View file @
64946979
import
{
chakra
,
Box
,
Text
,
Input
,
Button
,
Link
}
from
'
@chakra-ui/react
'
;
import
{
chakra
,
Box
,
Text
,
Button
,
Link
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
import
type
{
SubmitHandler
}
from
'
react-hook-form
'
;
import
{
FormProvider
,
useForm
}
from
'
react-hook-form
'
;
import
type
{
Screen
}
from
'
../types
'
;
import
type
{
OtpCodeFormFields
,
Screen
}
from
'
../types
'
;
import
useApiFetch
from
'
lib/api/useApiFetch
'
;
import
getErrorMessage
from
'
lib/errors/getErrorMessage
'
;
import
useToast
from
'
lib/hooks/useToast
'
;
import
IconSvg
from
'
ui/shared/IconSvg
'
;
import
IconSvg
from
'
ui/shared/IconSvg
'
;
import
AuthModalFieldOtpCode
from
'
../fields/AuthModalFieldOtpCode
'
;
interface
Props
{
interface
Props
{
email
:
string
;
email
:
string
;
onSubmit
:
(
screen
:
Screen
)
=>
void
;
onSubmit
:
(
screen
:
Screen
)
=>
void
;
...
@@ -12,24 +19,97 @@ interface Props {
...
@@ -12,24 +19,97 @@ interface Props {
const
AuthModalScreenOtpCode
=
({
email
,
onSubmit
}:
Props
)
=>
{
const
AuthModalScreenOtpCode
=
({
email
,
onSubmit
}:
Props
)
=>
{
const
handleSubmitClick
=
React
.
useCallback
(()
=>
{
const
apiFetch
=
useApiFetch
();
onSubmit
({
type
:
'
success_created_email
'
});
const
toast
=
useToast
();
},
[
onSubmit
]);
const
formApi
=
useForm
<
OtpCodeFormFields
>
({
mode
:
'
onBlur
'
,
defaultValues
:
{
code
:
''
,
},
});
const
onFormSubmit
:
SubmitHandler
<
OtpCodeFormFields
>
=
React
.
useCallback
((
formData
)
=>
{
return
apiFetch
(
'
auth_confirm_otp
'
,
{
fetchParams
:
{
method
:
'
POST
'
,
body
:
{
otp
:
formData
.
code
,
email
,
},
},
})
.
then
(()
=>
{
onSubmit
({
type
:
'
success_created_email
'
});
})
.
catch
((
error
)
=>
{
// TODO @tom2drum handle incorrect code error
toast
({
status
:
'
error
'
,
title
:
'
Error
'
,
description
:
getErrorMessage
(
error
)
||
'
Something went wrong
'
,
});
});
},
[
apiFetch
,
email
,
onSubmit
,
toast
]);
const
handleResendCodeClick
=
React
.
useCallback
(()
=>
{
return
apiFetch
(
'
auth_send_otp
'
,
{
fetchParams
:
{
method
:
'
POST
'
,
body
:
{
email
,
},
},
})
.
then
(()
=>
{
toast
({
status
:
'
success
'
,
title
:
'
Code sent
'
,
description
:
'
Code has been sent to your email
'
,
});
})
.
catch
((
error
)
=>
{
toast
({
status
:
'
error
'
,
title
:
'
Error
'
,
description
:
getErrorMessage
(
error
)
||
'
Something went wrong
'
,
});
});
},
[
apiFetch
,
email
,
toast
]);
return
(
return
(
<
Box
>
<
FormProvider
{
...
formApi
}
>
<
Text
>
<
chakra
.
form
Please check
{
'
'
}
noValidate
<
chakra
.
span
fontWeight=
"700"
>
{
email
}
</
chakra
.
span
>
{
'
'
}
onSubmit=
{
formApi
.
handleSubmit
(
onFormSubmit
)
}
and enter your code below.
>
</
Text
>
<
Text
mb=
{
6
}
>
<
Input
placeholder=
"Confirmation code"
mt=
{
6
}
/>
Please check
{
'
'
}
<
Link
display=
"flex"
alignItems=
"center"
gap=
{
2
}
mt=
{
3
}
w=
"fit-content"
>
<
chakra
.
span
fontWeight=
"700"
>
{
email
}
</
chakra
.
span
>
{
'
'
}
<
IconSvg
name=
"repeat"
boxSize=
{
5
}
/>
and enter your code below.
<
Box
fontSize=
"sm"
>
Resend code
</
Box
>
</
Text
>
</
Link
>
<
AuthModalFieldOtpCode
/>
<
Button
mt=
{
6
}
onClick=
{
handleSubmitClick
}
>
Submit
</
Button
>
<
Link
</
Box
>
display=
"flex"
alignItems=
"center"
gap=
{
2
}
mt=
{
3
}
w=
"fit-content"
onClick=
{
handleResendCodeClick
}
>
<
IconSvg
name=
"repeat"
boxSize=
{
5
}
/>
<
Box
fontSize=
"sm"
>
Resend code
</
Box
>
</
Link
>
<
Button
mt=
{
6
}
type=
"submit"
isLoading=
{
formApi
.
formState
.
isSubmitting
}
onClick=
{
formApi
.
handleSubmit
(
onFormSubmit
)
}
>
Submit
</
Button
>
</
chakra
.
form
>
</
FormProvider
>
);
);
};
};
...
...
ui/snippets/auth/types.ts
View file @
64946979
...
@@ -8,3 +8,12 @@ export type Screen = {
...
@@ -8,3 +8,12 @@ export type Screen = {
}
|
{
}
|
{
type
:
'
success_created_email
'
;
type
:
'
success_created_email
'
;
}
}
export
interface
EmailFormFields
{
email
:
string
;
reCaptcha
:
string
;
}
export
interface
OtpCodeFormFields
{
code
:
string
;
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment