diff --git a/public/House with garden.svg b/public/House with garden.svg
new file mode 100644
index 0000000000..c08ad15b1d
--- /dev/null
+++ b/public/House with garden.svg
@@ -0,0 +1,14 @@
+
diff --git a/src/app/pages/mobile/mobile-profile-page.tsx b/src/app/pages/mobile/mobile-profile-page.tsx
index 20c6b7a937..fee3c45928 100644
--- a/src/app/pages/mobile/mobile-profile-page.tsx
+++ b/src/app/pages/mobile/mobile-profile-page.tsx
@@ -1,5 +1,6 @@
'use client';
+import axios from 'axios';
import Link from 'next/link';
import React, { useState, useEffect } from 'react';
import styled from 'styled-components';
@@ -7,9 +8,9 @@ import styled from 'styled-components';
import { Bookmark } from '@/components';
import { useAuthValue, useUserData } from '@/features/auth';
import {
+ type GetFollowingListDTO,
useCertification,
useFollowUser,
- useFollowingListData,
useGetCode,
useUnfollowUser,
useUserProfile,
@@ -312,10 +313,30 @@ function UserInfo({
}: UserProfileInfoProps) {
const [isChecked, setIsChecked] = useState(false);
- const followList = useFollowingListData();
- const [isMarked, setIsMarked] = useState(
- followList.data?.data.followingList[memberId] != null,
- );
+ const [followList, setFollowList] = useState>();
+ const [isMarked, setIsMarked] = useState(false);
+
+ useEffect(() => {
+ if (followList?.[memberId] != null) {
+ setIsMarked(true);
+ } else setIsMarked(false);
+ }, [followList]);
+
+ useEffect(() => {
+ (async () => {
+ try {
+ const res = await axios.get(
+ '/maru-api/profile/follow',
+ );
+ const followListData = res.data.data.followingList;
+ setFollowList(followListData);
+ return true;
+ } catch (error) {
+ console.error(error);
+ return false;
+ }
+ })();
+ }, [setIsMarked]);
const toggleSwitch = () => {
setIsChecked(!isChecked);
diff --git a/src/app/pages/mobile/mobile-shared-post-page.tsx b/src/app/pages/mobile/mobile-shared-post-page.tsx
index 49ef50159a..721fe1f20a 100644
--- a/src/app/pages/mobile/mobile-shared-post-page.tsx
+++ b/src/app/pages/mobile/mobile-shared-post-page.tsx
@@ -6,7 +6,7 @@ import styled from 'styled-components';
import { Bookmark, CircularProfileImage } from '@/components';
import { ImageGrid } from '@/components/shared-post-page';
-import { useAuthValue, useUserData } from '@/features/auth';
+import { useAuthValue } from '@/features/auth';
import { useCreateChatRoom } from '@/features/chat';
import { fromAddrToCoord } from '@/features/geocoding';
import { useFollowUser, useUnfollowUser } from '@/features/profile';
@@ -445,15 +445,6 @@ export function MobileSharedPostPage({
enabled: type === 'dormitory' && auth?.accessToken != null,
});
- const { data: userData } = useUserData(auth?.accessToken != null);
- const [userId, setUserId] = useState('');
-
- useEffect(() => {
- if (userData != null) {
- setUserId(userData.memberId);
- }
- }, [userData]);
-
useEffect(() => {
if (sharedPost?.data.address.roadAddress != null) {
fromAddrToCoord({ query: sharedPost?.data.address.roadAddress }).then(
@@ -474,16 +465,7 @@ export function MobileSharedPostPage({
}
}, [sharedPost]);
- const [roomName, setRoomName] = useState('');
-
- useEffect(() => {
- if (sharedPost !== undefined) {
- setRoomName(sharedPost.data.publisherAccount.nickname);
- }
- }, [sharedPost]);
-
- const members = [userId];
- const { mutate: chattingMutate } = useCreateChatRoom(roomName, members);
+ const { mutate: chattingMutate } = useCreateChatRoom();
const isLoading = useMemo(
() =>
@@ -574,7 +556,12 @@ export function MobileSharedPostPage({
{
- chattingMutate();
+ if (selected == null) return;
+
+ chattingMutate({
+ roomName: selected.nickname,
+ members: [selected.memberId],
+ });
}}
>
채팅
diff --git a/src/app/pages/profile-page.tsx b/src/app/pages/profile-page.tsx
index afeae53605..94feb29e1d 100644
--- a/src/app/pages/profile-page.tsx
+++ b/src/app/pages/profile-page.tsx
@@ -1,5 +1,6 @@
'use client';
+import axios from 'axios';
import Link from 'next/link';
import React, { useState, useEffect } from 'react';
import styled from 'styled-components';
@@ -7,9 +8,9 @@ import styled from 'styled-components';
import { Bookmark } from '@/components';
import { useAuthValue, useUserData } from '@/features/auth';
import {
+ type GetFollowingListDTO,
useCertification,
useFollowUser,
- useFollowingListData,
useGetCode,
useUnfollowUser,
useUserProfile,
@@ -443,10 +444,30 @@ function UserInfo({
}: UserProfileInfoProps) {
const [isChecked, setIsChecked] = useState(false);
- const followList = useFollowingListData();
- const [isMarked, setIsMarked] = useState(
- followList.data?.data.followingList[memberId] != null,
- );
+ const [followList, setFollowList] = useState>();
+ const [isMarked, setIsMarked] = useState(false);
+
+ useEffect(() => {
+ if (followList?.[memberId] != null) {
+ setIsMarked(true);
+ } else setIsMarked(false);
+ }, [followList]);
+
+ useEffect(() => {
+ (async () => {
+ try {
+ const res = await axios.get(
+ '/maru-api/profile/follow',
+ );
+ const followListData = res.data.data.followingList;
+ setFollowList(followListData);
+ return true;
+ } catch (error) {
+ console.error(error);
+ return false;
+ }
+ })();
+ }, [setIsMarked]);
const toggleSwitch = () => {
setIsChecked(!isChecked);
diff --git a/src/app/pages/shared-post-page.tsx b/src/app/pages/shared-post-page.tsx
index 1f3035e703..ad56004904 100644
--- a/src/app/pages/shared-post-page.tsx
+++ b/src/app/pages/shared-post-page.tsx
@@ -2,12 +2,13 @@
import { useRouter } from 'next/navigation';
import { useEffect, useMemo, useRef, useState } from 'react';
+import { useRecoilState } from 'recoil';
import styled from 'styled-components';
import { Bookmark, CircularProfileImage } from '@/components';
import { CardToggleButton, ImageGrid } from '@/components/shared-post-page';
-import { useAuthValue, useUserData } from '@/features/auth';
-import { useCreateChatRoom } from '@/features/chat';
+import { useAuthValue } from '@/features/auth';
+import { chatOpenState, useCreateChatRoom } from '@/features/chat';
import { fromAddrToCoord } from '@/features/geocoding';
import { useFollowUser, useUnfollowUser } from '@/features/profile';
import {
@@ -496,15 +497,6 @@ export function SharedPostPage({
enabled: type === 'dormitory' && auth?.accessToken != null,
});
- const { data: userData } = useUserData(auth?.accessToken != null);
- const [userId, setUserId] = useState('');
-
- useEffect(() => {
- if (userData != null) {
- setUserId(userData.memberId);
- }
- }, [userData]);
-
useEffect(() => {
if (sharedPost?.data.address.roadAddress != null) {
fromAddrToCoord({ query: sharedPost?.data.address.roadAddress }).then(
@@ -525,15 +517,9 @@ export function SharedPostPage({
}
}, [sharedPost]);
- const [roomName, setRoomName] = useState('');
+ const [, setIsChatOpen] = useRecoilState(chatOpenState);
- useEffect(() => {
- if (sharedPost !== undefined) {
- setRoomName(sharedPost.data.publisherAccount.nickname);
- }
- }, [sharedPost]);
-
- const { mutate: chattingMutate } = useCreateChatRoom(roomName, [userId]);
+ const { mutate: chattingMutate } = useCreateChatRoom();
const isLoading = useMemo(
() =>
@@ -754,7 +740,16 @@ export function SharedPostPage({
{
- chattingMutate();
+ if (selected == null) return;
+
+ chattingMutate({
+ roomName: selected.nickname,
+ members: [selected.memberId],
+ });
+
+ setTimeout(() => {
+ setIsChatOpen(true);
+ }, 200);
}}
>
채팅하기
diff --git a/src/components/FloatingChatting.tsx b/src/components/FloatingChatting.tsx
index 268e2d733d..8f20cdc569 100644
--- a/src/components/FloatingChatting.tsx
+++ b/src/components/FloatingChatting.tsx
@@ -4,13 +4,14 @@ import { Client } from '@stomp/stompjs';
import axios from 'axios';
import { useRouter } from 'next/navigation';
import React, { useEffect, useState } from 'react';
+import { useRecoilState } from 'recoil';
import styled from 'styled-components';
import { ChattingList } from './chat/ChattingList';
import { ChattingRoom } from './chat/ChattingRoom';
import { useAuthValue, useUserData } from '@/features/auth';
-import { type GetChatRoomDTO } from '@/features/chat';
+import { chatOpenState, type GetChatRoomDTO } from '@/features/chat';
import { useIsMobile } from '@/shared/mobile';
const styles = {
@@ -246,7 +247,7 @@ function FloatingChattingBox() {
}, [message, isChatRoomOpen]);
// const roomName = 'test2';
- // const members = ['naver_htT4VdDRPKqGqKpnncpa71HCA4CVg5LdRC1cWZhCnF8'];
+ // const members = ['naver_hW_CDCYdU3NNTQWq_TV_MkpldnMZI6fOD1mnPo-V1NE'];
// const { mutate: chattingCreate } = useCreateChatRoom(roomName, members);
return (
@@ -269,12 +270,12 @@ function FloatingChattingBox() {
{/* */}
+ onClick={() => {
+ chattingCreate();
+ }}
+ >
+ 생성
+ */}
{chatRooms.map((room, index) => (
(false);
+ const [isChatOpen, setIsChatOpen] = useRecoilState(chatOpenState);
const router = useRouter();
const toggleChat = () => {
@@ -315,7 +316,6 @@ export function FloatingChatting() {
const isMobile = useIsMobile();
useEffect(() => {
- if (!isMobile) router.replace('/');
if (isChatOpen && isMobile) {
router.replace('/chat');
}
@@ -324,9 +324,14 @@ export function FloatingChatting() {
}
}, [isChatOpen, isMobile]);
+ useEffect(() => {
+ if (!isMobile && window.location.pathname === '/chat') {
+ router.replace('/');
+ }
+ }, [isMobile]);
+
const auth = useAuthValue();
if (auth == null) return <>>;
-
return (
<>
diff --git a/src/components/card/VitalSection.tsx b/src/components/card/VitalSection.tsx
index 32201a63cc..4eb359ccb0 100644
--- a/src/components/card/VitalSection.tsx
+++ b/src/components/card/VitalSection.tsx
@@ -348,7 +348,7 @@ export function VitalSection({
setFeatures(data);
}
- }, []);
+ }, [vitalFeatures]);
const handleEssentialFeatureChange = useCallback(
(key: 'smoking' | 'roomSharingOption' | 'mateAge', value: string) => {
diff --git a/src/components/chat/ChatMenu.tsx b/src/components/chat/ChatMenu.tsx
index 17083b6574..752b4b30fe 100644
--- a/src/components/chat/ChatMenu.tsx
+++ b/src/components/chat/ChatMenu.tsx
@@ -4,8 +4,8 @@ import Link from 'next/link';
import { useEffect, useState } from 'react';
import styled from 'styled-components';
-// import { useFollowingListData } from '@/features/profile';
-import { useChatRoomUser } from '@/features/chat';
+import { useChatRoomUser, useInviteUsers } from '@/features/chat';
+import { useSearchUser } from '@/features/profile';
const styles = {
menuContainer: styled.div`
@@ -169,7 +169,6 @@ const styles = {
followingUserContainer: styled.div`
display: flex;
padding: 0.625rem;
- justify-content: center;
align-items: center;
gap: 0.625rem;
align-self: stretch;
@@ -203,7 +202,6 @@ export function ChatMenu({
const [isInviteClick, setIsInviteClick] = useState(false);
const users = useChatRoomUser(roomId);
const [userList, setUserList] = useState([]);
- // const folloingUsers = useFollowingListData();
useEffect(() => {
if (users.data !== undefined) {
@@ -217,9 +215,26 @@ export function ChatMenu({
onMenuClicked(isCloseClick);
};
- // const { mutate: inviteUser } = useInviteUsers(roomId, [
- // 'naver_htT4VdDRPKqGqKpnncpa71HCA4CVg5LdRC1cWZhCnF8',
- // ]);
+ const [email, setEmail] = useState('');
+ const { mutate: mutateSearchUser, data: searchData } = useSearchUser(email);
+
+ const [searchUser, setSearchUser] = useState();
+
+ useEffect(() => {
+ if (searchData?.data != null) {
+ setSearchUser(searchData.data);
+ }
+ }, [searchData]);
+
+ const { mutate: inviteUser } = useInviteUsers(roomId, [
+ searchUser?.memberId ?? '',
+ ]);
+
+ function handleKeyUp(event: React.KeyboardEvent) {
+ if (event.keyCode === 13) {
+ mutateSearchUser();
+ }
+ }
return (
@@ -243,7 +258,6 @@ export function ChatMenu({
{
- // inviteUser();
setIsInviteClick(prev => !prev);
}}
>
@@ -253,30 +267,31 @@ export function ChatMenu({
-
+ {
+ setEmail(e.target.value);
+ }}
+ onKeyUp={handleKeyUp}
+ />
- {/* {Object.values(
- folloingUsers.data?.data.followingList as Record<
- string,
- string[]
- >,
- ).map((user, index) => (
+ {searchUser != null ? (
{
+ inviteUser();
+ }}
>
-
- {user[0]}
+
+ {searchUser?.nickname}
- ))} */}
+ ) : null}
)}
- 마이 마루
채팅방 나가기
diff --git a/src/components/chat/ChattingList.tsx b/src/components/chat/ChattingList.tsx
index f08723c0df..8ca149530d 100644
--- a/src/components/chat/ChattingList.tsx
+++ b/src/components/chat/ChattingList.tsx
@@ -33,7 +33,7 @@ const styles = {
width: 3rem;
height: 3rem;
border-radius: 50%;
- background: url('__avatar_url.png') lightgray 50% / cover no-repeat;
+ background: url('/House with garden.svg') lightgray 50% / cover no-repeat;
`,
roomName: styled.p`
color: #000;
diff --git a/src/components/chat/ChattingRoom.tsx b/src/components/chat/ChattingRoom.tsx
index e7941e4138..70c983ef3b 100644
--- a/src/components/chat/ChattingRoom.tsx
+++ b/src/components/chat/ChattingRoom.tsx
@@ -64,7 +64,7 @@ const styles = {
width: 1rem;
height: 1rem;
flex-shrink: 0;
- background: url('kebab-horizontal.svg') no-repeat;
+ background: url('/kebab-horizontal.svg') no-repeat;
cursor: pointer;
`,
messageContainer: styled.div`
@@ -147,6 +147,26 @@ function calTimeDiff(time: string, type: string) {
return `${Math.floor(timeDiff / (60 * 24))}일 전`;
}
+function useInterval(callback: () => void, delay: number) {
+ const savedCallback = useRef(callback);
+
+ useEffect(() => {
+ savedCallback.current = callback;
+ }, [callback]);
+
+ useEffect(() => {
+ if (delay != null) {
+ const id = setInterval(() => {
+ savedCallback.current();
+ }, delay);
+ return () => {
+ clearInterval(id);
+ };
+ }
+ return undefined;
+ }, [delay]);
+}
+
export function ChattingRoom({
userId,
userName,
@@ -241,7 +261,11 @@ export function ChattingRoom({
}, [auth?.accessToken]);
const sendMessage = () => {
- if (stompClient !== null && stompClient.connected) {
+ if (
+ stompClient !== null &&
+ stompClient.connected &&
+ inputMessage.length !== 0
+ ) {
const destination = `/send/${roomId}`;
stompClient.publish({
@@ -258,6 +282,16 @@ export function ChattingRoom({
setInputMessage('');
};
+ const [timeString, setTimeString] = useState(calTimeDiff(lastTime, 'server'));
+
+ useEffect(() => {
+ setTimeString(calTimeDiff(time, type));
+ }, [time, type]);
+
+ useInterval(() => {
+ setTimeString(calTimeDiff(time, type));
+ }, 60000);
+
const handleMenuClick = () => {
setIsMenuClick(prev => !prev);
};
@@ -301,7 +335,7 @@ export function ChattingRoom({
/>
{roomName}
- {calTimeDiff(time, type)}
+ {timeString}
{isMenuClick && (
diff --git a/src/components/chat/MobileChattingRoom.tsx b/src/components/chat/MobileChattingRoom.tsx
index 56d74ecc94..be2d7a7d49 100644
--- a/src/components/chat/MobileChattingRoom.tsx
+++ b/src/components/chat/MobileChattingRoom.tsx
@@ -143,6 +143,26 @@ function calTimeDiff(time: string, type: string) {
return `${Math.floor(timeDiff / (60 * 24))}일 전`;
}
+function useInterval(callback: () => void, delay: number) {
+ const savedCallback = useRef(callback);
+
+ useEffect(() => {
+ savedCallback.current = callback;
+ }, [callback]);
+
+ useEffect(() => {
+ if (delay != null) {
+ const id = setInterval(() => {
+ savedCallback.current();
+ }, delay);
+ return () => {
+ clearInterval(id);
+ };
+ }
+ return undefined;
+ }, [delay]);
+}
+
export function MobileChattingRoom({
userId,
userName,
@@ -254,6 +274,16 @@ export function MobileChattingRoom({
setInputMessage('');
};
+ const [timeString, setTimeString] = useState(calTimeDiff(lastTime, 'server'));
+
+ useEffect(() => {
+ setTimeString(calTimeDiff(time, type));
+ }, [time, type]);
+
+ useInterval(() => {
+ setTimeString(calTimeDiff(time, type));
+ }, 60000);
+
const handleMenuClick = () => {
setIsMenuClick(prev => !prev);
};
@@ -297,7 +327,7 @@ export function MobileChattingRoom({
/>
{roomName}
- {calTimeDiff(time, type)}
+ {timeString}
{isMenuClick && (
diff --git a/src/components/chat/ReceiverMessage.tsx b/src/components/chat/ReceiverMessage.tsx
index f0eab0367e..2ec6b250ab 100644
--- a/src/components/chat/ReceiverMessage.tsx
+++ b/src/components/chat/ReceiverMessage.tsx
@@ -25,7 +25,7 @@ const styles = {
height: 2rem;
border-radius: 50%;
flex-shrink: 0;
- background: url('__avatar_url.png') center no-repeat;
+ background: url('/__avatar_url.png') center no-repeat;
`,
userName: styled.p`
color: var(--Text-gray, #666668);
@@ -49,7 +49,7 @@ const styles = {
leftTop: styled.div`
width: 0.9375rem;
height: 0.75rem;
- background: url('Bubble tip R.svg') no-repeat;
+ background: url('/Bubble tip R.svg') no-repeat;
`,
leftMiddle: styled.div`
width: 0.375rem;
@@ -59,7 +59,7 @@ const styles = {
leftBottom: styled.div`
width: 0.375rem;
height: 0.4375rem;
- background: url('bottom-curve-vector R.svg') no-repeat;
+ background: url('/bottom-curve-vector R.svg') no-repeat;
`,
right: styled.div`
display: flex;
diff --git a/src/components/chat/SenderMessage.tsx b/src/components/chat/SenderMessage.tsx
index e26e1505a8..3e0a15f6cb 100644
--- a/src/components/chat/SenderMessage.tsx
+++ b/src/components/chat/SenderMessage.tsx
@@ -56,11 +56,6 @@ const styles = {
font-weight: 300;
line-height: normal;
`,
- readState: styled.div`
- width: 1rem;
- height: 0.5rem;
- background: url('read.svg') no-repeat;
- `,
left: styled.div`
display: flex;
flex-direction: column;
@@ -71,7 +66,7 @@ const styles = {
leftTop: styled.div`
width: 0.9375rem;
height: 0.75rem;
- background: url('Bubble tip.svg') no-repeat;
+ background: url('/Bubble tip.svg') no-repeat;
`,
leftMiddle: styled.div`
width: 0.375rem;
@@ -82,7 +77,7 @@ const styles = {
width: 0.375rem;
height: 0.4375rem;
fill: var(--Gray-5, #828282);
- background: url('bottom-curve-vector.svg') no-repeat;
+ background: url('/bottom-curve-vector.svg') no-repeat;
`,
};
@@ -103,7 +98,6 @@ export function SenderMessage({
{message}
{getLocalTime(time, type)}
-
diff --git a/src/features/chat/chat.api.ts b/src/features/chat/chat.api.ts
index 81cb1d41be..e7a5938be7 100644
--- a/src/features/chat/chat.api.ts
+++ b/src/features/chat/chat.api.ts
@@ -14,11 +14,17 @@ export const getChatRoomList = async (token: string | undefined) =>
})
.then(res => res.data);
-export const postChatRoom = async (roomName: string, members: string[]) => {
+export const postChatRoom = async ({
+ roomName,
+ members,
+}: {
+ roomName: string;
+ members: string[];
+}) => {
await axios
.post(`/maru-api/chatRoom`, {
- roomName: roomName,
- members: members,
+ roomName,
+ members,
})
.then(res => res.data);
};
@@ -26,7 +32,7 @@ export const postChatRoom = async (roomName: string, members: string[]) => {
export const postInviteUser = async (roomId: number, members: string[]) => {
await axios
.post(`/maru-api/chatRoom/${roomId}/invite`, {
- members: members,
+ members,
})
.then(res => res.data);
};
@@ -40,9 +46,9 @@ export const getEnterChatRoom = async (
`/maru-api/chatRoom/${roomId}/chat`,
{
params: {
- roomId: roomId,
- page: page,
- size: size,
+ roomId,
+ page,
+ size,
},
},
);
diff --git a/src/features/chat/chat.atom.ts b/src/features/chat/chat.atom.ts
new file mode 100644
index 0000000000..659c327b35
--- /dev/null
+++ b/src/features/chat/chat.atom.ts
@@ -0,0 +1,6 @@
+import { atom } from 'recoil';
+
+export const chatOpenState = atom({
+ key: 'isChatOpenState',
+ default: false,
+});
diff --git a/src/features/chat/chat.hook.ts b/src/features/chat/chat.hook.ts
index 3fdd47e077..c62388bab0 100644
--- a/src/features/chat/chat.hook.ts
+++ b/src/features/chat/chat.hook.ts
@@ -16,11 +16,9 @@ export const useChatRoomList = (token: string | undefined) =>
enabled: token !== undefined,
});
-export const useCreateChatRoom = (roomName: string, members: string[]) =>
+export const useCreateChatRoom = () =>
useMutation({
- mutationFn: async () => {
- await postChatRoom(roomName, members);
- },
+ mutationFn: postChatRoom,
});
export const useInviteUsers = (roomId: number, members: string[]) =>
diff --git a/src/features/chat/index.ts b/src/features/chat/index.ts
index be0e3149d5..ddc5adcc10 100644
--- a/src/features/chat/index.ts
+++ b/src/features/chat/index.ts
@@ -1,2 +1,3 @@
export * from './chat.hook';
export * from './chat.dto';
+export * from './chat.atom';
diff --git a/src/features/profile/index.ts b/src/features/profile/index.ts
index e342a017d1..6c4e6fb3d8 100644
--- a/src/features/profile/index.ts
+++ b/src/features/profile/index.ts
@@ -1 +1,2 @@
export * from './profile.hook';
+export * from './profile.dto';
diff --git a/src/features/profile/profile.api.ts b/src/features/profile/profile.api.ts
index 2c55463523..f8a342d9ee 100644
--- a/src/features/profile/profile.api.ts
+++ b/src/features/profile/profile.api.ts
@@ -39,10 +39,7 @@ export const putUserCard = async (
location,
features,
})
- .then(res => {
- console.log(res.data);
- return res.data;
- });
+ .then(res => res.data);
export const getFollowingListData = async () =>
await axios