Skip to content

Commit dc6fc3b

Browse files
committed
feat:添加登录注册
1 parent b74c252 commit dc6fc3b

File tree

11 files changed

+203
-24
lines changed

11 files changed

+203
-24
lines changed

src/App.tsx

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
11
import React from 'react';
2-
import logo from './logo.svg';
32
import './App.css';
4-
import {ProjectListScreen} from './screens/project-list'
53
import {LoginScreen} from "./screens/login";
4+
import {useAuth} from "./context/auth-context";
5+
import {AuthenticatedApp} from "./authenticated-app";
6+
import {UnauthenticatedApp} from "./unauthenticated-app";
7+
68
function App() {
7-
return (
8-
<div className="App">
9-
{/*<ProjectListScreen />*/}
10-
<LoginScreen />
11-
</div>
12-
);
9+
const {user} = useAuth()
10+
return (
11+
<div className="App">
12+
{
13+
user ? <AuthenticatedApp /> : <UnauthenticatedApp />
14+
}
15+
</div>
16+
);
1317
}
1418

1519
export default App;

src/auth-provider.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
//在真实环境中,如果使用firebase泽中第三方auth服务的话,本文件不需要开发者进行开发
2+
3+
import {User} from "./screens/project-list/search-panel";
4+
const apiUrl = process.env.REACT_APP_API_URL
5+
const localStorageKey = '__auth__provider__token'
6+
7+
export const getToken = () =>{
8+
window.localStorage.getItem(localStorageKey)
9+
}
10+
11+
export const handleUserResponse = ({user}: {user: User}) =>{
12+
window.localStorage.setItem(localStorageKey, user.token || '')
13+
return user
14+
}
15+
16+
export const login = (data:{username:string, password: string}) =>{
17+
return fetch(`${apiUrl}/login`,{
18+
method: 'POST',
19+
headers:{
20+
'Content-Type': 'application/json'
21+
},
22+
body: JSON.stringify(data)
23+
}).then(async res =>{
24+
if(res.ok){
25+
return handleUserResponse(await res.json())
26+
}else{
27+
return Promise.reject(data)
28+
}
29+
})
30+
}
31+
32+
33+
export const register = (data:{username:string, password: string}) =>{
34+
return fetch(`${apiUrl}/register`,{
35+
method: 'POST',
36+
headers:{
37+
'Content-Type': 'application/json'
38+
},
39+
body: JSON.stringify(data)
40+
}).then(async res =>{
41+
if(res.ok){
42+
return handleUserResponse(await res.json())
43+
}else{
44+
return Promise.reject(data)
45+
}
46+
})
47+
}
48+
49+
export const logout = async () => window.localStorage.removeItem(localStorageKey)

src/authenticated-app.tsx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import React from "react";
2+
import {ProjectListScreen} from "./screens/project-list";
3+
import {useAuth} from "./context/auth-context";
4+
5+
export const AuthenticatedApp = ()=>{
6+
const {logout} = useAuth()
7+
return <div>
8+
<button onClick={logout}>登出</button>
9+
<ProjectListScreen />
10+
</div>
11+
}

src/context/auth-context.tsx

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import React, {ReactNode, useState} from 'react'
2+
import * as auth from 'auth-provider'
3+
import {User} from "../screens/project-list/search-panel";
4+
5+
6+
const AuthContext = React.createContext<{
7+
user: User | null,
8+
login: (form:AuthForm) => Promise<void>,
9+
register: (form:AuthForm) => Promise<void>,
10+
logout: () => Promise<void>,
11+
}|undefined>(undefined)
12+
13+
AuthContext.displayName = 'AuthContext'
14+
15+
interface AuthForm {
16+
username: string;
17+
password: string;
18+
}
19+
20+
export const AuthProvider = ({children}:{children: ReactNode}) =>{
21+
const [user, setUser] = useState<User | null>(null)
22+
23+
//point free
24+
const login = (form: AuthForm) => auth.login(form).then(setUser)
25+
const register = (form: AuthForm) => auth.register(form).then(user => setUser(user))
26+
const logout = () => auth.logout().then(() => setUser(null))
27+
28+
return <AuthContext.Provider children={children} value={{user,login,register, logout}}></AuthContext.Provider>
29+
}
30+
31+
export const useAuth = () =>{
32+
const context = React.useContext(AuthContext)
33+
if(!context){
34+
throw new Error('useAuth必须在AuthProvider中使用')
35+
}
36+
return context
37+
}

