Skip to content

Commit ffa5167

Browse files
authored
Merge pull request #122 from rnjshippo/dev
로그인 loading 처리 / 실패시 안내 메시지 출력 + 스레드 edit/delete 버튼을 내가 쓴 댓글일때만 표시
2 parents a6ada13 + 7180ee6 commit ffa5167

File tree

5 files changed

+76
-24
lines changed

5 files changed

+76
-24
lines changed

client/src/components/LoginBox/LoginBox.tsx

Lines changed: 48 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,16 @@
1-
import React, { useState } from 'react';
1+
import React, { useEffect, useState } from 'react';
22
import styled from 'styled-components';
33
import { useDispatch } from 'react-redux';
44
import { darken } from 'polished';
55
import { Link } from 'react-router-dom';
66
import isEmail from 'validator/es/lib/isEmail';
77
import { loginRequest } from '@/store/modules/auth.slice';
8-
import {
9-
FormButton as LoginButton,
10-
FormInput as Input,
11-
FormLabel as Label,
12-
} from '@/styles/shared/form';
8+
import { FormButton, FormInput as Input, FormLabel as Label } from '@/styles/shared/form';
139
import { WarningIcon } from '@/components';
1410
import { IconBox, WarningText } from '@/components/EmailBox/EmailBox';
1511
import { flex } from '@/styles/mixin';
12+
import { useAuthState } from '@/hooks';
13+
import LoadingSvg from '@/public/icon/loading.svg';
1614

