Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/관리자 유저 모달 개선 #647 #649

Merged
merged 31 commits into from
Feb 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
210d6d8
[Fix] 라디오버튼 스타일 오류 수정 #647
Feb 11, 2023
e2074a6
input핸들러 오류 해결 #647
Feb 11, 2023
fcb851f
[Feat] 숫자 NaN표시 제거 #647
Feb 11, 2023
410308c
[Fix] import 및 css 순서 정렬 #647
Feb 11, 2023
f32e239
[feat] 숫자input 삭제불가->0으로 표기 #647
Feb 11, 2023
b8b630a
[Feat] inputHandler 개선(불변성 유지) #647
Feb 11, 2023
606f395
[Fix] 이미지 alt 추가 #647
Feb 11, 2023
2a9b915
[Fix] prop 타입명 수정 #647
Feb 11, 2023
6b35b04
[Feat] 상태메세지 글자수 제한 #647
Feb 11, 2023
2a885b9
[Feat] api 요청 수정 #647
Feb 14, 2023
18452b4
[Feat] api put요청 보내기 성공 #647
Feb 14, 2023
5ded19d
[Feat] 상태메시지 30자이상 리렌더링 방지 #647
Feb 15, 2023
3b74115
[Feat] 숫자 input 타입 변경 #647
Feb 15, 2023
259cc24
[Feat] Prop의 modalName 타입 삭제 #647
Feb 15, 2023
939102a
[Feat] put요청 id 수정 #647
Feb 15, 2023
b819fcf
[Feat] 수정,취소 버튼 테두리 삭제 #647
Feb 15, 2023
2f40270
[Feat] 주석 삭제, textarea 태그 수정 #647
Feb 15, 2023
ea4a13f
[Feat] 이메일 명세 수정 #647
Feb 15, 2023
8920c4e
[Fix] 업로드 타입 수정 #647
Feb 15, 2023
0f2dc61
[Fix] 콘솔로그 삭제 #647
Feb 17, 2023
7182f5c
[Fix] 콘솔로그 삭제 #647
Feb 17, 2023
2b73042
[Feat] 상태메세지 변수명 수정 #647
Feb 17, 2023
b730cdb
[Feat] CSS 정렬 수정 #647
Feb 17, 2023
063930f
[Fix] eMail로 수정 #647
Feb 17, 2023
ed985af
[Feat] 에러로그 처리, api 명세 변경 #647
Feb 17, 2023
1c72803
[Fix] 유저아이디로 수정 #647
Feb 17, 2023
24e06b7
[Fix] userId 에러 수정 #647
Feb 17, 2023
1ab33a6
[Feat] 콘솔로그 삭제 #647
Feb 17, 2023
8105ff8
merge main
Feb 17, 2023
5a5debc
[Fix] 압축문제 해결 필요 #647
Feb 17, 2023
349293f
[Fix] 에러 catch 수정 #647
Feb 17, 2023
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
4 changes: 2 additions & 2 deletions components/modal/ModalProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import styles from 'styles/modal/Modal.module.scss';

