Skip to content
This repository has been archived by the owner on May 8, 2024. It is now read-only.

Commit

Permalink
feat: reset & change password (#13)
Browse files Browse the repository at this point in the history
Co-authored-by: gjzuloaga <[email protected]>
  • Loading branch information
BoYanZh and gjzuloaga authored Mar 21, 2024
1 parent bbae20e commit a76b15a
Show file tree
Hide file tree
Showing 7 changed files with 408 additions and 15 deletions.
87 changes: 87 additions & 0 deletions src/client/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,12 @@ export interface SchemaUser {
username?: string
}

export interface SchemaUserChangePassword {
currentPassword?: string
newPassword?: string
username?: string
}

export interface SchemaUserDetail {
address?: string
address2?: string
Expand Down Expand Up @@ -242,6 +248,11 @@ export interface SchemaUserListResponse {
offset?: number
}

export interface SchemaUserResetPassword {
newPassword?: string
username?: string
}

export type QueryParamsType = Record<string | number, any>
export type ResponseFormat = keyof Omit<Body, 'body' | 'bodyUsed'>

Expand Down Expand Up @@ -642,6 +653,56 @@ export class Api<
...params
}),

/**
* @description Change the user's password.
*
* @tags Auth
* @name V1AuthChangepasswordCreate
* @summary change password
* @request POST:/api/v1/auth/changepassword
*/
v1AuthChangepasswordCreate: (
changePassword: SchemaUserChangePassword,
query?: {
/** Redirect url after login */
redirect_url?: string
},
params: RequestParams = {}
) =>
this.request<SchemaUserChangePassword, SchemaErrorResponse>({
path: `/api/v1/auth/changepassword`,
method: 'POST',
query: query,
body: changePassword,
type: ContentType.Json,
format: 'json',
...params
}),

/**
* @description Initiate the password reset process.
*
* @tags Auth
* @name V1AuthForgotpasswordCreate
* @summary forgot password
* @request POST:/api/v1/auth/forgotpassword
*/
v1AuthForgotpasswordCreate: (
query?: {
/** Email */
email?: string
},
params: RequestParams = {}
) =>
this.request<object, SchemaErrorResponse>({
path: `/api/v1/auth/forgotpassword`,
method: 'POST',
query: query,
type: ContentType.Json,
format: 'json',
...params
}),

/**
* @description Get current JWT.
*
Expand Down Expand Up @@ -725,6 +786,32 @@ export class Api<
type: ContentType.Json,
format: 'json',
...params
}),

/**
* @description Reset the user's password.
*
* @tags Auth
* @name V1AuthResetpasswordCreate
* @summary reset password
* @request POST:/api/v1/auth/resetpassword
*/
v1AuthResetpasswordCreate: (
resetPassword: SchemaUserResetPassword,
query?: {
/** Redirect url after login */
redirect_url?: string
},
params: RequestParams = {}
) =>
this.request<SchemaUserResetPassword, SchemaErrorResponse>({
path: `/api/v1/auth/resetpassword`,
method: 'POST',
query: query,
body: resetPassword,
type: ContentType.Json,
format: 'json',
...params
})
}
movie = {
Expand Down
122 changes: 122 additions & 0 deletions src/pages/ChangePassword/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import { useRequest } from 'ahooks'
import PageContainer from 'components/PageContainer'
import { useAuth } from 'hooks/useAuth'
import { useState } from 'react'
import { Col, Row } from 'react-bootstrap'
import Button from 'react-bootstrap/Button'
import Form from 'react-bootstrap/Form'
import { Navigate, useNavigate, useSearchParams } from 'react-router-dom'
import { DOMAIN_HOST } from 'utils/constants'
import Backend from 'utils/service'

const ChangeForm: React.FC = () => {
const { user } = useAuth()
const [searchParams] = useSearchParams()
const [username, setUsername] = useState('')
const [currentPassword, setCurrentPassword] = useState('')
const [newPassword, setNewPassword] = useState('')
const navigate = useNavigate()
const { run: changePasssword } = useRequest(
async () => {
const from = searchParams.get('from') ?? '/'
return Backend.auth.v1AuthChangepasswordCreate(
{
username,
currentPassword,
newPassword
},
{
redirect_url: `${DOMAIN_HOST}${from}`
}
)
},
{
manual: true,
onSuccess: () => {
navigate('/logout') // Navigate to the login page
}
}
)

const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault()
changePasssword()
}

return user ? (
<>
<div className='text-center'>
<h1>Reset Password</h1>
</div>
<Col xs={12} md={8} lg={6} className='mx-auto mt-3'>
<Form onSubmit={handleSubmit} validated>
<Form.Group as={Row} className='mb-3' controlId='formBasicEmail'>
<Form.Label className='text-sm-end' column sm={2}>
Username
</Form.Label>
<Col sm={10}>
<Form.Control
required
type='text'
placeholder='Username'
defaultValue={username}
onChange={e => {
setUsername(e.target.value)
}}
/>
</Col>
</Form.Group>
<Form.Group as={Row} className='mb-3' controlId='formBasicPassword'>
<Form.Label className='text-sm-end' column sm={2}>
Current Password
</Form.Label>
<Col sm={10}>
<Form.Control
required
type='password'
placeholder='Current Password'
defaultValue={currentPassword}
onChange={e => {
setCurrentPassword(e.target.value)
}}
/>
</Col>
</Form.Group>
<Form.Group as={Row} className='mb-3' controlId='formBasicPassword'>
<Form.Label className='text-sm-end' column sm={2}>
New Password
</Form.Label>
<Col sm={10}>
<Form.Control
required
type='password'
placeholder='Password'
defaultValue={newPassword}
onChange={e => {
setNewPassword(e.target.value)
}}
/>
</Col>
</Form.Group>
<Form.Group as={Row} className='mb-3'>
<Col sm={{ span: 10, offset: 2 }}>
<Button variant='primary' type='submit'>
Submit
</Button>
</Col>
</Form.Group>
</Form>
</Col>
</>
) : (
<Navigate to='/' />
)
}

