diff --git a/frontend/src/components/landing/member/LandingMember.tsx b/frontend/src/components/landing/member/LandingMember.tsx index 56f5905..b26ed7a 100644 --- a/frontend/src/components/landing/member/LandingMember.tsx +++ b/frontend/src/components/landing/member/LandingMember.tsx @@ -8,6 +8,7 @@ import useUpdateUserStatus from "../../../hooks/common/member/useUpdateUserStatu import { DEFAULT_MEMBER } from "../../../constants/projects"; import { memberResponse } from "../../../types/DTO/authDTO"; import emitMemberStatusUpdate from "../../../utils/emitMemberStatusUpdate"; +import { STORAGE_KEY } from "../../../constants/storageKey"; interface LandingMemberProps { projectTitle: string; @@ -56,18 +57,20 @@ const LandingMember = ({ projectTitle }: LandingMemberProps) => { }; function selectStatusOption(option: string) { - emitMemberStatusUpdate(socket, { - ...myInfo, - status: USER_WORD_STATUS[option], - }); - if (option === USER_STATUS_WORD.away || option === USER_STATUS_WORD.off) { handleCanAddStatusEventListener(false); + localStorage.setItem(STORAGE_KEY.UPDATE_STATUS_WITH_INTENTION, "true"); removeUserStatusEventListener(); } else { handleCanAddStatusEventListener(true); + localStorage.removeItem(STORAGE_KEY.UPDATE_STATUS_WITH_INTENTION); addUserStatusEventListener(); } + + emitMemberStatusUpdate(socket, { + ...myInfo, + status: USER_WORD_STATUS[option], + }); } return ( diff --git a/frontend/src/components/landing/member/UserBlock.tsx b/frontend/src/components/landing/member/UserBlock.tsx index 4979901..c3a4323 100644 --- a/frontend/src/components/landing/member/UserBlock.tsx +++ b/frontend/src/components/landing/member/UserBlock.tsx @@ -12,19 +12,17 @@ const UserStateDisplay = ({ status }: { status: "on" | "off" | "away" }) => { return (
-

{text}

+