export default function ModalProvider() {
const [
{ modalName, cancel, enroll, manual, announcement, exp, intraId },
{ modalName, cancel, enroll, manual, announcement, exp, intraId, userId },
setModal,
] = useRecoilState(modalState);
const setReloadMatch = useSetRecoilState(reloadMatchState);
Expand All @@ -38,7 +38,7 @@ export default function ModalProvider() {
'USER-PROFILE_EDIT': <EditProfileModal />,
'FIXED-AFTER_GAME': <AfterGameModal />,
'FIXED-STAT': <StatChangeModal {...exp} />,
'ADMIN-PROFILE': intraId ? <AdminProfileModal value={intraId} /> : null,
'ADMIN-PROFILE': userId ? <AdminProfileModal value={userId} /> : null,
'ADMIN-PENALTY': intraId ? <AdminPenaltyModal value={intraId} /> : null,
'ADMIN-NOTI_ALL': intraId ? <AdminNotiAllModal value={intraId} /> : null,
'ADMIN-NOTI_USER': intraId ? <AdminNotiUserModal value={intraId} /> : null,
Expand Down
150 changes: 88 additions & 62 deletions components/modal/admin/AdminProfileModal.tsx
Original file line number Diff line number Diff line change
@@ -1,83 +1,105 @@
import { useSetRecoilState } from 'recoil';
import Image from 'next/image';
import { useEffect, useState } from 'react';
42sungwook marked this conversation as resolved.
Show resolved Hide resolved
import styles from 'styles/admin/modal/AdminProfile.module.scss';
import { useSetRecoilState } from 'recoil';
import {
AdminProfileProps,
roleTypes,
UserInfo,
} from 'types/admin/adminUserTypes';
import { racketTypes } from 'types/userTypes';
import { modalState } from 'utils/recoil/modal';
import instance from 'utils/axios';
import Image from 'next/image';
import axios from 'axios';
import useUploadImg from 'hooks/useUploadImg';
import { Props, roleTypes, UserInfo } from 'types/admin/adminUserTypes';
import { racketTypes } from 'types/userTypes';
import styles from 'styles/admin/modal/AdminProfile.module.scss';
import { errorState } from 'utils/recoil/error';

const STAT_MSG_LIMIT = 30;

export default function AdminProfileModal(props: AdminProfileProps) {
const [userInfo, setUserInfo] = useState<UserInfo>({
intraId: '',
userImageUri: null,
statusMessage: '',
racketType: 'shakeHand',
wins: 0,
losses: 0,
ppp: 0,
eMail: '',
roleType: 'ROLE_USER',
});

export default function AdminProfileModal(props: Props) {
const [userInfo, setUserInfo] = useState<UserInfo>();
const { imgData, imgPreview, uploadImg } = useUploadImg();
const setModal = useSetRecoilState(modalState);
const setError = useSetRecoilState(errorState);

useEffect(() => {
getBasicProfileHandler();
}, []);

const getBasicProfileHandler = async () => {
const res = await fetch(`http://localhost:3000/api/admin/users`); //admin/users/{props.intraId}/detail
const data = await res.json();
setUserInfo(data[0]);
try {
const res = await instance.get(
`/pingpong/admin/users/${props.value}/detail`
);
setUserInfo(res?.data);
} catch (e) {
setError('SW01');
}
};

const inputHandler = ({
target: { name, value },
}:
| React.ChangeEvent<HTMLTextAreaElement>
42sungwook marked this conversation as resolved.
Show resolved Hide resolved
| React.ChangeEvent<HTMLInputElement>) => {
if (name === 'statusMessage' && value.length > STAT_MSG_LIMIT) return;
setUserInfo({ ...userInfo, [name]: value });
};

const inputNumHandler = ({
target: { name, value },
}: React.ChangeEvent<HTMLInputElement>) => {
if (name === 'wins' || name === 'losses' || name === 'ppp') {
const intValue = parseInt(value);
setUserInfo((prev: any) => ({
...prev,
[name]: intValue,
}));
} else {
setUserInfo((prev: any) => ({
...prev,
[name]: value,
}));
}
const intValue = parseInt(value);
setUserInfo({ ...userInfo, [name]: intValue });
};

const submitHandler = async () => {
//const formData = new FormData();
console.log(userInfo);
// const data = {
// userId: userInfo.userId,
// intraId: userInfo.intraId,
// statusMessage: userInfo.statusMessage,
// racketType: userInfo.racketType,
// wins: userInfo.wins,
// losses: userInfo.losses,
// ppp: userInfo.ppp,
// eMail: userInfo.eMail,
// roleType: userInfo.roleType,
// };
//formData.append('files', imgData);
// formData.append(
// 'data',
// new Blob([JSON.stringify(data)], {
// type: 'application/json',
// })
// );
// await instance.put(`/admin/users/${userInfo.userId}`, e);
// try {
// const result = await axios.put(`/admin/users/daijeong/detail`);
// console.log(result);
// } catch (error) {
// console.log(error);
// }
const formData = new FormData();
const data = {
userId: props.value,
intraId: userInfo.intraId,
statusMessage: userInfo.statusMessage,
racketType: userInfo.racketType,
wins: userInfo.wins,
losses: userInfo.losses,
ppp: userInfo.ppp,
eMail: userInfo.eMail,
roleType: userInfo.roleType,
};
formData.append(
'updateRequestDto',
new Blob([JSON.stringify(data)], {
type: 'application/json',
})
);
formData.append(
'multipartFile',
new Blob([imgData as File], { type: 'image/jpeg' })
);

try {
await instance.put(
`/pingpong/admin/users/${props.value}/detail`,
formData
);
} catch (e) {
setError('SW02');
}
};

return (
<>
<div
className={
styles.modal
} /* method="put" */ /* encType="multipart/form-data" */
>
<div className={styles.modal}>
<div className={styles.title}>
<div>회원 정보 수정</div>
</div>
Expand All @@ -87,8 +109,9 @@ export default function AdminProfileModal(props: Props) {
<label className={styles.image}>
<Image
src={imgPreview ? imgPreview : `${userInfo?.userImageUri}`}
layout='fill'
alt=''
width='120'
height='110'
alt='Profile Image'
42sungwook marked this conversation as resolved.
Show resolved Hide resolved
/>
<input
type='file'
Expand Down Expand Up @@ -116,11 +139,12 @@ export default function AdminProfileModal(props: Props) {
</div>
<div className={styles.middle}>
<label>상태 메시지</label>
<div>{`${userInfo.statusMessage.length} / ${STAT_MSG_LIMIT}`}</div>
<textarea
42sungwook marked this conversation as resolved.
Show resolved Hide resolved
name='statusMessage'
onChange={inputHandler}
value={userInfo?.statusMessage}
></textarea>
/>
</div>
<div className={styles.bottom}>
<div className={styles.choice}>
Expand Down Expand Up @@ -173,22 +197,24 @@ export default function AdminProfileModal(props: Props) {
<div>
<input
name='wins'
onChange={inputHandler}
type='number'
onChange={inputNumHandler}
value={userInfo?.wins}
42sungwook marked this conversation as resolved.
Show resolved Hide resolved
/>
</div>
<div>
<input
name='losses'
onChange={inputHandler}
type='number'
onChange={inputNumHandler}
value={userInfo?.losses}
/>
</div>
<div>
<input
type='text'
name='ppp'
onChange={inputHandler}
type='number'
onChange={inputNumHandler}
value={userInfo?.ppp}
/>
</div>
Expand Down
23 changes: 13 additions & 10 deletions hooks/useUploadImg.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,35 @@
import { useEffect, useState } from 'react';
import { ChangeEvent, useEffect, useState } from 'react';
import { useSetRecoilState } from 'recoil';
import { errorState } from 'utils/recoil/error';
import imageCompression from 'browser-image-compression';

export default function useUploadImg() {
const [imgData, setImgData] = useState<File>();
const [imgPreview, setImgPreview] = useState<any>();
const [imgPreview, setImgPreview] = useState<string>();

const uploadImg = (e: any) => {
const file = e.target.files[0];
const setError = useSetRecoilState(errorState);
const uploadImg = (e: ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];
if (file) {
setImgData(file);
}
};

const imgCompress = async (fileSrc: File) => {
const options = {
/* const options = {
maxSizeMB: 0.1,
maxWidthOrHeight: 320,
useWebWorker: true,
};
}; */
try {
const res = await imageCompression(fileSrc, options);
// const res = await imageCompression(fileSrc, options);
const reader = new FileReader();
reader.readAsDataURL(res);
reader.readAsDataURL(fileSrc);
reader.onloadend = () => {
setImgPreview(reader.result);
setImgPreview(reader.result as string);
};
} catch (error) {
console.log(error);
setError('SW00');
}
};

Expand Down
27 changes: 27 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 1 addition & 3 deletions pages/admin/users.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@ export default function Users() {
<div>
users page
<button
onClick={() =>
setModal({ modalName: 'ADMIN-PROFILE', intraId: 'daijeong' })
}
onClick={() => setModal({ modalName: 'ADMIN-PROFILE', userId: 5 })}
>
자세히
</button>
Expand Down
6 changes: 3 additions & 3 deletions pages/api/admin/users/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ export default function handler(
) {
const user: any = [
{
userId: 1,
intraId: 'sungwook',
userId: 5,
intraId: 'jiyun',
userImageUri:
'https://42gg-public-image.s3.ap-northeast-2.amazonaws.com/images/sungwook.jpeg',
'https://42gg-public-image.s3.ap-northeast-2.amazonaws.com/images/jiyun.jpeg',
racketType: 'penholder',
statusMessage: 'hello',
wins: 10,
Expand Down
Loading