const Index: React.FC = () => (
<PageContainer>
<ChangeForm />
</PageContainer>
)

export default Index
23 changes: 11 additions & 12 deletions src/pages/EditProfile/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ import PageContainer from 'components/PageContainer'
import type React from 'react'
import { useState } from 'react'
import { Form, Button, Col, Row, Accordion } from 'react-bootstrap'
import { useNavigate } from 'react-router-dom'
import Backend from 'utils/service'

const UserProfileForm: React.FC = () => {
// TODO: submit update user
const navigate = useNavigate()
const { run: submit } = useRequest(async () => null)
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault()
Expand Down Expand Up @@ -37,18 +39,15 @@ const UserProfileForm: React.FC = () => {
disabled
/>
</Form.Group>
<Form.Group as={Col} controlId='formGridPassword'>
<Form.Label className='required'>Password</Form.Label>
<Form.Control
type='password'
placeholder='Password'
onChange={e => {
setUser(prevUser => ({
...prevUser,
password: e.target.value
}))
}}
/>
<Form.Group as={Col} controlId='formGridEmail'>
<Form.Label>Password</Form.Label>
<Button
type='button'
className='form-control'
onClick={() => navigate('/changePassword', { replace: true })}
>
Change Password
</Button>
</Form.Group>
</Row>
<Row className='mb-3'>
Expand Down
58 changes: 58 additions & 0 deletions src/pages/ForgotPassword/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { useRequest } from 'ahooks'
import PageContainer from 'components/PageContainer'
import { useState } from 'react'
import { Col, Row, Form, Button, Alert } from 'react-bootstrap'
import Backend from 'utils/service'

const ForgotPassword: React.FC = () => {
const [email, setEmail] = useState('')
const [info, setInfo] = useState('')
const { run } = useRequest(
async () => Backend.auth.v1AuthForgotpasswordCreate({ email }),
{
manual: true,
onSuccess: () => {
setInfo('Done! Check you email!')
}
}
)
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault()
run()
}
return (
<PageContainer>
<div className='text-center'>
<h1>Forgot Password</h1>
</div>
<Col xs={12} md={8} lg={6} className='mx-auto mt-3'>
{info ? <Alert variant='success'>{info}</Alert> : null}
<Form onSubmit={handleSubmit}>
<Form.Group as={Row} className='mb-3' controlId='formBasicEmail'>
<Form.Label className='text-sm-end' column sm={2}>
Email
</Form.Label>
<Col sm={10}>
<Form.Control
required
type='email'
placeholder='Enter your email'
value={email}
onChange={e => setEmail(e.target.value)}
/>
</Col>
</Form.Group>
<Form.Group as={Row} className='mb-3'>
<Col sm={{ span: 10, offset: 2 }}>
<Button variant='primary' type='submit'>
Send Reset Email
</Button>
</Col>
</Form.Group>
</Form>
</Col>
</PageContainer>
)
}

export default ForgotPassword
14 changes: 11 additions & 3 deletions src/pages/Login/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { useState } from 'react'
import { Alert, Col, Row } from 'react-bootstrap'
import Button from 'react-bootstrap/Button'
import Form from 'react-bootstrap/Form'
import { Navigate, useSearchParams } from 'react-router-dom'
import { Navigate, useSearchParams, useNavigate } from 'react-router-dom'
import { DOMAIN_HOST } from 'utils/constants'
import Backend from 'utils/service'

Expand All @@ -17,14 +17,15 @@ const LoginForm: React.FC = () => {
const [username, setUsername] = useState('demo')
const [password, setPassword] = useState('123456')
const [remember, setRemember] = useState(false)
const navigate = useNavigate()
const { run: login } = useRequest(
async () => {
const from = searchParams.get('from') ?? '/'
return Backend.auth.v1AuthLoginCreate(
{
username,
password,
remember
password
// remember
},
{
redirect_url: `${DOMAIN_HOST}${from}`
Expand All @@ -48,6 +49,10 @@ const LoginForm: React.FC = () => {
login()
}

const handleForgotPassword = () => {
navigate('/forgotPassword') // Navigate to the Forgot Password page
}

return user ? (
user.is_admin ? (
<Navigate to='/admin' />
Expand Down Expand Up @@ -104,6 +109,9 @@ const LoginForm: React.FC = () => {
}}
name='rememberme'
/>
<Button variant='link' onClick={handleForgotPassword}>
Forgot Password
</Button>
<Button
style={{ marginTop: '10px' }}
variant='primary'
Expand Down
Loading

0 comments on commit a76b15a

Please sign in to comment.