{text}

); }; -const UserBlock = ({ imageUrl, username, status }: UserBlockProps) => { - return ( -
- -

{username}

- -
- ); -}; +const UserBlock = ({ imageUrl, username, status }: UserBlockProps) => ( +
+ +

{username}

+ +
+); export default UserBlock; diff --git a/frontend/src/constants/storageKey.ts b/frontend/src/constants/storageKey.ts index 3cb1294..c900b23 100644 --- a/frontend/src/constants/storageKey.ts +++ b/frontend/src/constants/storageKey.ts @@ -1,4 +1,5 @@ export const STORAGE_KEY = { MEMBER: "member", REDIRECT: "redirect", + UPDATE_STATUS_WITH_INTENTION: "updateStatusWithIntention", }; diff --git a/frontend/src/hooks/common/member/useAwayUser.ts b/frontend/src/hooks/common/member/useAwayUser.ts index a6bcf60..d40c59e 100644 --- a/frontend/src/hooks/common/member/useAwayUser.ts +++ b/frontend/src/hooks/common/member/useAwayUser.ts @@ -3,6 +3,7 @@ import { Socket } from "socket.io-client"; import useMemberStore from "../../../stores/useMemberStore"; import useThrottle from "../throttle/useThrottle"; import emitMemberStatusUpdate from "../../../utils/emitMemberStatusUpdate"; +import { STORAGE_KEY } from "../../../constants/storageKey"; const useAwayUser = (socket: Socket) => { const timerRef = useRef(null); @@ -70,6 +71,13 @@ const useAwayUser = (socket: Socket) => { addUserStatusEventListener(); } + if ( + localStorage.getItem(STORAGE_KEY.UPDATE_STATUS_WITH_INTENTION) === "true" + ) { + removeUserStatusEventListener(); + return; + } + return () => { removeUserStatusEventListener(); }; diff --git a/frontend/src/hooks/common/member/useUpdateUserStatus.ts b/frontend/src/hooks/common/member/useUpdateUserStatus.ts index c3c3e44..943f623 100644 --- a/frontend/src/hooks/common/member/useUpdateUserStatus.ts +++ b/frontend/src/hooks/common/member/useUpdateUserStatus.ts @@ -1,3 +1,4 @@ +import { useEffect, useRef } from "react"; import { Socket } from "socket.io-client"; import { LandingSocketData, @@ -6,8 +7,8 @@ import { } from "../../../types/common/landing"; import { LandingDTO, LandingMemberDTO } from "../../../types/DTO/landingDTO"; import useMemberStore from "../../../stores/useMemberStore"; -import { useEffect, useRef } from "react"; import { USER_STATUS_WORD } from "../../../constants/landing"; +import sortMemberByStatus from "../../../utils/sortMemberByStatus"; const useUpdateUserStatus = ( socket: Socket, @@ -22,11 +23,11 @@ const useUpdateUserStatus = ( addMember, } = useMemberStore(); const inviteLinkIdRef = useRef(""); - const handleInitEvent = (content: LandingDTO) => { const { myInfo, member: memberList, inviteLinkId } = content; updateMyInfo(myInfo); - updateMemberList(memberList); + handleChangeStatus(USER_STATUS_WORD[myInfo.status]); + updateMemberList(memberList.sort(sortMemberByStatus)); inviteLinkIdRef.current = inviteLinkId; }; @@ -51,16 +52,18 @@ const useUpdateUserStatus = ( } updateMemberList( - memberList.map((member) => { - if (member.id === content.id) { - return { - ...member, - status: (content as LandingMemberDTO).status, - }; - } + memberList + .map((member) => { + if (member.id === content.id) { + return { + ...member, + status: (content as LandingMemberDTO).status, + }; + } - return member; - }) + return member; + }) + .sort(sortMemberByStatus) ); break; diff --git a/frontend/src/hooks/common/socket/useLandingSocket.ts b/frontend/src/hooks/common/socket/useLandingSocket.ts index fcbeb33..1f4b2d5 100644 --- a/frontend/src/hooks/common/socket/useLandingSocket.ts +++ b/frontend/src/hooks/common/socket/useLandingSocket.ts @@ -1,68 +1,27 @@ import { Socket } from "socket.io-client"; import { useEffect, useState } from "react"; -import { - LandingDTO, - LandingLinkDTO, - LandingMemoDTO, - LandingProjectDTO, - LandingSprintDTO, -} from "../../../types/DTO/landingDTO"; +import { LandingDTO, LandingProjectDTO } from "../../../types/DTO/landingDTO"; import { DEFAULT_VALUE } from "../../../constants/landing"; import { LandingSocketData, LandingSocketDomain, - LandingSocketMemoAction, } from "../../../types/common/landing"; const useLandingSocket = (socket: Socket) => { const [project, setProject] = useState( DEFAULT_VALUE.PROJECT ); - const [sprint, setSprint] = useState(null); - const [memoList, setMemoList] = useState([]); - const [link, setLink] = useState([]); const handleInitEvent = (content: LandingDTO) => { - const { project, sprint, memoList, link } = content as LandingDTO; + const { project } = content as LandingDTO; setProject(project); - setSprint(sprint); - setMemoList(memoList); - setLink(link); }; - const handleMemoEvent = ( - action: LandingSocketMemoAction, - content: LandingMemoDTO - ) => { - switch (action) { - case LandingSocketMemoAction.CREATE: - setMemoList((memoList: LandingMemoDTO[]) => [content, ...memoList]); - break; - case LandingSocketMemoAction.DELETE: - setMemoList((memoList: LandingMemoDTO[]) => - memoList.filter((memo: LandingMemoDTO) => memo.id !== content.id) - ); - break; - case LandingSocketMemoAction.COLOR_UPDATE: - setMemoList((memoList: LandingMemoDTO[]) => - memoList.map((memo: LandingMemoDTO) => { - if (memo.id !== content.id) { - return memo; - } - return { ...memo, color: content.color }; - }) - ); - } - }; - - const handleOnLanding = ({ domain, action, content }: LandingSocketData) => { + const handleOnLanding = ({ domain, content }: LandingSocketData) => { switch (domain) { case LandingSocketDomain.INIT: handleInitEvent(content); break; - case LandingSocketDomain.MEMO: - handleMemoEvent(action, content); - break; } }; @@ -77,9 +36,6 @@ const useLandingSocket = (socket: Socket) => { return { project, - sprint, - memoList, - link, }; }; diff --git a/frontend/src/test/sortMemberByStatus.test.ts b/frontend/src/test/sortMemberByStatus.test.ts new file mode 100644 index 0000000..cbf6504 --- /dev/null +++ b/frontend/src/test/sortMemberByStatus.test.ts @@ -0,0 +1,20 @@ +import { LandingMemberDTO } from "../types/DTO/landingDTO"; +import sortMemberByStatus from "../utils/sortMemberByStatus"; + +describe("sortMemberByStatus test", () => { + it("on, away, off 순 정렬 테스트", () => { + const memberList: LandingMemberDTO[] = [ + { id: 1, username: "", imageUrl: "", status: "off" }, + { id: 2, username: "", imageUrl: "", status: "on" }, + { id: 3, username: "", imageUrl: "", status: "away" }, + { id: 4, username: "", imageUrl: "", status: "on" }, + { id: 5, username: "", imageUrl: "", status: "off" }, + { id: 6, username: "", imageUrl: "", status: "away" }, + ]; + + const sortedMemberIdList = memberList + .sort(sortMemberByStatus) + .map(({ id }) => id); + expect(sortedMemberIdList).toStrictEqual([2, 4, 3, 6, 1, 5]); + }); +}); diff --git a/frontend/src/utils/sortMemberByStatus.ts b/frontend/src/utils/sortMemberByStatus.ts new file mode 100644 index 0000000..7696151 --- /dev/null +++ b/frontend/src/utils/sortMemberByStatus.ts @@ -0,0 +1,32 @@ +import { LandingMemberDTO, MemberStatus } from "../types/DTO/landingDTO"; + +const getStatusOrder = (status: MemberStatus) => { + if (status === "on") { + return 2; + } + + if (status === "away") { + return 1; + } + + return 0; +}; + +const sortMemberByStatus = ( + member1: LandingMemberDTO, + member2: LandingMemberDTO +) => { + const member1Status = getStatusOrder(member1.status); + const member2Status = getStatusOrder(member2.status); + if (member1Status > member2Status) { + return -1; + } + + if (member1Status < member2Status) { + return 1; + } + + return 0; +}; + +export default sortMemberByStatus;