From dbe6a629e56a4edee2f6d2619c5cb0843adc805d Mon Sep 17 00:00:00 2001 From: Seungho Date: Mon, 8 Jul 2024 14:56:09 +0900 Subject: [PATCH 1/2] =?UTF-8?q?feat(chat):=20=EC=B1=84=ED=8C=85=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=EC=B0=BD=EC=97=90=EC=84=9C=20=EC=B9=9C?= =?UTF-8?q?=EA=B5=AC=EB=AA=A9=EB=A1=9D=EC=9D=84=20=EA=B0=80=EC=A0=B8?= =?UTF-8?q?=EC=98=AC=20=EC=88=98=20=EC=9E=88=EB=8F=84=EB=A1=9D=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 개요 - 채팅 생성창에서 친구목록을 가져올 수 있도록 한다. 수정 사항 - `FriendList.jsx` - default value 삭제 - api.js - 현재 멤버의 커넥트 가져오는 함수 구현 - `ChatRoomPage.jsx` - 현재의 멤버Id와 커넥트를 가져오는 부분 `useEffect`에 구현 - `FriendListPage.jsx` - `filterAcceptedConnects`: 성사된 커넥트만 보여줌 - `getOtherMemberFromConnect`: 커넥트에서 상대방의 정보를 가져옴 - 정보를 바탕으로 친구목록을 보여줌 - `secureStoreUtils.js` - 본인 ID를 secure store에서 가져오는 과정이 계속 반복되어, 유틸 함수로 추출 --- src/components/chat/FriendList.jsx | 2 +- src/config/api.js | 4 +++ src/pages/chat/ChatRoomPage.jsx | 10 +++--- src/pages/chat/FriendListPage.jsx | 56 ++++++++++++++++++------------ src/util/secureStoreUtils.js | 11 ++++++ 5 files changed, 55 insertions(+), 28 deletions(-) create mode 100644 src/util/secureStoreUtils.js diff --git a/src/components/chat/FriendList.jsx b/src/components/chat/FriendList.jsx index 08010b88..f8b6bd9f 100644 --- a/src/components/chat/FriendList.jsx +++ b/src/components/chat/FriendList.jsx @@ -6,7 +6,7 @@ import IconChatProfile from "@components/chat/IconChatProfile"; import IconSend from "@components/common/IconSend"; import IconMenu from "@components/chat/IconMenu"; -const FriendList = ({ name = "name" }) => { +const FriendList = ({ name }) => { return ( <> diff --git a/src/config/api.js b/src/config/api.js index 410893e6..473daead 100644 --- a/src/config/api.js +++ b/src/config/api.js @@ -47,6 +47,10 @@ export const changePassword = (email) => { }); }; +export const getMyConnects = () => { + return api.get("/connects"); +}; + export const getProfile = () => { return api.get("/members/profile"); }; diff --git a/src/pages/chat/ChatRoomPage.jsx b/src/pages/chat/ChatRoomPage.jsx index 86b2da34..57ec90db 100644 --- a/src/pages/chat/ChatRoomPage.jsx +++ b/src/pages/chat/ChatRoomPage.jsx @@ -25,7 +25,7 @@ import IconChatSetting from "@components/chat/IconChatSetting"; import ChatBubble from "./ChatBubble/ChatBubble"; import { useWebSocket } from "context/WebSocketContext"; import formatKoreanTime from "util/formatTime"; -import * as SecureStore from "expo-secure-store"; +import { getMyMemberId } from "util/secureStoreUtils"; const ChatRoomPage = ({ route }) => { const navigation = useNavigation(); @@ -40,11 +40,11 @@ const ChatRoomPage = ({ route }) => { const flatListRef = useRef(null); useEffect(() => { - const getMemberId = async () => { - const id = await SecureStore.getItemAsync("memberId"); - setMemberId(parseInt(id)); + const fetchMyMemberId = async () => { + const myMemberId = await getMyMemberId(); + setMemberId(myMemberId); }; - getMemberId(); + fetchMyMemberId(); }, []); useEffect(() => { diff --git a/src/pages/chat/FriendListPage.jsx b/src/pages/chat/FriendListPage.jsx index 55b71838..28fa661a 100644 --- a/src/pages/chat/FriendListPage.jsx +++ b/src/pages/chat/FriendListPage.jsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { useState, useEffect } from "react"; import { Text, View, SafeAreaView, FlatList } from "react-native"; import FriendListStyles from "@pages/chat/FriendListStyles"; @@ -6,26 +6,33 @@ import FriendListStyles from "@pages/chat/FriendListStyles"; import TopBar from "@components/common/TopBar"; import IconFriendNumber from "@components/chat/IconFriendNumber"; import FriendList from "@components/chat/FriendList"; +import { getMyConnects } from "config/api"; +import { getMyMemberId } from "util/secureStoreUtils"; const FriendListPage = () => { - const FriendData = [ - { - id: "1", - name: "Dann", - }, - { - id: "2", - name: "Amy", - }, - { - id: "3", - name: "Haedam", - }, - { - id: "4", - name: "Jenny", - }, - ]; + const [connects, setConnects] = useState([]); + const [myMemberId, setMyMemberId] = useState(null); + + const filterAcceptedConnects = (connects) => { + return connects.filter((connect) => connect.status === "ACCEPTED"); + }; + + const getOtherMemberFromConnect = (connect) => { + return connect.from_member.id === myMemberId + ? connect.to_member + : connect.from_member; + }; + + useEffect(() => { + const fetchMyMemberIDAndConnects = async () => { + const myMemberId = await getMyMemberId(); + const response = await getMyConnects(); + const acceptedConnects = filterAcceptedConnects(response.data); + setMyMemberId(myMemberId); + setConnects(acceptedConnects); + }; + fetchMyMemberIDAndConnects(); + }, []); return ( @@ -33,12 +40,17 @@ const FriendListPage = () => { 내 친구 - {"23"} + + {connects.length} + } + data={connects} + renderItem={({ item }) => { + const otherMember = getOtherMemberFromConnect(item); + return ; + }} keyExtractor={(item) => item.id} /> diff --git a/src/util/secureStoreUtils.js b/src/util/secureStoreUtils.js new file mode 100644 index 00000000..abbac7dc --- /dev/null +++ b/src/util/secureStoreUtils.js @@ -0,0 +1,11 @@ +import * as SecureStore from "expo-secure-store"; + +export const getMyMemberId = async () => { + try { + const myMemberId = await SecureStore.getItemAsync("memberId"); + return myMemberId ? parseInt(myMemberId) : null; + } catch (error) { + console.error("본인 memberId를 로컬에서 가져올 수 없습니다.", error); + return null; + } +}; From e0a97a29c1b13cac9c59a462312d68b61def8e1d Mon Sep 17 00:00:00 2001 From: Seungho Date: Mon, 8 Jul 2024 22:55:36 +0900 Subject: [PATCH 2/2] =?UTF-8?q?feat(loading):=20=EB=A1=9C=EB=94=A9=20?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 개요 - 디자인 명세서에 따라 로딩 화면을 구현한다. - https://www.figma.com/design/mWNXToJWQFleMlVHUshgnF/Dife_design?node-id=1953-18902&m=dev 수정 사항 - DifeYelloDotLogo.jsx - 디프 로고 (노란점있는 버전) SVG 생성 - Dot.jsx - 로딩의 점 컴포넌트이며 재활용을 위해 외부 컴포넌트로 작성 - Loading.jsx - 점 + 로고로 이루어진 로딩 컴포넌트 - useRef로 세개의 점에 대한 애니메이션 값(Opacity 값)을 생성함 - 그것을 배열로 보관하여, 개수만큼(3개) Dot 컴포넌트를 생성하고, Opacity의 값이 애니메이션으로 변하면서 동시에, Animated.interpolate를 사용해서 translateY 값도 0부터 -10으로 변할 수 있도록 한다. 즉, 점의 색이 진해질수록, translateY의 값이 -10의 위치로 이동 - WebSocketContext.js - 기존의 임시 로딩 텍스트를 삭제하고 생성한 Loading 컴포넌트 적용 --- src/components/common/DifeYellowDotLogo.jsx | 21 +++++ src/components/common/loading/Dot.jsx | 28 +++++++ src/components/common/loading/Loading.jsx | 89 +++++++++++++++++++++ src/context/WebSocketContext.js | 4 +- 4 files changed, 140 insertions(+), 2 deletions(-) create mode 100644 src/components/common/DifeYellowDotLogo.jsx create mode 100644 src/components/common/loading/Dot.jsx create mode 100644 src/components/common/loading/Loading.jsx diff --git a/src/components/common/DifeYellowDotLogo.jsx b/src/components/common/DifeYellowDotLogo.jsx new file mode 100644 index 00000000..e43e58c7 --- /dev/null +++ b/src/components/common/DifeYellowDotLogo.jsx @@ -0,0 +1,21 @@ +import * as React from "react"; +import Svg, { Circle, Path } from "react-native-svg"; + +const DifeYellowDotLogo = () => ( + + + + +); +export default DifeYellowDotLogo; diff --git a/src/components/common/loading/Dot.jsx b/src/components/common/loading/Dot.jsx new file mode 100644 index 00000000..b66c8160 --- /dev/null +++ b/src/components/common/loading/Dot.jsx @@ -0,0 +1,28 @@ +import React from "react"; +import { Animated, StyleSheet } from "react-native"; + +const Dot = ({ opacity, translateY }) => { + return ( + + ); +}; + +const styles = StyleSheet.create({ + dot: { + width: 12, + height: 12, + borderRadius: 10, + backgroundColor: "#2964E0", + margin: 5, + }, +}); + +export default Dot; diff --git a/src/components/common/loading/Loading.jsx b/src/components/common/loading/Loading.jsx new file mode 100644 index 00000000..7b9b1e3d --- /dev/null +++ b/src/components/common/loading/Loading.jsx @@ -0,0 +1,89 @@ +import React, { useEffect, useRef } from "react"; +import { View, Animated, StyleSheet, SafeAreaView } from "react-native"; +import Dot from "./Dot"; +import DifeYellowDotLogo from "../DifeYellowDotLogo"; + +const INITAL_OPACITY = 0.2; +const DOT_COUNT = 3; + +const createAnimatedValues = (count, initialValue) => { + const animatedValues = []; + for (let i = 0; i < count; i++) { + animatedValues.push(new Animated.Value(initialValue)); + } + return animatedValues; +}; + +const Loading = () => { + const dotOpacities = useRef( + createAnimatedValues(DOT_COUNT, INITAL_OPACITY), + ).current; + + const createAnimationConfig = (isOn) => { + return { + toValue: isOn ? 1 : INITAL_OPACITY, + duration: 500, + useNativeDriver: true, + }; + }; + + const createSequence = (animatedValue) => { + return Animated.sequence([ + Animated.timing(animatedValue, createAnimationConfig(true)), + Animated.timing(animatedValue, createAnimationConfig(false)), + ]); + }; + + useEffect(() => { + const animate = () => { + Animated.loop( + Animated.stagger(200, dotOpacities.map(createSequence)), + ).start(); + }; + animate(); + }, [dotOpacities]); + + return ( + + + + + + + {dotOpacities.map((opacity, index) => ( + + ))} + + + + ); +}; + +const styles = StyleSheet.create({ + container: { + flex: 1, + alignItems: "center", + justifyContent: "center", + }, + logo: { + position: "absolute", + bottom: "100%", + marginBottom: 3, + }, + dots: { + flexDirection: "row", + alignItems: "center", + justifyContent: "center", + height: 89, + width: 89, + }, +}); + +export default Loading; diff --git a/src/context/WebSocketContext.js b/src/context/WebSocketContext.js index d96939de..cdc1c50e 100644 --- a/src/context/WebSocketContext.js +++ b/src/context/WebSocketContext.js @@ -7,8 +7,8 @@ import React, { } from "react"; import { Client } from "@stomp/stompjs"; import { getChatroomsByType } from "../config/api"; // Adjust the import path as necessary -import { Text } from "react-native"; import { WS_URL } from "@env"; +import Loading from "@components/common/loading/Loading"; const WebSocketContext = createContext(null); @@ -121,7 +121,7 @@ export const WebSocketProvider = ({ children }) => { disconnectWebSocket, }} > - {isConnected ? children : LOADING...} + {isConnected ? children : } ); };