-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Minor : Icon 추가 * New : 유저정보 변경 뮤테이션 추가 * New : 파일 삭제 뮤테이션 추가 * Refactor : 쿼리 인벨리데이션과정 추가 * New : 정보 수정 서버 URL 추가 * Refactor : 앱바, 드로워 컴포넌트 분리 * New : 프로필 수정기능 적용
- Loading branch information
1 parent
266bbae
commit 769547e
Showing
14 changed files
with
407 additions
and
66 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,48 +1,73 @@ | ||
"use client"; | ||
import { AppBar, Button, IconButton, Toolbar, Typography } from "@mui/material"; | ||
import { | ||
AppBar, | ||
Button, | ||
IconButton, | ||
Toolbar, | ||
Typography, | ||
styled, | ||
} from "@mui/material"; | ||
import GoBackIcon from "@/assets/icons/GoBackIcon.svg"; | ||
import { MouseEventHandler, ReactNode, memo } from "react"; | ||
import { useRouter } from "next/navigation"; | ||
|
||
interface CustomAppbarInterface { | ||
title?: string; | ||
buttonComponent?: ReactNode; | ||
disableButton?: boolean; | ||
onClickButton?: MouseEventHandler<HTMLButtonElement>; | ||
prependButton?: ReactNode; | ||
onClickPrepend?: MouseEventHandler<HTMLButtonElement>; | ||
|
||
appendButton?: ReactNode; | ||
disableAppend?: boolean; | ||
onClickAppend?: MouseEventHandler<HTMLButtonElement>; | ||
} | ||
|
||
const CustomAppbar = ({ | ||
title, | ||
buttonComponent, | ||
disableButton, | ||
onClickButton, | ||
appendButton, | ||
prependButton, | ||
onClickPrepend, | ||
disableAppend, | ||
onClickAppend, | ||
}: CustomAppbarInterface) => { | ||
const router = useRouter(); | ||
|
||
return ( | ||
<AppBar position={"static"}> | ||
<Toolbar sx={{ display: "flex", justifyContent: "space-between" }}> | ||
<IconButton onClick={() => router.back()}> | ||
<GoBackIcon /> | ||
</IconButton> | ||
{/* 프리팬드 버튼 */} | ||
{prependButton ? ( | ||
<AppbarButton variant="text" onClick={onClickPrepend}> | ||
{prependButton} | ||
</AppbarButton> | ||
) : ( | ||
<IconButton onClick={() => router.back()}> | ||
<GoBackIcon /> | ||
</IconButton> | ||
)} | ||
{/* 타이틀 */} | ||
<Typography component="h1" variant="subtitle2" fontWeight={"bold"}> | ||
{title} | ||
</Typography> | ||
{buttonComponent ? ( | ||
<Button | ||
disabled={disableButton} | ||
onClick={onClickButton} | ||
{/* 어팬드 버튼 */} | ||
{appendButton ? ( | ||
<AppbarButton | ||
disabled={disableAppend} | ||
onClick={onClickAppend} | ||
variant="text" | ||
sx={{ minWidth: 40, fontWeight: "medium" }} | ||
> | ||
{buttonComponent} | ||
</Button> | ||
{appendButton} | ||
</AppbarButton> | ||
) : ( | ||
<div style={{ width: "40px" }} /> | ||
)} | ||
</Toolbar> | ||
</AppBar> | ||
); | ||
}; | ||
const AppbarButton = styled(Button)(() => ({ | ||
minWidth: 40, | ||
fontWeight: "medium", | ||
fontSize:'18px' | ||
})); | ||
|
||
export default memo(CustomAppbar); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
import { | ||
Box, | ||
SwipeableDrawer, | ||
SwipeableDrawerProps, | ||
styled, | ||
} from "@mui/material"; | ||
import React from "react"; | ||
|
||
interface Props extends SwipeableDrawerProps {} | ||
|
||
const CustomSwipeableDrawer = ({ open, onOpen, onClose, children }: Props) => { | ||
const pullerBleed = 24; | ||
|
||
return ( | ||
<SwipeableDrawer | ||
open={open} | ||
onOpen={onOpen} | ||
onClose={onClose} | ||
anchor="bottom" | ||
disableSwipeToOpen | ||
PaperProps={{ | ||
sx: { | ||
p: 2, | ||
borderTopLeftRadius: pullerBleed, | ||
borderTopRightRadius: pullerBleed, | ||
overFlow: "hidden", | ||
}, | ||
}} | ||
ModalProps={{ | ||
keepMounted: false, | ||
}} | ||
> | ||
<Puller /> | ||
<Box sx={{ mt: `${pullerBleed + 8}px` }}>{children}</Box> | ||
</SwipeableDrawer> | ||
); | ||
}; | ||
|
||
const Puller = styled(Box)(() => ({ | ||
width: 56, | ||
height: 4, | ||
backgroundColor: "#F6EAFB", | ||
borderRadius: 3, | ||
position: "absolute", | ||
top: 8, | ||
left: "calc(50% - 28px)", | ||
})); | ||
|
||
export default CustomSwipeableDrawer; |
20 changes: 20 additions & 0 deletions
20
client/src/components/user/info/drawer/UserInfoEditingDrawer.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import CustomSwipeableDrawer from "@/components/CustomSwipeableDrawer"; | ||
import UserPageContext from "@/store/user/UserPageContext"; | ||
import { useContext } from "react"; | ||
import UserInfoEditingForm from "./UserInfoEditingForm"; | ||
|
||
const UserInfoEditingDrawer = () => { | ||
const { isEditing, setIsEditing } = useContext(UserPageContext); | ||
|
||
return ( | ||
<CustomSwipeableDrawer | ||
open={isEditing} | ||
onClose={() => setIsEditing(false)} | ||
onOpen={() => setIsEditing(true)} | ||
> | ||
<UserInfoEditingForm /> | ||
</CustomSwipeableDrawer> | ||
); | ||
}; | ||
|
||
export default UserInfoEditingDrawer; |
154 changes: 154 additions & 0 deletions
154
client/src/components/user/info/drawer/UserInfoEditingForm.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
"use client"; | ||
import { useMyInfoQuery } from "@/queries/auth/useMyInfoQuery"; | ||
import { | ||
Stack, | ||
Avatar, | ||
Typography, | ||
TextField, | ||
Button, | ||
Badge, | ||
} from "@mui/material"; | ||
import CameraIcon from "@/assets/icons/badge/CameraIcon.svg"; | ||
import { useCallback, useContext, useEffect, useState } from "react"; | ||
import useNewAttachMutation from "@/queries/attach/useNewAttachMutation"; | ||
import useDeleteAttachMutation from "@/queries/attach/useDeleteAttachMutation"; | ||
import UserPageContext from "@/store/user/UserPageContext"; | ||
import CustomAppbar from "@/components/CustomAppbar"; | ||
import { useGlobalLoadingStore } from "./../../../../store/useGlobalLoadingStore"; | ||
import usePatchUserInfoMutation from "@/queries/user/usePatchUserInfoMutation"; | ||
|
||
const UserInfoEditingForm = () => { | ||
const { setIsEditing } = useContext(UserPageContext); | ||
|
||
const { isLoading, setLoading } = useGlobalLoadingStore(); | ||
|
||
const { data } = useMyInfoQuery(); | ||
|
||
const [introduction, setIntroduction] = useState(data?.introduction); | ||
const [file, setFile] = useState<File>(); | ||
const [fileUrl, setFileUrl] = useState<string | ArrayBuffer | null>(null); | ||
|
||
const { mutateAsync: attachFile } = useNewAttachMutation(); | ||
const { mutateAsync: removeFile } = useDeleteAttachMutation(); | ||
const { mutateAsync: patchUserInfo } = usePatchUserInfoMutation(); | ||
|
||
const submitFileHandler = useCallback( | ||
async (file: File) => { | ||
if (!data) { | ||
return; | ||
} | ||
await attachFile({ | ||
file: file, | ||
url: { type: "PROFILE", pk: Number(data?.userNo) }, | ||
}); | ||
}, | ||
[data] | ||
); | ||
|
||
const submitHandler = async () => { | ||
setLoading(true); | ||
await patchUserInfo({ introduction }); | ||
if (file) { | ||
data?.profileImages.forEach(async (profile) => { | ||
await removeFile(String(profile.attachNo)); | ||
}); | ||
await submitFileHandler(file); | ||
} | ||
setIsEditing(false); | ||
setLoading(false); | ||
}; | ||
|
||
useEffect(() => { | ||
if (!file) { | ||
return; | ||
} | ||
const reader = new FileReader(); | ||
reader.readAsDataURL(file); | ||
reader.onloadend = () => setFileUrl(reader.result); | ||
}, [file]); | ||
|
||
return ( | ||
<> | ||
<CustomAppbar | ||
title={"프로필 수정"} | ||
prependButton={"취소"} | ||
onClickPrepend={() => setIsEditing(false)} | ||
onClickAppend={submitHandler} | ||
appendButton={"저장"} | ||
disableAppend={isLoading} | ||
/> | ||
<Stack | ||
component="form" | ||
alignItems="center" | ||
gap={6} | ||
width="100%" | ||
minHeight="70vh" | ||
> | ||
<label style={{ cursor: "pointer" }}> | ||
<Badge | ||
anchorOrigin={{ | ||
vertical: "bottom", | ||
horizontal: "right", | ||
}} | ||
color="primary" | ||
badgeContent={<CameraIcon />} | ||
> | ||
<Avatar | ||
src={(fileUrl as string) ?? data?.profileImages?.[0]?.attachUrl} | ||
sx={{ width: 80, height: 80, border: "1px solid #ccc" }} | ||
/> | ||
</Badge> | ||
<input | ||
type="file" | ||
accept="image/*" | ||
onChange={(e) => { | ||
if (e.target.files) { | ||
setFile(e.target.files[0]); | ||
} | ||
}} | ||
style={{ display: "none" }} | ||
/> | ||
</label> | ||
<Stack gap={2} width="100%"> | ||
<Stack direction="row" width="100%"> | ||
<Typography fontWeight="bold" width={120}> | ||
{"닉네임"} | ||
</Typography> | ||
<TextField | ||
disabled | ||
value={data?.nickname ?? ""} | ||
helperText={"닉네임은 수정할 수 없어요"} | ||
size="small" | ||
fullWidth | ||
autoComplete="off" | ||
/> | ||
</Stack> | ||
<Stack direction="row" width="100%"> | ||
<Typography fontWeight="bold" width={120}> | ||
{"자기소개"} | ||
</Typography> | ||
<TextField | ||
value={introduction ?? ""} | ||
onChange={({ target }) => { | ||
setIntroduction(target.value); | ||
}} | ||
helperText={ | ||
"나에 대해 소개해보세요, 좋아하는 술, 술의 맛, 음식 뭐든 좋아요" | ||
} | ||
size="small" | ||
fullWidth | ||
autoComplete="off" | ||
multiline | ||
rows={3} | ||
/> | ||
</Stack> | ||
</Stack> | ||
<Button disabled={isLoading} fullWidth onClick={submitHandler}> | ||
프로필 저장하기 | ||
</Button> | ||
</Stack> | ||
</> | ||
); | ||
}; | ||
|
||
export default UserInfoEditingForm; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.