From 6ed987e6fad69d068112086afbcdb379264e283f Mon Sep 17 00:00:00 2001 From: dbswl701 Date: Fri, 18 Apr 2025 00:50:47 +0900 Subject: [PATCH 1/3] =?UTF-8?q?feat:=20=EC=9D=B4=EB=AF=B8=EC=A7=80=20?= =?UTF-8?q?=EC=97=85=EB=A1=9C=EB=93=9C=20=EB=B0=8F=20=EC=84=9C=EB=B2=84=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20api=20=EC=97=B0=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pages/chat/components/AddServerModal.tsx | 30 ++++++++++++++----- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/src/view/pages/chat/components/AddServerModal.tsx b/src/view/pages/chat/components/AddServerModal.tsx index 57858af..fd03075 100644 --- a/src/view/pages/chat/components/AddServerModal.tsx +++ b/src/view/pages/chat/components/AddServerModal.tsx @@ -1,8 +1,8 @@ import { useRef, useState } from 'react'; -import axios from 'axios'; import Modal from '@components/common/Modal'; import ChatServer from '../../../../service/feature/team/ChatServer.tsx'; +import axiosInstance from 'src/service/feature/common/axios/axiosInstance.ts'; export default function AddServerModal() { const [preview, setPreview] = useState(null); @@ -23,17 +23,30 @@ export default function AddServerModal() { } try { + // 이미지가 있는 경우, 먼저 업로드 + let iconUrl = ''; const formData = new FormData(); - formData.append('name', name); + if (fileRef.current) { - formData.append('icon', fileRef.current); + formData.append('file', fileRef.current); + + const res = await axiosInstance.post('/images', formData, { + headers: { + 'Content-Type': 'multipart/form-data', + }, + }); + iconUrl = res.data.message; } - const response = await axios.post('/api/servers', formData, { - headers: { - 'Content-Type': 'multipart/form-data', + // 서버 생성 요청 + const response = await axiosInstance.post( + '/teams', + { + name, + iconUrl, }, - }); + { withCredentials: true }, + ); console.log('서버 생성 성공', response.data); // TODO: 성공 시 모달 닫거나 페이지 이동 등의 후속 처리 @@ -49,11 +62,14 @@ export default function AddServerModal() { if (file) { const url = URL.createObjectURL(file); setPreview(url); + fileRef.current = file; } }; + const handleClick = () => { inputRef.current?.click(); }; + return ( From 05660a4a4a6f97f2e0281ff095a10d0360dcd755 Mon Sep 17 00:00:00 2001 From: dbswl701 Date: Tue, 22 Apr 2025 18:52:38 +0900 Subject: [PATCH 2/3] =?UTF-8?q?feat:=20=EC=9D=B4=EB=AF=B8=EC=A7=80=20?= =?UTF-8?q?=EC=97=85=EB=A1=9C=EB=93=9C=20=EB=B0=8F=20=EC=84=9C=EB=B2=84=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20api=20=EC=97=B0=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../feature/common/axios/axiosInstance.ts | 2 +- src/service/feature/team/ChatServer.tsx | 19 +++++++-- src/service/feature/team/api/teamApi.ts | 24 ++++++++++++ .../feature/team/hooks/useTeamSidebar.ts | 31 +++++++++++++++ src/service/feature/team/types/team.ts | 6 +++ .../components/layout/sidebar/TeamSidebar.tsx | 39 +++++++------------ .../pages/chat/components/AddServerModal.tsx | 21 +++------- 7 files changed, 97 insertions(+), 45 deletions(-) create mode 100644 src/service/feature/team/api/teamApi.ts create mode 100644 src/service/feature/team/hooks/useTeamSidebar.ts create mode 100644 src/service/feature/team/types/team.ts diff --git a/src/service/feature/common/axios/axiosInstance.ts b/src/service/feature/common/axios/axiosInstance.ts index e3abd7c..f4975af 100644 --- a/src/service/feature/common/axios/axiosInstance.ts +++ b/src/service/feature/common/axios/axiosInstance.ts @@ -2,7 +2,7 @@ import axios from 'axios'; import { toast } from 'sonner'; import { ERROR_MESSAGES } from '../../../lib/const/toast/errorMessage.ts'; -const API_BASE_URL = 'http://flowchat.shop:30002'; +const API_BASE_URL = 'http://flowchat.shop:30003'; const axiosInstance = axios.create({ baseURL: API_BASE_URL, diff --git a/src/service/feature/team/ChatServer.tsx b/src/service/feature/team/ChatServer.tsx index 37e9e31..103a504 100644 --- a/src/service/feature/team/ChatServer.tsx +++ b/src/service/feature/team/ChatServer.tsx @@ -1,10 +1,14 @@ +import { Team } from './types/team'; + interface ChatServerProps { - title: string; + server?: Team; isActive: boolean; onClick: () => void; + isAdd?: boolean; } export default function ChatServer({ - title, + isAdd, + server, isActive, onClick, }: ChatServerProps) { @@ -15,7 +19,16 @@ export default function ChatServer({ onClick={onClick} type='button' > -
{title}
+ {isAdd ? ( +
추가
+ ) : ( + !server &&
me
+ )} + {server?.iconUrl ? ( + {server.name} + ) : ( +
{server?.name}
+ )} ); } diff --git a/src/service/feature/team/api/teamApi.ts b/src/service/feature/team/api/teamApi.ts new file mode 100644 index 0000000..48a9165 --- /dev/null +++ b/src/service/feature/team/api/teamApi.ts @@ -0,0 +1,24 @@ +import axiosInstance from '../../common/axios/axiosInstance'; +import { Team } from '../types/team'; + +export const getTeams = async (): Promise => { + const res = await axiosInstance.get('/teams', { + withCredentials: true, + }); + return res.data.data; +}; + +export const postTeam = async ( + name: string, + iconUrl: string, +): Promise<{ teamId: string }> => { + const res = await axiosInstance.post( + '/teams', + { + name, + iconUrl, + }, + { withCredentials: true }, + ); + return res.data.data; +}; diff --git a/src/service/feature/team/hooks/useTeamSidebar.ts b/src/service/feature/team/hooks/useTeamSidebar.ts new file mode 100644 index 0000000..4cbfa34 --- /dev/null +++ b/src/service/feature/team/hooks/useTeamSidebar.ts @@ -0,0 +1,31 @@ +import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; +import { getTeams, postTeam } from '../api/teamApi'; + +// 쿼리키 +const teamKeys = { + all: ['teams'] as const, + lists: () => [...teamKeys.all, 'list'] as const, +}; + +export const useGetTeam = () => { + const { data, isLoading, error } = useQuery({ + queryKey: teamKeys.lists(), + queryFn: getTeams, + staleTime: 10 * 60 * 1000, + gcTime: 60 * 60 * 1000, + }); + + return { data, isLoading, error }; +}; + +export const useCreateTeam = () => { + const queryClient = useQueryClient(); + return useMutation({ + mutationFn: ({ name, iconUrl }: { name: string; iconUrl: string }) => + postTeam(name, iconUrl), + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: teamKeys.lists() }); + }, + onError: () => {}, + }); +}; diff --git a/src/service/feature/team/types/team.ts b/src/service/feature/team/types/team.ts new file mode 100644 index 0000000..cddc6ff --- /dev/null +++ b/src/service/feature/team/types/team.ts @@ -0,0 +1,6 @@ +export interface Team { + id: string; + name: string; + masterId: string; + iconUrl: string; +} diff --git a/src/view/components/layout/sidebar/TeamSidebar.tsx b/src/view/components/layout/sidebar/TeamSidebar.tsx index 48d976e..703b09f 100644 --- a/src/view/components/layout/sidebar/TeamSidebar.tsx +++ b/src/view/components/layout/sidebar/TeamSidebar.tsx @@ -1,11 +1,7 @@ import AddServerModal from '@pages/chat/components/AddServerModal'; import { useNavigate, useParams } from 'react-router-dom'; import ChatServer from 'src/service/feature/team/ChatServer'; - -const servers = [ - { id: 1, title: '서버1' }, - { id: 2, title: 'server2' }, -]; +import { useGetTeam } from 'src/service/feature/team/hooks/useTeamSidebar'; // 대충 넣은 것 const TeamSidebar = () => { @@ -13,40 +9,33 @@ const TeamSidebar = () => { const channelId = params.serverId; const navigate = useNavigate(); - const handleChannel = (server: { id: number; title: string }) => { - console.log('server: ', server); - if (server.id === 0) { + // 팀 목록 불러오기 + const { data: servers, isLoading } = useGetTeam(); + + if (isLoading) return
로딩중....
; + + const handleChannel = (id: string) => { + if (id === '') { navigate(`/channels/@me`); } else { - navigate(`/channels/${server.id}`); + navigate(`/channels/${id}`); } }; return ( - //
- // {[1, 2, 3].map((server) => ( - //
- // {server} - //
- // ))} - //
{/* 자기 채널 */} handleChannel({ id: 0, title: 'me' })} - title={'me'} + onClick={() => handleChannel('')} />
- {servers.map((server) => ( + {servers?.map((server) => ( handleChannel(server)} - title={server.title} + onClick={() => handleChannel(server.id)} + server={server} /> ))} {/* 서버 추가하기 */} @@ -55,4 +44,4 @@ const TeamSidebar = () => { ); }; -export default TeamSidebar; // src/view/ui/Common/UserProfileBar.tsx +export default TeamSidebar; diff --git a/src/view/pages/chat/components/AddServerModal.tsx b/src/view/pages/chat/components/AddServerModal.tsx index fd03075..c1bd19e 100644 --- a/src/view/pages/chat/components/AddServerModal.tsx +++ b/src/view/pages/chat/components/AddServerModal.tsx @@ -3,11 +3,14 @@ import { useRef, useState } from 'react'; import Modal from '@components/common/Modal'; import ChatServer from '../../../../service/feature/team/ChatServer.tsx'; import axiosInstance from 'src/service/feature/common/axios/axiosInstance.ts'; +import { useCreateTeam } from 'src/service/feature/team/hooks/useTeamSidebar.ts'; export default function AddServerModal() { const [preview, setPreview] = useState(null); const [name, setName] = useState('누구님의 서버'); + const { mutate } = useCreateTeam(); + console.log('서버 추가 보이냐'); const inputRef = useRef(null); @@ -37,18 +40,8 @@ export default function AddServerModal() { }); iconUrl = res.data.message; } + mutate({ name, iconUrl }); - // 서버 생성 요청 - const response = await axiosInstance.post( - '/teams', - { - name, - iconUrl, - }, - { withCredentials: true }, - ); - - console.log('서버 생성 성공', response.data); // TODO: 성공 시 모달 닫거나 페이지 이동 등의 후속 처리 } catch (error) { console.error('서버 생성 실패', error); @@ -73,11 +66,7 @@ export default function AddServerModal() { return ( - + From ec76860078759972d865fa061c41279a65f6fd34 Mon Sep 17 00:00:00 2001 From: dbswl701 Date: Wed, 30 Apr 2025 00:52:51 +0900 Subject: [PATCH 3/3] =?UTF-8?q?style:=20=EC=84=9C=EB=B2=84=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1=20=EC=8A=A4=ED=83=80=EC=9D=BC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/view/components/common/Icon.tsx | 6 +----- src/view/components/layout/LayoutWithSidebar.tsx | 3 +-- .../sidebar/components/channel/ChannelNavigation.tsx | 6 ++++-- .../layout/sidebar/components}/team/ChatServer.tsx | 5 +++-- .../components/layout/sidebar/{ => team}/TeamSidebar.tsx | 8 +++----- src/view/pages/chat/components/AddServerModal.tsx | 2 +- 6 files changed, 13 insertions(+), 17 deletions(-) rename src/{service/feature => view/components/layout/sidebar/components}/team/ChatServer.tsx (82%) rename src/view/components/layout/sidebar/{ => team}/TeamSidebar.tsx (85%) diff --git a/src/view/components/common/Icon.tsx b/src/view/components/common/Icon.tsx index d9ad137..f3aa9fb 100644 --- a/src/view/components/common/Icon.tsx +++ b/src/view/components/common/Icon.tsx @@ -1,11 +1,9 @@ interface IconProps { path: string; className?: string; - width?: number; - height?: number; } -const Icon = ({ path, className, width, height }: IconProps) => { +const Icon = ({ path, className }: IconProps) => { return (
{ alt={`${path} icon`} className='w-full h-full object-contain' src={`/assets/img/${path}.svg`} - width={width} - height={height} />
); diff --git a/src/view/components/layout/LayoutWithSidebar.tsx b/src/view/components/layout/LayoutWithSidebar.tsx index cb4b5f2..02310c9 100644 --- a/src/view/components/layout/LayoutWithSidebar.tsx +++ b/src/view/components/layout/LayoutWithSidebar.tsx @@ -1,11 +1,10 @@ import { Outlet, useLocation } from 'react-router-dom'; import UserProfileBar from '@components/layout/UserProfileBar.tsx'; -import TeamSidebar from '@components/layout/sidebar/TeamSidebar.tsx'; +import TeamSidebar from '@components/layout/sidebar/team/TeamSidebar.tsx'; import DirectChannelSidebar from './sidebar/channel/DirectChannelSidebar.tsx'; import ServerChannelSidebar from './sidebar/channel/ServerChannelSidebar.tsx'; const LayoutWithSidebar = () => { - const location = useLocation(); const isDMView = location.pathname.startsWith('/channels/@me'); diff --git a/src/view/components/layout/sidebar/components/channel/ChannelNavigation.tsx b/src/view/components/layout/sidebar/components/channel/ChannelNavigation.tsx index 532a5e8..a85c8be 100644 --- a/src/view/components/layout/sidebar/components/channel/ChannelNavigation.tsx +++ b/src/view/components/layout/sidebar/components/channel/ChannelNavigation.tsx @@ -1,4 +1,6 @@ -import NavigationCard from '@components/layout/sidebar/channel/components/NavigationCard.tsx'; +// import NavigationCard from '@components/layout/sidebar/channel/components/NavigationCard.tsx'; + +import NavigationCard from './NavigationCard'; const ChannelNavigation = () => { const menus = [ @@ -23,4 +25,4 @@ const ChannelNavigation = () => { ); }; -export default ChannelNavigation; \ No newline at end of file +export default ChannelNavigation; diff --git a/src/service/feature/team/ChatServer.tsx b/src/view/components/layout/sidebar/components/team/ChatServer.tsx similarity index 82% rename from src/service/feature/team/ChatServer.tsx rename to src/view/components/layout/sidebar/components/team/ChatServer.tsx index 103a504..d208614 100644 --- a/src/service/feature/team/ChatServer.tsx +++ b/src/view/components/layout/sidebar/components/team/ChatServer.tsx @@ -1,4 +1,5 @@ -import { Team } from './types/team'; +import Icon from '@components/common/Icon'; +import { Team } from '../../../../../../service/feature/team/types/team'; interface ChatServerProps { server?: Team; @@ -20,7 +21,7 @@ export default function ChatServer({ type='button' > {isAdd ? ( -
추가
+ ) : ( !server &&
me
)} diff --git a/src/view/components/layout/sidebar/TeamSidebar.tsx b/src/view/components/layout/sidebar/team/TeamSidebar.tsx similarity index 85% rename from src/view/components/layout/sidebar/TeamSidebar.tsx rename to src/view/components/layout/sidebar/team/TeamSidebar.tsx index 703b09f..2a7ef19 100644 --- a/src/view/components/layout/sidebar/TeamSidebar.tsx +++ b/src/view/components/layout/sidebar/team/TeamSidebar.tsx @@ -1,18 +1,15 @@ import AddServerModal from '@pages/chat/components/AddServerModal'; import { useNavigate, useParams } from 'react-router-dom'; -import ChatServer from 'src/service/feature/team/ChatServer'; +import ChatServer from '@components/layout/sidebar/components/team/ChatServer'; import { useGetTeam } from 'src/service/feature/team/hooks/useTeamSidebar'; -// 대충 넣은 것 const TeamSidebar = () => { const params = useParams(); const channelId = params.serverId; const navigate = useNavigate(); // 팀 목록 불러오기 - const { data: servers, isLoading } = useGetTeam(); - - if (isLoading) return
로딩중....
; + const { data: servers } = useGetTeam(); const handleChannel = (id: string) => { if (id === '') { @@ -21,6 +18,7 @@ const TeamSidebar = () => { navigate(`/channels/${id}`); } }; + return (
{/* 자기 채널 */} diff --git a/src/view/pages/chat/components/AddServerModal.tsx b/src/view/pages/chat/components/AddServerModal.tsx index c1bd19e..3486c12 100644 --- a/src/view/pages/chat/components/AddServerModal.tsx +++ b/src/view/pages/chat/components/AddServerModal.tsx @@ -1,7 +1,7 @@ import { useRef, useState } from 'react'; import Modal from '@components/common/Modal'; -import ChatServer from '../../../../service/feature/team/ChatServer.tsx'; +import ChatServer from '../../../components/layout/sidebar/components/team/ChatServer.tsx'; import axiosInstance from 'src/service/feature/common/axios/axiosInstance.ts'; import { useCreateTeam } from 'src/service/feature/team/hooks/useTeamSidebar.ts';