src/context/index.tsx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import React, {ReactNode} from "react";
2+
import {AuthProvider} from "./auth-context";
3+
4+
5+
export const AppProviders = ({children}:{children: ReactNode}) =>{
6+
return <AuthProvider>
7+
{children}
8+
</AuthProvider>
9+
}

src/index.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,14 @@ import './index.css';
44
import App from './App';
55
import reportWebVitals from './reportWebVitals';
66
import {loadDevTools} from 'jira-dev-tool'
7+
import {AppProviders} from "./context";
78

8-
loadDevTools(()=>{
9+
loadDevTools(() => {
910
ReactDOM.render(
1011
<React.StrictMode>
11-
<App />
12+
<AppProviders>
13+
<App/>
14+
</AppProviders>
1215
</React.StrictMode>,
1316
document.getElementById('root')
1417
);

src/screens/login/index.tsx

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,27 @@
11
import React, {FormEvent, FormEventHandler} from 'react'
22
import * as qs from "qs";
33
import {cleanObject} from "../../utils";
4+
import {useAuth} from "../../context/auth-context";
5+
46
const apiUrl = process.env.REACT_APP_API_URL
57
export const LoginScreen = () => {
68

7-
const login = (param: { username: string, password: string }) => {
8-
fetch(`${apiUrl}/login`,{
9-
method: 'POST',
10-
headers:{
11-
'Content-Type': 'application/json'
12-
},
13-
body: JSON.stringify(param)
14-
}).then(async res =>{
15-
if(res.ok){
16-
}
17-
})
18-
}
9+
const{login,user} = useAuth()
1910

2011
const handleSubmit = (event: FormEvent<HTMLFormElement>) => {
2112
event.preventDefault() //组织默认事件
2213
const username = (event.currentTarget.elements[0] as HTMLInputElement).value
2314
const password = (event.currentTarget.elements[1] as HTMLInputElement).value
24-
login({username,password})
15+
login({username, password})
2516
}
2617

2718
return <form onSubmit={handleSubmit}>
19+
{
20+
user ? <div>
21+
登录成功,用户名:{user?.name}
22+
token: {user?.token}
23+
</div> : null
24+
}
2825
<div>
2926
<label htmlFor="username">用户名</label>
3027
<input type="text" id={'username'}/>

src/screens/project-list/search-panel.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ export interface User {
44
id: string;
55
name: string;
66
personId: string;
7-
organization: string
7+
organization: string;
8+
token: string;
89
}
910

1011
interface SearchPanelProps{

src/unauthenticated-app/index.tsx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import React, {useState} from "react";
2+
import {RegisterScreen} from "./register";
3+
import {LoginScreen} from "./login";
4+
5+
export const UnauthenticatedApp = () =>{
6+
const [isRegister, setIsRegister] = useState(false)
7+
return <div>
8+
{
9+
isRegister ? <RegisterScreen /> : <LoginScreen/>
10+
}
11+
<button onClick={()=> setIsRegister(!isRegister)}>切换到{isRegister ? '登录' : '注册'}</button>
12+
</div>
13+
}

src/unauthenticated-app/login.tsx

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import React, {FormEvent, FormEventHandler} from 'react'
2+
import {useAuth} from "../context/auth-context";
3+
4+
5+
const apiUrl = process.env.REACT_APP_API_URL
6+
export const LoginScreen = () => {
7+
8+
const{login,user} = useAuth()
9+
10+
const handleSubmit = (event: FormEvent<HTMLFormElement>) => {
11+
event.preventDefault() //组织默认事件
12+
const username = (event.currentTarget.elements[0] as HTMLInputElement).value
13+
const password = (event.currentTarget.elements[1] as HTMLInputElement).value
14+
login({username, password})
15+
}
16+
17+
return <form onSubmit={handleSubmit}>
18+
<div>
19+
<label htmlFor="username">用户名</label>
20+
<input type="text" id={'username'}/>
21+
</div>
22+
<div>
23+
<label htmlFor="password">密码</label>
24+
<input type="password" id={'password'}/>
25+
</div>
26+
<button type={'submit'}>登录</button>
27+
</form>
28+
}

0 commit comments

Comments
 (0)