diff --git a/README.md b/README.md index 5f241e9..5fe6aac 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,56 @@ -# Odugi project +# Odugi ๐ŸŽง + + + + +- Odugi ๋Š” ๋””์Šค์ฝ”๋“œ์˜ ๋””์ž์ธ๊ณผ ์ฃผ์š” ๊ธฐ๋Šฅ๋“ค์„ ํด๋ก ํ•˜์—ฌ ๋งŒ๋“  ํ”„๋กœ์ ํŠธ ์ž…๋‹ˆ๋‹ค. + + +
+
+ + +| ํŒ€์› | ์—ญํ•  | +| --------------------------------------- | --------- | +| [๊น€ํ˜„์šฐ](https://github.com/krokerdile) | FRONT-END | +| [ํ—ˆ๋‹ค์€](https://github.com/nno3onn) | FRONT-END | +| [๋ฐฑ์ข…์ธ](https://github.com/whipbaek) | BACK-END | + + +# Architecture + + +๊ฐœ๋ฐœ์€ MSA ๊ตฌ์กฐ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์ง„ํ–‰๋˜์—ˆ์œผ๋ฉฐ Spring Cloud์™€ Eureka๋ฅผ ํ™œ์šฉํ•˜์—ฌ ์ง„ํ–‰ํ•˜์˜€์Šต๋‹ˆ๋‹ค. + +### Server List + +

+ +# ๊ธฐ์ˆ  ์Šคํƒ + +#### FRONT END ๐Ÿ”ฎ + +- TypeScript +- React +- Zustand +- React Query +- Story Book + +#### BACK END & Devops โ™Ÿ๏ธ + +- JAVA +- Spring FrameWork (JPA, Security, Cloud ..) +- MySQL +- Redis +- STOMP, WebSocket +- RabbitMQ +- AWS +- AWS S3 +- Jenkins + +
+ +# ๊ธฐ๋Šฅ diff --git a/package.json b/package.json index 2b46b3c..99e087a 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,33 @@ "name": "frontend", "version": "0.1.0", "private": true, + "scripts": { + "start": "craco start", + "build": "craco build", + "test": "craco test", + "eject": "react-scripts eject", + "chromatic": "chromatic", + "storybook": "start-storybook -p 6006 -s public", + "build-storybook": "build-storybook -s public" + }, + "eslintConfig": { + "extends": [ + "react-app", + "react-app/jest" + ] + }, + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + }, "dependencies": { "@emotion/react": "^11.10.5", "@emotion/styled": "^11.10.5", @@ -35,33 +62,6 @@ "web-vitals": "^2.1.0", "zustand": "^4.3.5" }, - "scripts": { - "start": "craco start", - "build": "craco build", - "test": "craco test", - "eject": "react-scripts eject", - "chromatic": "chromatic", - "storybook": "start-storybook -p 6006 -s public", - "build-storybook": "build-storybook -s public" - }, - "eslintConfig": { - "extends": [ - "react-app", - "react-app/jest" - ] - }, - "browserslist": { - "production": [ - ">0.2%", - "not dead", - "not op_mini all" - ], - "development": [ - "last 1 chrome version", - "last 1 firefox version", - "last 1 safari version" - ] - }, "devDependencies": { "@craco/craco": "^7.0.0", "@storybook/addon-actions": "^6.5.16", diff --git a/src/api/chat.ts b/src/api/chat.ts index a43e77a..c949278 100644 --- a/src/api/chat.ts +++ b/src/api/chat.ts @@ -5,14 +5,13 @@ const chatApi = { const { userId } = queryKey[1]; return await clientApi.get("/state/getchannel", { - params: { - userId, - }, + params: { userId }, }); }, - enter: async () => { + enterInvitation: async () => { return await clientApi.post("/chat/community_enter", { + //!TODO ๊ธฐ๋Šฅ ์ถ”๊ฐ€๋˜๋ฉด ํ•˜๋“œ์ฝ”๋”ฉ ์ˆ˜์ •ํ•  ๊ฒƒ name: "์ข…์ธ", channelId: "220", }); diff --git a/src/api/userSetting.ts b/src/api/userSetting.ts index 575ecfb..a091956 100644 --- a/src/api/userSetting.ts +++ b/src/api/userSetting.ts @@ -35,8 +35,8 @@ const userSettingApi = { }); }, - // ์„œ๋ฒ„ ํ”„๋กœํ•„๋ช… ์ด๋ฆ„ ๋ณ€๊ฒฝ - communityUpdate: async ({ + // ์ปค๋ฎค๋‹ˆํ‹ฐ ํ”„๋กœํ•„๋ช… ์ด๋ฆ„ ๋ณ€๊ฒฝ + updateCommunityName: async ({ communityId, userId, userName, diff --git a/src/components/atoms/Div/Status.tsx b/src/components/atoms/Div/Status.tsx index 636bd9d..0f0713f 100644 --- a/src/components/atoms/Div/Status.tsx +++ b/src/components/atoms/Div/Status.tsx @@ -1,7 +1,4 @@ import styled from "styled-components"; -import StateDisturbIcon from "../Icons/StateDisturbIcon"; -import StateEmptyIcon from "../Icons/StateEmptyIcon"; -import StateMobileIcon from "../Icons/StateMobileIcon"; import StateOffIcon from "../Icons/StateOffIcon"; import StateOnIcon from "../Icons/StateOnIcon"; diff --git a/src/components/molecules/Div/InviteFriendBox.tsx b/src/components/molecules/Div/InviteFriendBox.tsx index 15d6724..dfc6132 100644 --- a/src/components/molecules/Div/InviteFriendBox.tsx +++ b/src/components/molecules/Div/InviteFriendBox.tsx @@ -21,18 +21,17 @@ const InviteFriendBox = ({ name, userId, channelId }: friend) => { let backUrl = process.env.REACT_APP_BASE_URL; let uuid = crypto.randomUUID(); - let shortUrl = uuid; const onSendInvite = () => { sendInvite({ communityId, userId, - shortUrl, + shortUrl: uuid, }); sendInviteToChat({ sender: userInfo.name, channelId: channelId, - linkMessage: `${backUrl}/invite/${shortUrl}/${userId}`, + linkMessage: `${backUrl}/invite/${uuid}/${userId}`, }); }; diff --git a/src/components/molecules/Div/MessageLog.tsx b/src/components/molecules/Div/MessageLog.tsx index e052693..02dc143 100644 --- a/src/components/molecules/Div/MessageLog.tsx +++ b/src/components/molecules/Div/MessageLog.tsx @@ -2,7 +2,6 @@ import UserLogo from "@components/atoms/Div/UserLogo"; import MessageText from "@components/atoms/Div/MessageText"; import { createRef, useEffect, useState } from "react"; import styled from "styled-components"; -import MessageHoverButtons from "../Button/MessageHoverButtons"; import MessageUserDate from "./MessageUserDate"; interface MessageLogProps { diff --git a/src/components/molecules/Div/UserSettingGeneralTab.tsx b/src/components/molecules/Div/UserSettingGeneralTab.tsx index 9105cd0..aa67bca 100644 --- a/src/components/molecules/Div/UserSettingGeneralTab.tsx +++ b/src/components/molecules/Div/UserSettingGeneralTab.tsx @@ -13,7 +13,6 @@ import { useEffect } from "react"; const UserSettingGeneralTab = () => { const { userInfo } = useUserStore(); - const { showSettingModal, settingModalType, @@ -68,13 +67,13 @@ const UserSettingGeneralTab = () => { {userInfo.email} - + {/* null} /> - + */} diff --git a/src/components/molecules/Div/WelcomeMessage.tsx b/src/components/molecules/Div/WelcomeMessage.tsx index c0bbc28..f7b7714 100644 --- a/src/components/molecules/Div/WelcomeMessage.tsx +++ b/src/components/molecules/Div/WelcomeMessage.tsx @@ -1,12 +1,11 @@ import MessageText from "@components/atoms/Div/MessageText"; import WelcomeIcon from "@components/atoms/Icons/WelcomeIcon"; -import React from "react"; import styled from "styled-components"; -interface WelcomeMessage { +interface WelcomeMessageProps { name: string; } -const WelcomeMessage = ({ name }: WelcomeMessage) => { +const WelcomeMessage = ({ name }: WelcomeMessageProps) => { return ( diff --git a/src/components/molecules/Modal/UserSettingIntroModal.tsx b/src/components/molecules/Modal/UserSettingIntroModal.tsx index 85df84a..282613c 100644 --- a/src/components/molecules/Modal/UserSettingIntroModal.tsx +++ b/src/components/molecules/Modal/UserSettingIntroModal.tsx @@ -12,10 +12,11 @@ const UserSettingIntroModal = () => { const { setShowSettingModal } = useSettingModalStore(); const { userInfo, setUserInfo } = useUserStore(); - const [introduction, changeIntroduction] = useInput(); + const [introduction, changeIntroduction] = useInput(userInfo.introduction); const { mutate: modifyIntro } = useModifyIntro(); const updataIntro = () => { + setShowSettingModal(false); modifyIntro({ introduction }); setUserInfo({ ...userInfo, introduction }); }; diff --git a/src/components/molecules/Modal/UserSettingNameModal.tsx b/src/components/molecules/Modal/UserSettingNameModal.tsx index 6bc4a36..4425b4b 100644 --- a/src/components/molecules/Modal/UserSettingNameModal.tsx +++ b/src/components/molecules/Modal/UserSettingNameModal.tsx @@ -12,7 +12,7 @@ const UserSettingNameModal = () => { const { userInfo, setUserInfo } = useUserStore(); const { setShowSettingModal } = useSettingModalStore(); - const [name, changeName] = useInput(); + const [name, changeName] = useInput(userInfo.name); const [password, changePassword] = useInput(); const { mutate: modifyName } = useModifyName(); const updateUserName = () => { diff --git a/src/components/organisms/CommunitySettingDefault.tsx b/src/components/organisms/CommunitySettingDefault.tsx index 24bbc26..5cd0b20 100644 --- a/src/components/organisms/CommunitySettingDefault.tsx +++ b/src/components/organisms/CommunitySettingDefault.tsx @@ -4,13 +4,12 @@ import FieldButton from "../atoms/Button/fieldButton"; import styled from "styled-components"; import ImageUploadButton from "../molecules/Button/ImageUploadButton"; import { useCallback, useRef, useState } from "react"; -import { useMutation } from "@tanstack/react-query"; import { useUserStore } from "@store/useUserStore"; import { useParams } from "react-router-dom"; import useDeleteCommunity from "@hooks/query/useDeleteCommnunity"; -import communityApi from "@api/community"; import useModifyCommunityImage from "@hooks/query/useModifyCommunityImage"; import DefaultInput from "@components/atoms/Input/DefaultInput"; +import useUpdateCommunityName from "@hooks/query/useUpdateCommunityName"; const CommunitySettingDefault = () => { let formData = new FormData(); @@ -20,9 +19,12 @@ const CommunitySettingDefault = () => { const [img, setImg] = useState(); const nameRef = useRef(null); + const { mutate: updateCommunityName } = useUpdateCommunityName(); const { mutate: modifyImage } = useModifyCommunityImage(); - const { mutate: updateCommunityName } = useMutation(communityApi.update); - const { mutate: deleteCommunity } = useDeleteCommunity(); + const { mutate: deleteCommunity } = useDeleteCommunity({ + communityId, + userId: userInfo.id, + }); const changeCommunityName = useCallback(() => { if (nameRef.current) diff --git a/src/components/organisms/MainDirectBody.tsx b/src/components/organisms/MainDirectBody.tsx index fba5f27..f742876 100644 --- a/src/components/organisms/MainDirectBody.tsx +++ b/src/components/organisms/MainDirectBody.tsx @@ -1,7 +1,6 @@ import clientApi from "@api/axios"; import WelcomeMessage from "@components/molecules/Div/WelcomeMessage"; import { Client, Stomp } from "@stomp/stompjs"; -import * as StompJS from "@stomp/stompjs"; import { useUserStore } from "@store/useUserStore"; import getFormatDate from "@utils/getFormatDate"; import { useEffect, useRef, useState } from "react"; diff --git a/src/hooks/query/useAcceptFriend.ts b/src/hooks/query/useAcceptFriend.ts index ba0cf0f..bb17075 100644 --- a/src/hooks/query/useAcceptFriend.ts +++ b/src/hooks/query/useAcceptFriend.ts @@ -1,12 +1,28 @@ -import { useMutation, useQueryClient } from "@tanstack/react-query"; import friendApi from "@api/friend"; +import { useMutation, useQueryClient } from "@tanstack/react-query"; const useAcceptFriend = () => { const queryClient = useQueryClient(); + const QUERY_KEY = ["friendList"]; return useMutation(friendApi.accept, { + onMutate: async (newFriend: any) => { + await queryClient.cancelQueries({ queryKey: QUERY_KEY }); + const previousFriendList = queryClient.getQueryData(QUERY_KEY); + queryClient.setQueryData(QUERY_KEY, [ + ...(previousFriendList as any), + newFriend, + ]); + + return { previousFriendList }; + }, + + onError: (_err: Error, _newFriend: any, context: any) => { + queryClient.setQueryData(QUERY_KEY, context.previousFriendList); + }, + onSettled: () => { - queryClient.invalidateQueries({ queryKey: ["friendList"] }); + queryClient.invalidateQueries({ queryKey: QUERY_KEY }); }, }); }; diff --git a/src/hooks/query/useChangeUserImage.ts b/src/hooks/query/useChangeUserImage.ts deleted file mode 100644 index 4764d34..0000000 --- a/src/hooks/query/useChangeUserImage.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { useMutation } from "@tanstack/react-query"; -import userSettingApi from "@api/userSetting"; - -const useChangeUserImage = () => { - return useMutation(userSettingApi.modifyImage); -}; - -export default useChangeUserImage; diff --git a/src/hooks/query/useCommunityUpdate.ts b/src/hooks/query/useCommunityUpdate.ts deleted file mode 100644 index 046e89f..0000000 --- a/src/hooks/query/useCommunityUpdate.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { useMutation } from "@tanstack/react-query"; -import userSettingApi from "@api/userSetting"; - -const useCommunityUpdate = () => { - return useMutation(userSettingApi.communityUpdate); -}; - -export default useCommunityUpdate; diff --git a/src/hooks/query/useCreateCommunity.ts b/src/hooks/query/useCreateCommunity.ts index 4d87cd4..26df54a 100644 --- a/src/hooks/query/useCreateCommunity.ts +++ b/src/hooks/query/useCreateCommunity.ts @@ -1,37 +1,35 @@ +import { useUserStore } from "@store/useUserStore"; import { useNavigate } from "react-router-dom"; -import { useUserStore } from "./../../store/useUserStore"; import communityApi from "@api/community"; import { useMutation, useQueryClient } from "@tanstack/react-query"; const useCreateCommunity = () => { - const queryClient = useQueryClient(); - const navigate = useNavigate(); - const { userInfo } = useUserStore(); + const navigate = useNavigate(); + const queryClient = useQueryClient(); + const QUERY_KEY = ["communityList", userInfo.id]; return useMutation(communityApi.create, { - onMutate: async (newCommunityList: any) => { - await queryClient.cancelQueries({ - queryKey: ["communityList", { userId: userInfo.id }], - }); - const previousCommunityList = queryClient.getQueriesData([ - "communityList", - newCommunityList, + onMutate: async (newCommunity: any) => { + await queryClient.cancelQueries({ queryKey: QUERY_KEY }); + const previousCommunityList = queryClient.getQueriesData(QUERY_KEY); + queryClient.setQueryData(QUERY_KEY, [ + ...previousCommunityList, + newCommunity, ]); - return { newCommunityList, previousCommunityList }; + + return { previousCommunityList }; }, - onError: (_err: Error, _newCommunityList: any, context: any) => { - queryClient.setQueriesData( - ["communityList"], - context?.previousCommunityList - ); + + onError: (_err: Error, _newCommunity: any, context: any) => { + queryClient.setQueriesData(QUERY_KEY, context.previousCommunityList); }, onSuccess: () => { navigate(-1); }, onSettled: () => { queryClient.invalidateQueries({ - queryKey: ["communityList", { userId: userInfo.id }], + queryKey: QUERY_KEY, }); }, }); diff --git a/src/hooks/query/useDeleteCommnunity.ts b/src/hooks/query/useDeleteCommnunity.ts index 05dfccd..4dd7ce7 100644 --- a/src/hooks/query/useDeleteCommnunity.ts +++ b/src/hooks/query/useDeleteCommnunity.ts @@ -1,13 +1,48 @@ import { useNavigate } from "react-router-dom"; import communityApi from "@api/community"; -import { useMutation } from "@tanstack/react-query"; +import { useMutation, useQueryClient } from "@tanstack/react-query"; -const useDeleteCommunity = () => { +interface useDeleteCommunityProps { + communityId: string | undefined; + userId: number; +} + +const useDeleteCommunity = ({ + communityId, + userId, +}: useDeleteCommunityProps) => { const navigate = useNavigate(); + const queryClient = useQueryClient(); + const QUERY_KEY = ["communityList", userId]; + return useMutation(communityApi.delete, { + onMutate: async () => { + await queryClient.cancelQueries({ + queryKey: QUERY_KEY, + }); + const previousCommunityList = queryClient.getQueriesData(QUERY_KEY); + + const newCommunityList = [...previousCommunityList].filter( + (community: any) => community.id !== communityId + ); + queryClient.setQueryData(QUERY_KEY, newCommunityList); + + return { newCommunityList, previousCommunityList }; + }, + + onError: (_err: Error, _newCommunityList: any, context: any) => { + queryClient.setQueriesData(QUERY_KEY, context?.previousCommunityList); + }, + onSuccess: () => { navigate("/@me"); }, + + onSettled: () => { + queryClient.invalidateQueries({ + queryKey: QUERY_KEY, + }); + }, }); }; diff --git a/src/hooks/query/useEnterInvitation.ts b/src/hooks/query/useEnterInvitation.ts index abb1efb..8647366 100644 --- a/src/hooks/query/useEnterInvitation.ts +++ b/src/hooks/query/useEnterInvitation.ts @@ -2,7 +2,7 @@ import chatApi from "@api/chat"; import { useMutation } from "@tanstack/react-query"; const useEnterInvitation = () => { - return useMutation(chatApi.enter); + return useMutation(chatApi.enterInvitation); }; export default useEnterInvitation; diff --git a/src/hooks/query/useGetCommunityList.ts b/src/hooks/query/useGetCommunityList.ts index d159806..73862c7 100644 --- a/src/hooks/query/useGetCommunityList.ts +++ b/src/hooks/query/useGetCommunityList.ts @@ -1,32 +1,14 @@ import communityApi from "@api/community"; import { useQuery } from "@tanstack/react-query"; -const useGetCommunityList = () => { - const { data: res } = useQuery(["communityList"], communityApi.getList); +const useGetCommunityList = ({ userId }: any) => { + const [list, setList] = useState([]); + const { data: res } = useQuery( + ["communityList", userId], + communityApi.getList + ); - // useEffect(() => { - if (!res?.data?.data) return []; - - // const List = (res as any)?.data.data || []; - // if (List[0] === "") { - // return setList([]); - // } - - // const parsedData: any = []; - // if (List.length > 0) { - // for (let i = 0; i < List?.length; i++) { - // if (i !== List.length - 1) { - // parsedData.push(JSON.parse(List[i] + "}")); - // } else { - // parsedData.push(JSON.parse(List[i])); - // } - // } - // } - - // setList(parsedData); - // setList(res.data.data); return res.data.data; - // }, [res]); }; export default useGetCommunityList; diff --git a/src/hooks/query/useModifyUserImage.ts b/src/hooks/query/useModifyUserImage.ts index 9c7bfef..c1ddb7d 100644 --- a/src/hooks/query/useModifyUserImage.ts +++ b/src/hooks/query/useModifyUserImage.ts @@ -1,4 +1,4 @@ -import { useMutation, useQuery } from "@tanstack/react-query"; +import { useMutation } from "@tanstack/react-query"; import userSettingApi from "@api/userSetting"; const useModifyUserImage = (options: any) => { diff --git a/src/hooks/query/useRejectFriend.ts b/src/hooks/query/useRejectFriend.ts index 5ffacd9..0572130 100644 --- a/src/hooks/query/useRejectFriend.ts +++ b/src/hooks/query/useRejectFriend.ts @@ -3,10 +3,26 @@ import friendApi from "@api/friend"; const useRejectFriend = () => { const queryClient = useQueryClient(); + const QUERY_KEY = ["friendList"]; return useMutation(friendApi.reject, { + onMutate: async (newFriend: any) => { + await queryClient.cancelQueries({ queryKey: QUERY_KEY }); + const previousFriendList: any = queryClient.getQueryData(QUERY_KEY); + const newFriendList = previousFriendList.filter( + (friend: any) => friend.id !== newFriend.id + ); + queryClient.setQueryData(QUERY_KEY, newFriendList); + + return { previousFriendList }; + }, + + onError: (_err: Error, _newFriend: any, context: any) => { + queryClient.setQueryData(QUERY_KEY, context.previousFriendList); + }, + onSettled: () => { - queryClient.invalidateQueries({ queryKey: ["friendList"] }); + queryClient.invalidateQueries({ queryKey: QUERY_KEY }); }, }); }; diff --git a/src/hooks/query/useSendEmail.ts b/src/hooks/query/useSendEmail.ts index 5beeedd..540e6c2 100644 --- a/src/hooks/query/useSendEmail.ts +++ b/src/hooks/query/useSendEmail.ts @@ -1,8 +1,8 @@ import { useMutation } from "@tanstack/react-query"; import authApi from "@api/auth"; -const useSendEmail = (options: any) => { - return useMutation(authApi.register, options); +const useSendEmail = () => { + return useMutation(authApi.register); }; export default useSendEmail; diff --git a/src/hooks/query/useCommunityNameUpdate.ts b/src/hooks/query/useUpdateCommunityName.ts similarity index 64% rename from src/hooks/query/useCommunityNameUpdate.ts rename to src/hooks/query/useUpdateCommunityName.ts index 39d66d0..9cfba3e 100644 --- a/src/hooks/query/useCommunityNameUpdate.ts +++ b/src/hooks/query/useUpdateCommunityName.ts @@ -1,8 +1,8 @@ import communityApi from "@api/community"; import { useMutation } from "@tanstack/react-query"; -const useModifyPassword = () => { +const useUpdateCommunityName = () => { return useMutation(communityApi.update); }; -export default useModifyPassword; +export default useUpdateCommunityName; diff --git a/src/hooks/query/useUpdateUserNameInCommunity.ts b/src/hooks/query/useUpdateUserNameInCommunity.ts new file mode 100644 index 0000000..6129830 --- /dev/null +++ b/src/hooks/query/useUpdateUserNameInCommunity.ts @@ -0,0 +1,8 @@ +import { useMutation } from "@tanstack/react-query"; +import userSettingApi from "@api/userSetting"; + +const useUpdateUserNameInCommunity = () => { + return useMutation(userSettingApi.updateCommunityName); +}; + +export default useUpdateUserNameInCommunity;