1715
const Container = styled.div`
1816
width: 100%;
@@ -32,7 +30,7 @@ const Form = styled.form`
3230
margin: 1.5rem auto;
3331
`;
3432

35-
const SignupButton = styled(LoginButton)`
33+
const SignupButton = styled(FormButton)`
3634
border: 1px solid ${(props) => props.theme.color.main};
3735
color: ${(props) => props.theme.color.main};
3836
background-color: white;
@@ -49,20 +47,39 @@ const WarningBox = styled.div`
4947
${flex('center', 'flex-start')};
5048
`;
5149

50+
const LoadingIcon = styled.img`
51+
width: 40px;
52+
height: 40px;
53+
`;
54+
55+
const LoginButton = styled(FormButton)`
56+
${flex()}
57+
`;
58+
59+
const LoadingButton = styled(FormButton)`
60+
height: 50px;
61+
cursor: initial;
62+
${flex()}
63+
`;
64+
5265
const LoginBox: React.FC = () => {
5366
const dispatch = useDispatch();
5467

5568
const [email, setEmail] = useState('');
5669
const [pw, setPw] = useState('');
5770
const [valid, setValid] = useState(true);
71+
const [loginFailed, setLoginFailed] = useState(false);
72+
const { login: loginState } = useAuthState();
5873

5974
const handleEmailChange = (e: React.ChangeEvent<HTMLInputElement>) => {
6075
setEmail(e.target.value);
6176
setValid(true);
77+
setLoginFailed(false);
6278
};
6379

6480
const handlePwChange = (e: React.ChangeEvent<HTMLInputElement>) => {
6581
setPw(e.target.value);
82+
setLoginFailed(false);
6683
};
6784

6885
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
@@ -74,6 +91,12 @@ const LoginBox: React.FC = () => {
7491
dispatch(loginRequest({ email, pw }));
7592
};
7693

94+
useEffect(() => {
95+
if (loginState.err?.response?.status === 401) {
96+
setLoginFailed(true);
97+
}
98+
}, [loginState.err]);
99+
77100
return (
78101
<Container>
79102
<Form onSubmit={handleSubmit}>
@@ -105,11 +128,25 @@ const LoginBox: React.FC = () => {
105128
value={pw}
106129
required
107130
/>
108-
<LoginButton type="submit">로그인</LoginButton>
109-
<Link to="/verify">
110-
<SignupButton type="button">회원가입</SignupButton>
111-
</Link>
112131
</Label>
132+
{loginFailed && (
133+
<WarningBox>
134+
<IconBox>
135+
<WarningIcon />
136+
</IconBox>
137+
<WarningText>이메일 또는 비밀번호가 일치하지 않습니다.</WarningText>
138+
</WarningBox>
139+
)}
140+
{loginState.loading ? (
141+
<LoadingButton type="submit">
142+
<LoadingIcon src={LoadingSvg} />
143+
</LoadingButton>
144+
) : (
145+
<LoginButton type="submit">로그인</LoginButton>
146+
)}
147+
<Link to="/verify">
148+
<SignupButton type="button">회원가입</SignupButton>
149+
</Link>
113150
</Form>
114151
</Container>
115152
);

client/src/components/SignupBox/SignupBox.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ const WarningBox = styled.div`
4040
${flex('center', 'flex-start')};
4141
`;
4242

43-
const regex = /^.*(?=^.{8,15}$)(?=.*\d)(?=.*[a-zA-Z])(?=.*[!@#$%^&+=]).*$/;
43+
const passwordRegex = /^.*(?=^.{8,15}$)(?=.*\d)(?=.*[a-zA-Z])(?=.*[!@#$%^&+=]).*$/;
4444

4545
const SignupBox: React.FC = () => {
4646
const dispatch = useDispatch();
@@ -73,7 +73,7 @@ const SignupBox: React.FC = () => {
7373
setPw(value);
7474
checkPassword(value, confirmPw);
7575

76-
if (!regex.test(value)) {
76+
if (!passwordRegex.test(value)) {
7777
setIsValidPw(false);
7878
} else {
7979
setIsValidPw(true);

client/src/components/common/ThreadItem/ThreadPopup/ThreadPopup.tsx

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { useDispatch } from 'react-redux';
88
import theme from '@/styles/theme';
99
import { sendMessageRequest } from '@/store/modules/socket.slice';
1010
import { SOCKET_MESSAGE_TYPE, THREAD_SUBTYPE } from '@/utils/constants';
11-
import { useChannelState } from '@/hooks';
11+
import { useChannelState, useUserState } from '@/hooks';
1212

1313
const Container = styled.div`
1414
position: relative;
@@ -68,6 +68,7 @@ const ThreadPopup: React.FC<ThreadPopupProps> = ({
6868

6969
const { current } = useChannelState();
7070
const dispatch = useDispatch();
71+
const { userInfo } = useUserState();
7172

7273
const openMenuModal = () => setMenuModalVisible(true);
7374
const openReactionModal = () => setReactionModalVisible(true);
@@ -98,9 +99,11 @@ const ThreadPopup: React.FC<ThreadPopupProps> = ({
9899
</CommentBox>
99100
</Link>
100101
)}
101-
<MoreActionBox onClick={openMenuModal} ref={popoverRef}>
102-
<DotIcon color={theme.color.black5} />
103-
</MoreActionBox>
102+
{userInfo?.id === thread.userId && (
103+
<MoreActionBox onClick={openMenuModal} ref={popoverRef}>
104+
<DotIcon color={theme.color.black5} />
105+
</MoreActionBox>
106+
)}
104107
{menuModalVisible && popoverRef.current && (
105108
<Popover
106109
anchorEl={popoverRef.current}

client/src/store/modules/auth.slice.ts

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,23 @@
22
/* eslint-disable no-param-reassign */
33
import { createSelector, createSlice, PayloadAction } from '@reduxjs/toolkit';
44
import { RootState } from '@/store/modules';
5+
import { AxiosError } from 'axios';
56

67
interface AuthState {
7-
loading: boolean;
8+
login: {
9+
loading: boolean;
10+
err: AxiosError | null;
11+
};
812
accessToken: string | null;
913
refreshToken: string | null;
1014
userId: number | null;
1115
}
1216

1317
const authState: AuthState = {
14-
loading: false,
18+
login: {
19+
loading: false,
20+
err: null,
21+
},
1522
accessToken: localStorage.getItem('accessToken'),
1623
refreshToken: localStorage.getItem('refreshToken'),
1724
userId: localStorage.getItem('userId') ? Number(localStorage.getItem('userId')) : null,
@@ -32,24 +39,29 @@ const authSlice = createSlice({
3239
initialState: authState,
3340
reducers: {
3441
loginRequest(state, action: PayloadAction<LoginRequestPayload>) {
35-
state.loading = true;
42+
state.login.loading = true;
3643
},
3744
loginSuccess(state, { payload }: PayloadAction<LoginSuccessPayload>) {
3845
const { accessToken, refreshToken, userId } = payload;
3946
state.accessToken = accessToken;
4047
state.refreshToken = refreshToken;
4148
state.userId = userId;
4249

43-
state.loading = false;
50+
state.login.loading = false;
51+
state.login.err = null;
4452
},
45-
loginFailure(state) {
46-
state.loading = false;
53+
loginFailure(state, { payload }: PayloadAction<{ err: AxiosError }>) {
54+
state.login.loading = false;
55+
state.login.err = payload.err;
4756
},
4857
logoutRequest() {},
4958
logoutSuccess(state) {
5059
state.accessToken = null;
5160
state.refreshToken = null;
5261
state.userId = null;
62+
63+
state.login.loading = false;
64+
state.login.err = null;
5365
},
5466
logoutFailure() {},
5567
},

client/src/store/sagas/authSaga.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ function* login({ email, pw }: LoginRequestPayload) {
2727
);
2828
}
2929
} catch (err) {
30-
yield put(loginFailure());
30+
yield put(loginFailure({ err }));
3131
}
3232
}
3333

0 commit comments

Comments
 (0)