From c5b93a4864b36f0df19471d9b89b998788bd4e08 Mon Sep 17 00:00:00 2001 From: Hojin Date: Wed, 24 Jan 2024 16:49:09 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=EC=BB=A4=EC=84=9C=EA=B3=B5=EC=9C=A0=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 1 + pnpm-lock.yaml | 11 +++ src/api/socket.ts | 3 +- src/components/Plan/PlanCursor.tsx | 94 +++++++++++++++++++++++++ src/components/Plan/PlanItem.tsx | 6 +- src/components/Plan/PlanOtherCursor.tsx | 63 +++++++++++++++++ src/components/Plan/PlanSectionTop.tsx | 19 ----- src/hooks/useSocket.ts | 27 ++++--- 8 files changed, 195 insertions(+), 29 deletions(-) create mode 100644 src/components/Plan/PlanCursor.tsx create mode 100644 src/components/Plan/PlanOtherCursor.tsx diff --git a/package.json b/package.json index 10b3be84..611f6d99 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "react-beautiful-dnd": "^13.1.1", "react-dom": "^18.2.0", "react-hook-form": "^7.49.2", + "react-icons": "^5.0.1", "react-infinite-scroller": "^1.2.6", "react-kakao-maps-sdk": "^1.1.24", "react-modal": "^3.16.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0720f243..71bfd5fe 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -77,6 +77,9 @@ dependencies: react-hook-form: specifier: ^7.49.2 version: 7.49.3(react@18.2.0) + react-icons: + specifier: ^5.0.1 + version: 5.0.1(react@18.2.0) react-infinite-scroller: specifier: ^1.2.6 version: 1.2.6(react@18.2.0) @@ -5145,6 +5148,14 @@ packages: react: 18.2.0 dev: false + /react-icons@5.0.1(react@18.2.0): + resolution: {integrity: sha512-WqLZJ4bLzlhmsvme6iFdgO8gfZP17rfjYEJ2m9RsZjZ+cc4k1hTzknEz63YS1MeT50kVzoa1Nz36f4BEx+Wigw==} + peerDependencies: + react: '*' + dependencies: + react: 18.2.0 + dev: false + /react-infinite-scroller@1.2.6(react@18.2.0): resolution: {integrity: sha512-mGdMyOD00YArJ1S1F3TVU9y4fGSfVVl6p5gh/Vt4u99CJOptfVu/q5V/Wlle72TMgYlBwIhbxK5wF0C/R33PXQ==} peerDependencies: diff --git a/src/api/socket.ts b/src/api/socket.ts index 93bc09d3..ff4101db 100644 --- a/src/api/socket.ts +++ b/src/api/socket.ts @@ -154,6 +154,7 @@ export const pubConnectMember = (pubMember: pubMember, tripId: string) => { destination: `/pub/trips/${tripId}/connectMember`, body: JSON.stringify(pubMember), }); + console.log('입장발생'); }; // 멤버 여정 페이지 퇴장 이벤트 발생시 @@ -162,6 +163,7 @@ export const pubDisconnectMember = (pubMember: pubMember, tripId: string) => { destination: `/pub/trips/${tripId}/disconnectMember`, body: JSON.stringify(pubMember), }); + console.log('퇴장발생'); }; // 여정 편집 페이지 입장 이벤트 발생시(모든 sub 다받음) @@ -206,5 +208,4 @@ export const pubCursor = (pubCursor: pubCursor, tripId: string) => { destination: `/pub/trips/${tripId}/cursor`, body: JSON.stringify(pubCursor), }); - console.log(pubCursor); }; diff --git a/src/components/Plan/PlanCursor.tsx b/src/components/Plan/PlanCursor.tsx new file mode 100644 index 00000000..48d10a01 --- /dev/null +++ b/src/components/Plan/PlanCursor.tsx @@ -0,0 +1,94 @@ +import { useEffect, useState, useContext } from 'react'; +import { BsFillCursorFill } from 'react-icons/bs'; +import { pubCursor } from '@api/socket'; +import { socketContext } from '@hooks/useSocket'; +import { useGetTripsAuthority } from '@hooks/useGetTripsAuthority'; + +type TripCursorData = { + memberId: number; + x: number; + y: number; + name: string; +}; + +type PlanCursorProps = { + date: string; +}; + +const PlanCursor = ({ date }: PlanCursorProps) => { + const token = localStorage.getItem('accessToken'); + const { memberId } = useGetTripsAuthority(); + const { callBackPub, tripId, tripMember } = useContext(socketContext); + const [position, setPosition] = useState({ x: 0, y: 0 }); + + const myName = tripMember?.data?.tripMembers.find( + (member) => member.memberId === memberId, + ); + + useEffect(() => { + const handleMouseMove = (e: MouseEvent) => { + setPosition({ x: e.clientX, y: e.clientY }); + }; + const cursorStyle = (style: string): void => { + document.querySelectorAll('*').forEach((el) => { + const element = el as HTMLElement; + element.style.cursor = style; + }); + }; + cursorStyle('none'); + document.addEventListener('mousemove', handleMouseMove); + return () => { + cursorStyle('auto'); + document.removeEventListener('mousemove', handleMouseMove); + }; + }, []); + + // useEffect(() => { + // if (token && position && myName && date && tripId) { + // const timeoutId = setTimeout(() => { + // callBackPub(() => + // pubCursor( + // { + // token: token, + // visitDate: date, + // x: position.x, + // y: position.y, + // }, + // tripId, + // ), + // ); + // }, 1000); + + // return () => clearTimeout(timeoutId); + // } + // }, [position]); + + useEffect(() => { + if (token && position && myName && date && tripId) { + callBackPub(() => + pubCursor( + { + token: token, + visitDate: date, + x: position.x, + y: position.y, + }, + tripId, + ), + ); + } + }, [position]); + + return ( +
+ +
+ {myName?.name} +
+
+ ); +}; + +export default PlanCursor; diff --git a/src/components/Plan/PlanItem.tsx b/src/components/Plan/PlanItem.tsx index 56def8f7..51ab0c63 100644 --- a/src/components/Plan/PlanItem.tsx +++ b/src/components/Plan/PlanItem.tsx @@ -11,6 +11,8 @@ import { visitDateState, isEditState } from '@recoil/socket'; import { pubGetPathAndItems, pubUpdateTransportation } from '@api/socket'; import { tapState } from '@recoil/plan'; import { useGetTripsAuthority } from '@hooks/useGetTripsAuthority'; +import PlanCursor from './PlanCursor'; +import PlanOtherCursor from './PlanOtherCursor'; type PlanItemProps = { date: string; @@ -62,8 +64,10 @@ const PlanItem: React.FC = ({ date, day }) => { return ( <> - {tripPath && } + + + {tripPath && }
{tripAuthority !== 'WRITE' || isEdit ? (
diff --git a/src/components/Plan/PlanOtherCursor.tsx b/src/components/Plan/PlanOtherCursor.tsx new file mode 100644 index 00000000..d8fa5090 --- /dev/null +++ b/src/components/Plan/PlanOtherCursor.tsx @@ -0,0 +1,63 @@ +import { useEffect, useState, useContext } from 'react'; +import { BsFillCursorFill } from 'react-icons/bs'; +import { pubCursor } from '@api/socket'; +import { socketContext } from '@hooks/useSocket'; +import { useGetTripsAuthority } from '@hooks/useGetTripsAuthority'; + +type TripCursorData = { + memberId: number; + x: number; + y: number; + name: string; +}; + +type PlanCursorProps = { + date: string; +}; + +const PlanOtherCursor = () => { + const { memberId } = useGetTripsAuthority(); + const { tripCursor } = useContext(socketContext); + const [otherCursors, setOtherCursors] = useState([]); + + console.log(otherCursors); + useEffect(() => { + if ( + tripCursor && + tripCursor.data && + tripCursor.data.memberId !== memberId + ) { + setOtherCursors((prevCursors) => { + const existingCursorIndex = prevCursors.findIndex( + (cursor) => cursor.memberId === tripCursor.data!.memberId, + ); + + if (existingCursorIndex !== -1) { + const updatedCursors = [...prevCursors]; + updatedCursors[existingCursorIndex] = tripCursor.data!; + return updatedCursors; + } else { + return [...prevCursors, tripCursor.data!]; + } + }); + } + }, [tripCursor, memberId]); + + return ( + <> + {otherCursors.map((cursor, index) => ( +
+ +
+ {cursor.name} +
+
+ ))} + + ); +}; + +export default PlanOtherCursor; diff --git a/src/components/Plan/PlanSectionTop.tsx b/src/components/Plan/PlanSectionTop.tsx index 6c03a1f7..fada423c 100644 --- a/src/components/Plan/PlanSectionTop.tsx +++ b/src/components/Plan/PlanSectionTop.tsx @@ -10,7 +10,6 @@ import { pubEnterMember, pubConnectMember, pubDisconnectMember, - pubCursor, } from '@api/socket'; import { useEffect } from 'react'; import { useRecoilState } from 'recoil'; @@ -34,7 +33,6 @@ const PlanSectionTop = () => { tripPath, tripMember, tripBudget, - tripCursor, } = useContext(socketContext); const [, setVisitDate] = useRecoilState(visitDateState); const { startDate, endDate } = useGetTrips(); @@ -47,8 +45,6 @@ const PlanSectionTop = () => { ({ DayArr, DateArr } = calculateDayAndDate(startDate, endDate)); } - console.log(tripCursor); - useEffect(() => { if (startDate) { setVisitDate({ visitDate: startDate }); @@ -84,21 +80,6 @@ const PlanSectionTop = () => { } }, [isEnter]); - // useEffect(() => { - // callBackPub(() => - // pubCursor( - // { - // token: - // 'eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiI4MCIsImF1dGgiOiJST0xFX1VTRVIiLCJleHAiOjE3MDU5OTQ4NDJ9.nu7XavOKvKaFYJB77bmPkkYV3rLvfra2zGxa9d9kArwS235CiKi_5UTzm4HqanUIFonhXmS0yxFBrjchlpPFQg', - // visitDate: '2024-02-07', - // x: 123.213, - // y: 92.531, - // }, - // tripId, - // ), - // ); - // }, []); - return (
{ const [tripBudget, setTripBudget] = useState(null); const [tripCursor, setTripCursor] = useState(null); - const [socketCallback, setSocketCallback] = useState<(() => void) | null>( - null, - ); + const socketCallbackRef = useRef<(() => void) | null>(null); const callBackPub = (callback: () => void): void => { - setSocketCallback(() => callback); + // socketCallbackRef에 새로운 콜백을 할당 + socketCallbackRef.current = callback; }; + console.log(socketCallbackRef.current); + const socketConnect = (tripId: string, visitDate: string) => { socketClient.onConnect = () => { subInfo(tripId, (res) => { @@ -91,8 +92,8 @@ export const useSocket = () => { } }); - if (socketCallback) { - socketCallback(); + if (socketCallbackRef.current) { + socketCallbackRef.current(); } }; @@ -103,11 +104,13 @@ export const useSocket = () => { if (tripId && visitDate) { socketConnect(tripId, visitDate.visitDate); } + console.log('소켓연결'); return () => { socketClient.deactivate(); + console.log('소켓해제'); }; - }, [tripId, visitDate, socketCallback]); + }, [tripId, visitDate]); return { tripInfo, @@ -120,3 +123,11 @@ export const useSocket = () => { callBackPub, }; }; + +// const [socketCallback, setSocketCallback] = useState<(() => void) | null>( +// null, +// ); + +// const callBackPub = (callback: () => void): void => { +// setSocketCallback(() => callback); +// };