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

feat: reset & change password #13

Merged
merged 4 commits into from
Mar 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading