mirror of
https://github.com/vercel/commerce.git
synced 2025-07-22 20:26:49 +00:00
✨ feat: login
:%s
This commit is contained in:
@@ -2,10 +2,10 @@ import { Layout } from 'src/components/common'
|
|||||||
import { useMessage } from 'src/components/contexts'
|
import { useMessage } from 'src/components/contexts'
|
||||||
|
|
||||||
export default function Test() {
|
export default function Test() {
|
||||||
const { showMessageSuccess } = useMessage()
|
const { showMessageError } = useMessage()
|
||||||
|
|
||||||
const handleClick = () => {
|
const handleClick = () => {
|
||||||
showMessageSuccess("Create account successfully")
|
showMessageError("Create account successfully")
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@@ -63,10 +63,14 @@ const InputFiledInForm = forwardRef<Ref, Props>(({
|
|||||||
return <></>
|
return <></>
|
||||||
}, [icon, error, isShowIconSuccess])
|
}, [icon, error, isShowIconSuccess])
|
||||||
|
|
||||||
const handleKeyDown = (e: any) => {
|
const handleKeyDown = (e: React.KeyboardEvent) => {
|
||||||
if (e.key === KEY.ENTER && onEnter) {
|
if (e.key === KEY.ENTER) {
|
||||||
const value = inputElementRef.current?.value || ''
|
e.stopPropagation()
|
||||||
onEnter(value)
|
e.preventDefault()
|
||||||
|
if (onEnter) {
|
||||||
|
const value = inputElementRef.current?.value || ''
|
||||||
|
onEnter(value)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -14,6 +14,7 @@ const MessageCommon = memo(({ messages, onRemove }: Props) => {
|
|||||||
<MessageItem
|
<MessageItem
|
||||||
key={item.id}
|
key={item.id}
|
||||||
id={item.id}
|
id={item.id}
|
||||||
|
type={item.type}
|
||||||
content={item.content}
|
content={item.content}
|
||||||
onRemove={onRemove}
|
onRemove={onRemove}
|
||||||
/>
|
/>
|
||||||
|
@@ -4,12 +4,11 @@
|
|||||||
@apply shadow-sm flex justify-center items-center cursor-default;
|
@apply shadow-sm flex justify-center items-center cursor-default;
|
||||||
width: fit-content;
|
width: fit-content;
|
||||||
padding: 0.8rem 2.4rem;
|
padding: 0.8rem 2.4rem;
|
||||||
margin-bottom: .8rem;
|
margin: 0 auto .8rem;
|
||||||
border-radius: 0.8rem;
|
border-radius: 0.8rem;
|
||||||
transition: all .5s;
|
transition: all .5s;
|
||||||
animation: showMessage .5s;
|
animation: showMessage .5s;
|
||||||
width: max-content;
|
width: max-content;
|
||||||
margin: 0 1.6rem;
|
|
||||||
|
|
||||||
&.hide {
|
&.hide {
|
||||||
display: none;
|
display: none;
|
||||||
|
@@ -40,7 +40,7 @@ const MessageItem = memo(
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isHide && !isMouseOver && onRemove) {
|
if (isHide && !isMouseOver && onRemove) {
|
||||||
onRemove(id || 0)
|
// onRemove(id || 0)
|
||||||
}
|
}
|
||||||
}, [isHide, isMouseOver, onRemove, id])
|
}, [isHide, isMouseOver, onRemove, id])
|
||||||
|
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
@import '../../../../styles/utilities';
|
@import '../../../../styles/utilities';
|
||||||
|
|
||||||
.formAuthen {
|
.formAuthen {
|
||||||
@apply bg-white w-full u-form;
|
@apply bg-white w-full;
|
||||||
.inner {
|
.inner {
|
||||||
@screen md {
|
@screen md {
|
||||||
width: 60rem;
|
width: 60rem;
|
||||||
|
@@ -1,9 +1,13 @@
|
|||||||
|
import { Form, Formik } from 'formik'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import React, { useEffect, useRef, useState } from 'react'
|
import React, { useEffect, useRef, useState } from 'react'
|
||||||
import { ButtonCommon, Inputcommon, InputPassword } from 'src/components/common'
|
import { ButtonCommon, Inputcommon, InputFiledInForm, InputPassword, InputPasswordFiledInForm } from 'src/components/common'
|
||||||
import { ROUTE } from 'src/utils/constanst.utils'
|
import { useMessage } from 'src/components/contexts'
|
||||||
import { CustomInputCommon } from 'src/utils/type.utils'
|
|
||||||
import useLogin from 'src/components/hooks/useLogin'
|
import useLogin from 'src/components/hooks/useLogin'
|
||||||
|
import { ROUTE } from 'src/utils/constanst.utils'
|
||||||
|
import { LANGUAGE } from 'src/utils/language.utils'
|
||||||
|
import { CustomInputCommon } from 'src/utils/type.utils'
|
||||||
|
import * as Yup from 'yup'
|
||||||
import s from '../FormAuthen.module.scss'
|
import s from '../FormAuthen.module.scss'
|
||||||
import SocialAuthen from '../SocialAuthen/SocialAuthen'
|
import SocialAuthen from '../SocialAuthen/SocialAuthen'
|
||||||
import styles from './FormLogin.module.scss'
|
import styles from './FormLogin.module.scss'
|
||||||
@@ -13,15 +17,17 @@ interface Props {
|
|||||||
onSwitch: () => void
|
onSwitch: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const DisplayingErrorMessagesSchema = Yup.object().shape({
|
||||||
|
email: Yup.string().email('Your email was wrong').required('Required'),
|
||||||
|
password: Yup.string()
|
||||||
|
.max(30, 'Password is too long')
|
||||||
|
.required('Required'),
|
||||||
|
})
|
||||||
|
|
||||||
const FormLogin = ({ onSwitch, isHide }: Props) => {
|
const FormLogin = ({ onSwitch, isHide }: Props) => {
|
||||||
const emailRef = useRef<CustomInputCommon>(null)
|
const emailRef = useRef<CustomInputCommon>(null)
|
||||||
const { loading, login, error } = useLogin()
|
const { loading, login } = useLogin()
|
||||||
const [email, setEmail] = useState('')
|
const { showMessageSuccess, showMessageError } = useMessage()
|
||||||
const [password, setPassword] = useState('')
|
|
||||||
|
|
||||||
const onLogin = () => {
|
|
||||||
login({ username: email, password })
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isHide) {
|
if (!isHide) {
|
||||||
@@ -29,42 +35,71 @@ const FormLogin = ({ onSwitch, isHide }: Props) => {
|
|||||||
}
|
}
|
||||||
}, [isHide])
|
}, [isHide])
|
||||||
|
|
||||||
useEffect(() => {
|
const onLogin = (values: { email: string; password: string }) => {
|
||||||
if (error) {
|
login({ username: values.email, password: values.password }, onLoginCallBack)
|
||||||
alert(error.message)
|
}
|
||||||
|
|
||||||
|
const onLoginCallBack = (isSuccess: boolean, message?: string) => {
|
||||||
|
if (isSuccess) {
|
||||||
|
showMessageSuccess("Login successfully!", 4000)
|
||||||
|
} else {
|
||||||
|
showMessageError(message || LANGUAGE.MESSAGE.ERROR)
|
||||||
}
|
}
|
||||||
}, [error])
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className={s.formAuthen}>
|
<section className={s.formAuthen}>
|
||||||
<div className={s.inner}>
|
<div className={s.inner}>
|
||||||
<div className={s.body}>
|
<div className={s.body}>
|
||||||
<Inputcommon
|
<Formik
|
||||||
placeholder="Email Address"
|
initialValues={{
|
||||||
value={email}
|
password: '',
|
||||||
onChange={(val) => setEmail(val.toString())}
|
email: '',
|
||||||
type="email"
|
}}
|
||||||
ref={emailRef}
|
validationSchema={DisplayingErrorMessagesSchema}
|
||||||
/>
|
onSubmit={onLogin}
|
||||||
|
|
||||||
|
>
|
||||||
|
{({ errors, touched, isValid, submitForm }) => (
|
||||||
|
<Form className="u-form">
|
||||||
|
<div className="body">
|
||||||
|
<InputFiledInForm
|
||||||
|
name="email"
|
||||||
|
placeholder="Email Address"
|
||||||
|
ref={emailRef}
|
||||||
|
error={
|
||||||
|
touched.email && errors.email
|
||||||
|
? errors.email.toString()
|
||||||
|
: ''
|
||||||
|
}
|
||||||
|
isShowIconSuccess={touched.email && !errors.email}
|
||||||
|
/>
|
||||||
|
<InputPasswordFiledInForm
|
||||||
|
name="password"
|
||||||
|
placeholder="Password"
|
||||||
|
error={
|
||||||
|
touched.password && errors.password
|
||||||
|
? errors.password.toString()
|
||||||
|
: ''
|
||||||
|
}
|
||||||
|
onEnter={isValid ? submitForm : undefined}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className={styles.bottom}>
|
||||||
|
<Link href={ROUTE.FORGOT_PASSWORD}>
|
||||||
|
<a href="" className={styles.forgotPassword}>
|
||||||
|
Forgot Password?
|
||||||
|
</a>
|
||||||
|
</Link>
|
||||||
|
<ButtonCommon HTMLType='submit' loading={loading} size="large">
|
||||||
|
Sign in
|
||||||
|
</ButtonCommon>
|
||||||
|
</div>
|
||||||
|
</Form>
|
||||||
|
)}
|
||||||
|
</Formik>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* <Inputcommon placeholder='Email Address' type='email' ref={emailRef}
|
|
||||||
isShowIconSuccess={true} isIconSuffix={true} /> */}
|
|
||||||
<InputPassword
|
|
||||||
placeholder="Password"
|
|
||||||
value={password}
|
|
||||||
onChange={(val) => setPassword(val.toString())}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className={styles.bottom}>
|
|
||||||
<Link href={ROUTE.FORGOT_PASSWORD}>
|
|
||||||
<a href="" className={styles.forgotPassword}>
|
|
||||||
Forgot Password?
|
|
||||||
</a>
|
|
||||||
</Link>
|
|
||||||
<ButtonCommon onClick={onLogin} loading={loading} size="large">
|
|
||||||
Sign in
|
|
||||||
</ButtonCommon>
|
|
||||||
</div>
|
|
||||||
<SocialAuthen />
|
<SocialAuthen />
|
||||||
<div className={s.others}>
|
<div className={s.others}>
|
||||||
<span>Don't have an account?</span>
|
<span>Don't have an account?</span>
|
||||||
|
@@ -33,7 +33,7 @@ const DisplayingErrorMessagesSchema = Yup.object().shape({
|
|||||||
|
|
||||||
const FormRegister = ({ onSwitch, isHide }: Props) => {
|
const FormRegister = ({ onSwitch, isHide }: Props) => {
|
||||||
const emailRef = useRef<CustomInputCommon>(null)
|
const emailRef = useRef<CustomInputCommon>(null)
|
||||||
const { loading, signup, error } = useSignup()
|
const { loading, signup } = useSignup()
|
||||||
const { showMessageSuccess, showMessageError } = useMessage()
|
const { showMessageSuccess, showMessageError } = useMessage()
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -54,12 +54,6 @@ const FormRegister = ({ onSwitch, isHide }: Props) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (error) {
|
|
||||||
alert(error.message)
|
|
||||||
}
|
|
||||||
}, [error])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section
|
<section
|
||||||
className={classNames({
|
className={classNames({
|
||||||
|
@@ -5,6 +5,7 @@ import { CommonError } from 'src/domains/interfaces/CommonError'
|
|||||||
import rawFetcher from 'src/utils/rawFetcher'
|
import rawFetcher from 'src/utils/rawFetcher'
|
||||||
import { LoginMutation } from '@framework/schema'
|
import { LoginMutation } from '@framework/schema'
|
||||||
import { LOCAL_STORAGE_KEY } from 'src/utils/constanst.utils'
|
import { LOCAL_STORAGE_KEY } from 'src/utils/constanst.utils'
|
||||||
|
import { errorMapping } from 'src/utils/errrorMapping'
|
||||||
|
|
||||||
const query = gql`
|
const query = gql`
|
||||||
mutation login($username: String!, $password: String!) {
|
mutation login($username: String!, $password: String!) {
|
||||||
@@ -31,7 +32,9 @@ const useLogin = () => {
|
|||||||
const [error, setError] = useState<CommonError | null>(null)
|
const [error, setError] = useState<CommonError | null>(null)
|
||||||
const { mutate } = useActiveCustomer()
|
const { mutate } = useActiveCustomer()
|
||||||
|
|
||||||
const login = (options: LoginInput) => {
|
const login = (options: LoginInput,
|
||||||
|
fCallBack: (isSuccess: boolean, message?: string) => void
|
||||||
|
) => {
|
||||||
setError(null)
|
setError(null)
|
||||||
setLoading(true)
|
setLoading(true)
|
||||||
rawFetcher<LoginMutation>({
|
rawFetcher<LoginMutation>({
|
||||||
@@ -40,15 +43,19 @@ const useLogin = () => {
|
|||||||
})
|
})
|
||||||
.then(({ data, headers }) => {
|
.then(({ data, headers }) => {
|
||||||
if (data.login.__typename !== 'CurrentUser') {
|
if (data.login.__typename !== 'CurrentUser') {
|
||||||
throw CommonError.create(data.login.message, data.login.errorCode)
|
throw CommonError.create(errorMapping(data.login.message), data.login.errorCode)
|
||||||
}
|
}
|
||||||
const authToken = headers.get('vendure-auth-token')
|
const authToken = headers.get('vendure-auth-token')
|
||||||
if (authToken != null) {
|
if (authToken != null) {
|
||||||
localStorage.setItem(LOCAL_STORAGE_KEY.TOKEN, authToken)
|
localStorage.setItem(LOCAL_STORAGE_KEY.TOKEN, authToken)
|
||||||
return mutate()
|
mutate()
|
||||||
}
|
}
|
||||||
|
fCallBack(true)
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
setError(error)
|
||||||
|
fCallBack(false, error.message)
|
||||||
})
|
})
|
||||||
.catch(setError)
|
|
||||||
.finally(() => setLoading(false))
|
.finally(() => setLoading(false))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
14
src/utils/errrorMapping.ts
Normal file
14
src/utils/errrorMapping.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import { LANGUAGE } from "./language.utils";
|
||||||
|
|
||||||
|
export function errorMapping(message?: string) {
|
||||||
|
if (!message) {
|
||||||
|
return LANGUAGE.MESSAGE.ERROR
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (message) {
|
||||||
|
case 'The provided credentials are invalid':
|
||||||
|
return 'The email address or password is incorrect!'
|
||||||
|
default:
|
||||||
|
return LANGUAGE.MESSAGE.ERROR
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user