Skip to content

Commit f30e933

Browse files
committed
Merge branch 'dev' of https://github.com/oodd-team/oodd-web-react into feat/OD-132
2 parents 5351bcb + 357a635 commit f30e933

File tree

13 files changed

+169
-61
lines changed

13 files changed

+169
-61
lines changed

.github/workflows/prod_cicd.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ jobs:
3636
echo "VITE_GOOGLE_CLIENT_ID=${{ secrets.VITE_GOOGLE_CLIENT_ID }}" >> .env
3737
echo "VITE_GOOGLE_CLIENT_SECRET=${{ secrets.VITE_GOOGLE_CLIENT_SECRET }}" >> .env
3838
39-
- run: yarn build-prod
39+
- run: yarn build
4040

4141
- name: deploy to s3
4242
uses: jakejarvis/s3-sync-action@master

src/assets/default/x.svg

Lines changed: 1 addition & 1 deletion
Loading

src/components/TopBar/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ const TopBar: React.FC<TopBarProps> = ({
2828
>
2929
<img src={LeftButtonSrc || ''} alt="뒤로가기" />
3030
</LeftButton>
31-
<StyledTextLayout $textTheme={{ style: 'heading2-bold' }} color={theme.colors.black}>
31+
<StyledTextLayout $textTheme={{ style: 'body1-bold' }} color={theme.colors.black}>
3232
{text}
3333
</StyledTextLayout>
3434
<RightButton

src/components/TopBar/styles.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ export const TopbarLayout = styled.header<TopbarLayoutProps>`
99
z-index: 1;
1010
background-color: white;
1111
width: 100%; /* 부모 너비에 맞춤 */
12-
height: 2.75rem;
1312
align-items: center;
1413
padding: 0.5rem 1.25rem;
1514
${({ $withBorder, theme }) =>

src/pages/Chats/ChatRoom/index.tsx

Lines changed: 58 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ import Block from '../../../assets/default/block.svg';
2727
import dayjs from 'dayjs';
2828
import 'dayjs/locale/ko';
2929
import { chatRoomMessagesData } from '../../../apis/chatting/dto';
30+
import { postUserBlockApi } from '../../../apis/user';
31+
import { PostUserBlockRequest } from '../../../apis/user/dto';
32+
import { handleError } from '../../../apis/util/handleError';
3033

3134
const ChatRoom: React.FC = () => {
3235
const [extendedMessages, setextendedMessages] = useState<ExtendedMessageDto[]>([]);
@@ -36,6 +39,7 @@ const ChatRoom: React.FC = () => {
3639
const [isLeaveModalOpen, setIsLeaveModalOpen] = useState(false);
3740
const [isBlockModalOpen, setIsBlockModalOpen] = useState(false);
3841
const [isStatusModalOpen, setIsStatusModalOpen] = useState(false);
42+
const [modalContent, setModalContent] = useState('');
3943

4044
const [isLoading, setIsLoading] = useState(true);
4145
const [isScroll, setIsScroll] = useState(false);
@@ -50,6 +54,53 @@ const ChatRoom: React.FC = () => {
5054
const nav = useNavigate();
5155
const socket = useSocket();
5256

57+
// 프로필 사진 클릭 시 프로필 페이지로 이동
58+
const handleUserClick = useCallback(() => {
59+
const opponentId = opponentInfo?.id ? opponentInfo.id : -1;
60+
if (opponentId === -1) {
61+
setModalContent('유저 정보를 찾을 수 없습니다.');
62+
setIsStatusModalOpen(true);
63+
} else {
64+
nav(`/users/${opponentId}`);
65+
}
66+
}, [opponentInfo, nav]);
67+
68+
// 유저 차단 api
69+
const postUserBlock = async () => {
70+
try {
71+
const data: PostUserBlockRequest = {
72+
fromUserId: userId,
73+
toUserId: opponentInfo?.id || -1,
74+
action: 'block',
75+
};
76+
const response = await postUserBlockApi(data);
77+
78+
if (response.isSuccess) {
79+
setModalContent('정상적으로 처리되었습니다.');
80+
nav('/chats');
81+
}
82+
} catch (error) {
83+
const errorMessage = handleError(error, 'user');
84+
setModalContent(errorMessage);
85+
} finally {
86+
setIsBlockModalOpen(false);
87+
setIsStatusModalOpen(true);
88+
}
89+
};
90+
91+
// 채팅방 나가기 api
92+
const leaveChatRoom = () => {
93+
if (socket) {
94+
const data = {
95+
chatRoomId: Number(chatRoomId),
96+
userId: userId,
97+
};
98+
socket.emit('leaveChatRoom', data);
99+
nav('/chats', { replace: true });
100+
}
101+
};
102+
103+
// 전체 메시지 조회
53104
const getChatRoomMessages = (data: chatRoomMessagesData[]) => {
54105
setAllMessages(data);
55106
if (data.length > messageLengthRef.current) {
@@ -58,6 +109,7 @@ const ChatRoom: React.FC = () => {
58109
setIsLoading(false);
59110
};
60111

112+
// 새 메시지 수신
61113
const getNewMessage = (data: chatRoomMessagesData) => {
62114
setAllMessages((prevMessages) => [...prevMessages, data]);
63115
setIsScroll((prev) => !prev);
@@ -66,10 +118,10 @@ const ChatRoom: React.FC = () => {
66118
useEffect(() => {
67119
if (socket) {
68120
// 채팅방 입장
69-
socket.emit('joinChatRoom', chatRoomId);
121+
socket.emit('joinChatRoom', { chatRoomId: Number(chatRoomId) });
70122

71123
// 전체 메시지 조회
72-
socket.emit('getChatRoomMessages', chatRoomId);
124+
socket.emit('getChatRoomMessages', { chatRoomId: Number(chatRoomId) });
73125
socket.on('chatRoomMessages', getChatRoomMessages);
74126

75127
// 최근 메시지 조회
@@ -140,7 +192,7 @@ const ChatRoom: React.FC = () => {
140192
isCloseButtonVisible: true,
141193
button: {
142194
content: '나가기',
143-
onClick: () => {},
195+
onClick: leaveChatRoom,
144196
},
145197
onClose: () => {
146198
setIsLeaveModalOpen(false);
@@ -152,15 +204,15 @@ const ChatRoom: React.FC = () => {
152204
isCloseButtonVisible: true,
153205
button: {
154206
content: '차단하기',
155-
onClick: () => {},
207+
onClick: postUserBlock,
156208
},
157209
onClose: () => {
158210
setIsBlockModalOpen(false);
159211
},
160212
};
161213

162214
const statusModalProps: ModalProps = {
163-
content: '사용자 정보가 없습니다',
215+
content: modalContent,
164216
onClose: () => {
165217
setIsStatusModalOpen(false);
166218
},
@@ -176,16 +228,6 @@ const ChatRoom: React.FC = () => {
176228
},
177229
};
178230

179-
// 프로필 사진 클릭 시 프로필 페이지로 이동
180-
const onClickProfile = useCallback(() => {
181-
const opponentId = opponentInfo?.id ? opponentInfo.id : -1;
182-
if (opponentId === -1) {
183-
setIsStatusModalOpen(true);
184-
} else {
185-
nav(`/users/${opponentId}`);
186-
}
187-
}, [opponentInfo, nav]);
188-
189231
return (
190232
<OODDFrame>
191233
{isLoading && <Loading />}
@@ -215,7 +257,7 @@ const ChatRoom: React.FC = () => {
215257
{message.sentMessage ? (
216258
<SentMessage {...message.sentMessage} />
217259
) : message.rcvdMessage ? (
218-
<RcvdMessage {...message.rcvdMessage} onClickProfile={onClickProfile} />
260+
<RcvdMessage {...message.rcvdMessage} onClickProfile={handleUserClick} />
219261
) : null}
220262
</div>
221263
);

src/pages/Chats/ChatRoomItem/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,10 @@ const ChatRoomItem: React.FC<ChatRoomData> = ({ chatRoomId, otherUser, latestMes
4040

4141
return (
4242
<ChatRoomItemLayout onClick={onClickChatRoom}>
43-
<UserImage src={otherUser.profilePictureUrl || defaultProfile} alt="user" />
43+
<UserImage src={otherUser?.profilePictureUrl || defaultProfile} alt="user" />
4444
<LeftBox>
4545
<StyledText $textTheme={{ style: 'body2-medium' }} color="#1D1D1D">
46-
{otherUser.nickname || '알수없음'}
46+
{otherUser?.nickname || '알수없음'}
4747
</StyledText>
4848
<LatestMessage $textTheme={{ style: 'caption2-regular' }} color="#1D1D1D">
4949
{latestMessage.content}

src/pages/Chats/RecentChat/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ const RecentChat: React.FC<RecentChatProps> = () => {
2727
};
2828

2929
if (socket) {
30-
socket.emit('getChatRooms', userId);
30+
socket.emit('getChatRooms', { userId: userId });
3131
socket.on('chatRoomList', getChatRooms);
3232
}
3333

src/pages/Chats/Request/Cards/Card/index.tsx

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
ArrowButton,
1010
Btn,
1111
CardLayout,
12+
OOTDImgBackground,
1213
OOTDImgBox,
1314
ProfileContainer,
1415
ProfileImgBox,
@@ -66,6 +67,10 @@ const Card: React.FC<CardProps> = ({ removeRejectedMatching, matching }) => {
6667
}
6768
};
6869

70+
const handleUserClick = () => {
71+
nav(`/users/${matching.requester.requesterId}`);
72+
};
73+
6974
const handleRejectButtonClick = () => {
7075
modifyMatchingStatus('reject');
7176
};
@@ -85,16 +90,27 @@ const Card: React.FC<CardProps> = ({ removeRejectedMatching, matching }) => {
8590
<CardLayout>
8691
{isStatusModalOpen && <Modal {...statusModalProps} />}
8792
<ProfileContainer>
88-
<ProfileImgBox>
93+
<ProfileImgBox onClick={handleUserClick}>
8994
<img src={requester.profilePictureUrl || defaultProfile} alt="profile" />
9095
</ProfileImgBox>
9196
<ProfileInfo>
92-
<StyledText $textTheme={{ style: 'body1-medium' }} color={theme.colors.black}>
97+
<StyledText $textTheme={{ style: 'body1-medium' }} color={theme.colors.black} onClick={handleUserClick}>
9398
{requester.nickname || '알수없음'}
9499
</StyledText>
95-
<StyledText $textTheme={{ style: 'caption2-regular' }} color={theme.colors.gray1}>
96-
{matching.requesterPost.styleTags}
97-
</StyledText>
100+
<div className="row-flex">
101+
{matching.requesterPost.styleTags.map((tag, index) => (
102+
<div className="row-flex" key={tag}>
103+
<StyledText $textTheme={{ style: 'caption2-regular' }} color={theme.colors.gray1}>
104+
{tag}
105+
</StyledText>
106+
{index < matching.requesterPost.styleTags.length - 1 && (
107+
<StyledText $textTheme={{ style: 'caption2-regular' }} color={theme.colors.gray1}>
108+
,&nbsp;
109+
</StyledText>
110+
)}
111+
</div>
112+
))}
113+
</div>
98114
</ProfileInfo>
99115
<SeeMore onClick={() => nav(`/users/${requester.requesterId}`)}>
100116
<StyledText $textTheme={{ style: 'caption2-regular' }} color="#8e8e93">
@@ -106,15 +122,19 @@ const Card: React.FC<CardProps> = ({ removeRejectedMatching, matching }) => {
106122
<OOTDImgBox>
107123
<Swiper
108124
direction="vertical"
125+
slidesPerView={1}
126+
effect="slide"
109127
pagination={{
110128
clickable: true,
111129
}}
112130
modules={[Pagination]}
113131
className="childSwiper"
114132
>
115-
{matching.requesterPost.postImages.map((image) => (
116-
<SwiperSlide key={image.url}>
117-
<img src={image.url} alt="OOTD" className="slide-image-small" />
133+
{matching.requesterPost.postImages.map((postImage) => (
134+
<SwiperSlide key={postImage.url}>
135+
<img src={postImage.url} alt="OOTD" className="slide-image-small" />
136+
<div className="blur"></div>
137+
<OOTDImgBackground $src={postImage.url} />
118138
</SwiperSlide>
119139
))}
120140
</Swiper>

src/pages/Chats/Request/Cards/Card/styles.tsx

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ export const CardLayout = styled.div`
55
background-color: #ececec;
66
border-radius: 0.5rem;
77
position: relative;
8+
height: 100%;
89
`;
910

1011
export const ProfileContainer = styled.div`
@@ -37,6 +38,10 @@ export const ProfileImgBox = styled.div`
3738
export const ProfileInfo = styled.div`
3839
gap: 0.463rem;
3940
cursor: pointer;
41+
42+
.row-flex {
43+
display: flex;
44+
}
4045
`;
4146

4247
export const SeeMore = styled.div`
@@ -57,24 +62,38 @@ export const ArrowButton = styled.button`
5762
export const OOTDImgBox = styled.div`
5863
position: relative;
5964
width: 100%;
60-
bottom: 0;
65+
height: 100%;
6166
border-radius: 0 0 0.5rem 0.5rem;
62-
background-color: #d9d9d9;
6367
overflow: hidden;
64-
margin: 0 auto;
6568
display: flex;
6669
justify-content: center;
70+
align-items: center;
6771
aspect-ratio: 1/1;
6872
6973
.slide-image-small {
7074
width: 100%;
75+
max-width: 640px;
7176
height: 100%;
72-
object-fit: cover;
73-
aspect-ratio: 4/5;
77+
object-fit: contain;
78+
}
79+
80+
.childSwiper {
81+
z-index: 10;
82+
// align-items: stretch;
83+
width: 100%;
84+
height: 100%;
85+
}
86+
87+
.childSwiper .swiper-slide {
88+
display: flex;
89+
justify-content: center;
7490
}
7591
7692
.childSwiper .swiper-pagination {
93+
position: absolute;
7794
right: 1.25rem;
95+
z-index: 10;
96+
pointer-events: none; /* 마우스 이벤트 무시 */
7897
}
7998
8099
.childSwiper .swiper-pagination-bullet {
@@ -83,6 +102,7 @@ export const OOTDImgBox = styled.div`
83102
border: 0.0625rem solid ${({ theme }) => theme.colors.white};
84103
background: rgba(255, 255, 255, 0.5);
85104
opacity: 1;
105+
pointer-events: auto; /* 페이지네이션 클릭 가능 */
86106
}
87107
88108
.childSwiper .swiper-pagination-bullet-active {
@@ -92,9 +112,28 @@ export const OOTDImgBox = styled.div`
92112
opacity: 1;
93113
}
94114
95-
.childSwiper .swiper-slide-small img {
115+
.childSwiper .slide-small {
96116
transition: none !important;
97117
}
118+
119+
.blur {
120+
position: absolute;
121+
z-index: -10;
122+
width: 100%;
123+
height: 100%;
124+
background: rgba(177, 177, 177, 0.5);
125+
backdrop-filter: blur(100px);
126+
}
127+
`;
128+
129+
export const OOTDImgBackground = styled.div<{ $src: string }>`
130+
width: 100%;
131+
height: 100%;
132+
position: absolute;
133+
z-index: -20;
134+
background-image: url(${({ $src }) => $src});
135+
background-repeat: no-repeat;
136+
background-size: cover;
98137
`;
99138

100139
export const Reaction = styled.div`

0 commit comments

Comments
 (0)