diff --git a/src/service/feature/channel/api/channelAPI.ts b/src/service/feature/channel/api/channelAPI.ts index a36ba56..d8eba6b 100644 --- a/src/service/feature/channel/api/channelAPI.ts +++ b/src/service/feature/channel/api/channelAPI.ts @@ -1,4 +1,5 @@ import { createAxiosInstance } from '@service/feature/common/axios/axiosInstance'; +import { DMDetail, DMList } from '../types/channel'; const axios = createAxiosInstance(); @@ -8,7 +9,10 @@ export const getChannelList = async (teamId: string) => { }; export const createChannel = async ({ - teamId, categoryId, name, channelType, + teamId, + categoryId, + name, + channelType, }: { teamId: string; categoryId: number; @@ -37,14 +41,19 @@ export const deleteChannel = async ({ return res.data; }; -export const moveChannel = async (teamId: string, categoryId: number, channelId: number, body: { - destCategoryId: number; - prevChannelId: number; - nextChannelId: number; -}) => { +export const moveChannel = async ( + teamId: string, + categoryId: number, + channelId: number, + body: { + destCategoryId: number; + prevChannelId: number; + nextChannelId: number; + }, +) => { const res = await axios.patch( `/teams/${teamId}/categories/${categoryId}/channels/${channelId}`, - body + body, ); return res.data; }; @@ -63,3 +72,18 @@ export const editChannel = async ({ ); return res.data; }; + +export const getDMDetail = async (channelId: number): Promise => { + const res = await axios.get(`/channels/${channelId}`); + return res.data.data; +}; + +export const getDMList = async (): Promise => { + const res = await axios.get(`/channels/me`); + return res.data.data; +}; + +export const createDM = async (memberIds: string[]) => { + const res = await axios.post(`/channels/members`, memberIds); + return res.data.data; +}; diff --git a/src/service/feature/channel/hook/query/useChannelQuery.ts b/src/service/feature/channel/hook/query/useChannelQuery.ts index 15510a1..2a3299f 100644 --- a/src/service/feature/channel/hook/query/useChannelQuery.ts +++ b/src/service/feature/channel/hook/query/useChannelQuery.ts @@ -1,5 +1,8 @@ import { useQuery } from '@tanstack/react-query'; -import { getChannelList } from '@service/feature/channel/api/channelAPI.ts'; +import { + getChannelList, + getDMList, +} from '@service/feature/channel/api/channelAPI.ts'; import { Channel } from '@service/feature/channel/types/channel.ts'; // response 형식이 다름. 임시로 설정하여 사용중 @@ -11,3 +14,11 @@ export const useChannelListQuery = (serverId: string) => { staleTime: 1000 * 60 * 5, }); }; + +export const useDMListQuery = () => { + return useQuery({ + queryKey: ['DMList'], + queryFn: getDMList, + staleTime: 1000 * 60 * 5, + }); +}; diff --git a/src/service/feature/channel/types/channel.ts b/src/service/feature/channel/types/channel.ts index 4eb89d4..785f346 100644 --- a/src/service/feature/channel/types/channel.ts +++ b/src/service/feature/channel/types/channel.ts @@ -8,6 +8,34 @@ export type ChannelType = 'text' | 'voice' | 'event'; // [key: string]: unknown; // } +export interface DMDetail { + channel: Channel2; + channelMembers: ChannelMember[]; +} + +export interface DMList extends Channel2 { + channelMembers: ChannelMember[]; +} + +export interface ChannelMember { + id: string; + nickname: string; + name: string; + avatarUrl: string; + state: 'ONLINE' | 'OFFLINE'; + createdAt: string; +} + +// 팀 서버 상세 조회에서 불러오는 channel 타입도 이것. 추후 아래 Channel 타입에서 이걸로 변경해야 할 듯 +export interface Channel2 { + id: number; + name: string; + position: number; + type: string; + accessType: string; + chatId: string; +} + export interface Channel { categoriesView: CategoriesView[]; team: Team; @@ -32,12 +60,5 @@ export interface Team { export interface TeamMembers { id: number; role: 'OWNER' | 'MEMBER'; - memberInfo: { - id: string; - nickname: string; - name: string; - avatarUrl: string; - state: 'OFFLINE' | 'ONLINE'; - createdAt: string; - }; + memberInfo: ChannelMember; } diff --git a/src/service/feature/chat/index.ts b/src/service/feature/chat/index.ts index 3381ff6..7cecc98 100644 --- a/src/service/feature/chat/index.ts +++ b/src/service/feature/chat/index.ts @@ -1,7 +1,10 @@ export { useChat } from './hook/useChat'; -export { useChannelListQuery } from '../channel/hook/query/useChannelQuery.ts'; +export { + useChannelListQuery, + useDMListQuery, +} from '../channel/hook/query/useChannelQuery.ts'; export { useMessageHistory } from './hook/useMessageHistory'; export { useSendMessage } from './hook/useSendMessage'; export { useSocket } from './context/useSocket'; export { SocketProvider } from './context/SocketProvider'; -export * from './store/chatSlice'; \ No newline at end of file +export * from './store/chatSlice'; diff --git a/src/service/feature/common/axios/axiosInstance.ts b/src/service/feature/common/axios/axiosInstance.ts index bd5e2a9..a99037d 100644 --- a/src/service/feature/common/axios/axiosInstance.ts +++ b/src/service/feature/common/axios/axiosInstance.ts @@ -6,68 +6,68 @@ import { getCookie } from '../../auth/lib/getCookie'; export type ServiceType = 'members' | 'teams' | 'dialog'; const API_CONFIG = { - BASE_DOMAIN: 'https://flowchat.shop:30200', - HEADERS: { - JSON: 'application/json', - }, + BASE_DOMAIN: 'https://flowchat.shop:30200', + HEADERS: { + JSON: 'application/json', + }, } as const; interface ErrorResponse { - message: string; + message: string; } const handleAxiosError = (error: AxiosError) => { - const { response } = error; - if (!response) { - toast.error('네트워크 오류 또는 서버 응답 없음'); - return Promise.reject(error); - } + const { response } = error; + if (!response) { + toast.error('네트워크 오류 또는 서버 응답 없음'); + return Promise.reject(error); + } - const errorMessages: Record = { - 401: ERROR_MESSAGES.UNAUTHORIZED, - 403: ERROR_MESSAGES.FORBIDDEN, - 500: ERROR_MESSAGES.SERVER_ERROR, - }; + const errorMessages: Record = { + 401: ERROR_MESSAGES.UNAUTHORIZED, + 403: ERROR_MESSAGES.FORBIDDEN, + 500: ERROR_MESSAGES.SERVER_ERROR, + }; - toast.error( - errorMessages[response.status] || - (response.data && response.data.message) || - ERROR_MESSAGES.DEFAULT_ERROR, - ); + toast.error( + errorMessages[response.status] || + (response.data && response.data.message) || + ERROR_MESSAGES.DEFAULT_ERROR, + ); - if (response.status === 401) { - // TODO: logout 처리 또는 /login 리디렉션 - } + if (response.status === 401) { + // TODO: logout 처리 또는 /login 리디렉션 + } - return Promise.reject(error); + return Promise.reject(error); }; export const createAxiosInstance = (): AxiosInstance => { - const instance = axios.create({ - baseURL: API_CONFIG.BASE_DOMAIN, - headers: { - 'Content-Type': API_CONFIG.HEADERS.JSON, - }, - withCredentials: true, - }); + const instance = axios.create({ + baseURL: API_CONFIG.BASE_DOMAIN, + headers: { + 'Content-Type': API_CONFIG.HEADERS.JSON, + }, + withCredentials: true, + }); - instance.interceptors.request.use( - (config) => { - const token = getCookie('accessToken'); - if (token) { - config.headers.Authorization = `Bearer ${token}`; - } - return config; - }, - (error) => Promise.reject(error) - ); + instance.interceptors.request.use( + (config) => { + const token = getCookie('accessToken'); + if (token) { + config.headers.Authorization = `Bearer ${token}`; + } + return config; + }, + (error) => Promise.reject(error), + ); - instance.interceptors.response.use( - (response: AxiosResponse) => response, - handleAxiosError - ); + instance.interceptors.response.use( + (response: AxiosResponse) => response, + handleAxiosError, + ); - return instance; + return instance; }; -export default createAxiosInstance; \ No newline at end of file +export default createAxiosInstance; diff --git a/src/service/feature/friend/types/friend.ts b/src/service/feature/friend/types/friend.ts index ada328b..ea6f2ed 100644 --- a/src/service/feature/friend/types/friend.ts +++ b/src/service/feature/friend/types/friend.ts @@ -1,14 +1,7 @@ +import { ChannelMember } from '@service/feature/channel/types/channel'; + export interface FriendData { friendshipId: 8; friendshipDateTime: string; - friendshipInfo: FriendInfoData; -} - -export interface FriendInfoData { - id: string; - nickname: string; - name: string; - avatarUrl: string; - state: 'ONLINE' | 'OFFLINE'; - createdAt: string; + friendshipInfo: ChannelMember; } diff --git a/src/view/components/common/Modal.tsx b/src/view/components/common/Modal.tsx index 6823415..2d7092a 100644 --- a/src/view/components/common/Modal.tsx +++ b/src/view/components/common/Modal.tsx @@ -114,7 +114,7 @@ Modal.Title = ({ onClick={() => context?.setIsOpen(false)} className='mr-1 group' > - + )} @@ -237,10 +237,12 @@ Modal.ProTip = ({ children }: { children: string }) => { Modal.Footer = ({ onSubmit, + onClose, backBtnText, submitBtnText, }: { onSubmit: () => void; + onClose?: () => void; backBtnText?: string; submitBtnText?: string; }) => { @@ -252,10 +254,17 @@ Modal.Footer = ({ onSubmit(); }; + const handleClose = () => { + if (onClose) { + onClose(); + } + context.setIsOpen(false); + }; + return (
); diff --git a/src/view/components/layout/sidebar/components/top/Mention.tsx b/src/view/components/layout/sidebar/components/top/Mention.tsx index 4f93e55..c6f3bf5 100644 --- a/src/view/components/layout/sidebar/components/top/Mention.tsx +++ b/src/view/components/layout/sidebar/components/top/Mention.tsx @@ -51,7 +51,7 @@ const Mention = ({ {/* 닫기로 수정 */} {toggle && } diff --git a/src/view/layout/LayoutWithSidebar.tsx b/src/view/layout/LayoutWithSidebar.tsx index 4adfcc6..367da0c 100644 --- a/src/view/layout/LayoutWithSidebar.tsx +++ b/src/view/layout/LayoutWithSidebar.tsx @@ -10,19 +10,19 @@ const LayoutWithSidebar = () => { const isDMView = location.pathname.startsWith('/channels/@me'); return ( -
-