Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
75 commits
Select commit Hold shift + click to select a range
5fee017
feat/#115: 1:1 채팅방 정보 조회 api 및 type 추가
DandelionQZ Jan 13, 2026
0126d01
Merge branch 'develop' of https://github.com/tinybite-2025/tinybite-c…
DandelionQZ Jan 13, 2026
14dc73a
fix/#115: 로딩 및 에러 처리 로직 개선 및 distanceKm 타입 수정
DandelionQZ Jan 14, 2026
658d0c0
fix/#115: 로딩 및 에러 처리 로직 개선
DandelionQZ Jan 14, 2026
9f10756
feat/#115: 일대일 채팅방 상세 조회 로직 추가
DandelionQZ Jan 14, 2026
d6a5ff5
chore/#115: 채팅방 정보 조회 시 불필요한 파라미터 주석 처리
DandelionQZ Jan 14, 2026
c415015
feat/#115: 1:1 채팅방 디테일 정보 조회 및 로딩/에러 처리 로직 추가
DandelionQZ Jan 14, 2026
6c326ba
feat/#115: 1:1 채팅방 상세 조회 쿼리 옵션 추가
DandelionQZ Jan 14, 2026
c6534b1
fix/#115: 채팅방 타입 상수의 대소문자 일관성 수정
DandelionQZ Jan 14, 2026
ea8a535
fix/#115: 채팅방 타입의 roomType을 문자열에서 RoomType으로 변경
DandelionQZ Jan 14, 2026
279638e
feat/#115: 1:1 채팅방 상태 핸들러 컴포넌트 추가 및 레이아웃 통합
DandelionQZ Jan 14, 2026
3d231fa
fix/#115: 참여중인 파티 필터의 roomType 대소문자 일관성 수정
DandelionQZ Jan 14, 2026
f914a1b
fix/#115: 마이페이지에서 파티 리스트 조회 api 호출시 거리 파라미터 추가
DandelionQZ Jan 14, 2026
3756ca9
feat/#115: 1:1 채팅방 상세 스키마에 participantId 및 partyId 추가
DandelionQZ Jan 14, 2026
32b58e5
feat/#115: 파티 참여 승인 및 거절 API 추가와 훅 구현
DandelionQZ Jan 14, 2026
e19fe85
fix/#115: 채팅 메시지 컴포넌트에서 사용자 ID 기반 메시지 구분 로직 추가 및 불필요한 isMine 필드 제거
DandelionQZ Jan 14, 2026
f8225ee
chore/#115: postApproveJoinParty 및 postRejectJoinParty에서 불필요한 응답 변수 제거
DandelionQZ Jan 14, 2026
1c4d002
feat/#115: 1:1 채팅방에서 파티 참여 승인 및 거절 로직 추가
DandelionQZ Jan 14, 2026
7bc2963
feat/#115: 채팅방 참여 승인 및 거절 후 1대1 채팅방 정보 갱신
DandelionQZ Jan 14, 2026
de051d7
chore/#115: 버전 0.5.0으로 업데이트 및 lockfileVersion 변경
DandelionQZ Jan 14, 2026
1c3df5b
fix/#115: 401 에러 처리에서 불필요한 URL 체크 제거
DandelionQZ Jan 14, 2026
e0c78af
fix/#115: 기본 픽업 장소를 빈 문자열로 초기화
DandelionQZ Jan 15, 2026
aa43ac0
feat/#115: 1:1 채팅방 수락 시 그룹 채팅방 ID 처리 및 네비게이션 추가
DandelionQZ Jan 15, 2026
dd037e9
feat/#115: 그룹 채팅 상태 및 카드 스키마 추가
DandelionQZ Jan 15, 2026
cc2eb78
feat/#115: 그룹 채팅방 엔드포인트 추가
DandelionQZ Jan 15, 2026
074f02b
feat/#115: 그룹 채팅방 목록 및 디테일 조회 api 추가
DandelionQZ Jan 15, 2026
94735fc
feat/#115: 그룹 채팅방 목록 및 정보 조회 로직 추가
DandelionQZ Jan 15, 2026
87b6529
refactor/#115: 타입 분리 및 구조 정리
DandelionQZ Jan 15, 2026
a99294a
feat/#115: 1:1 및 그룹 채팅 아이템 이미지 처리 로직 개선
DandelionQZ Jan 15, 2026
1036882
feat/#115: 1:1 및 그룹 채팅방 정보 통합 조회 로직 추가
DandelionQZ Jan 15, 2026
5f900e1
feat/#115: 그룹 채팅 아이템 처리 로직 추가
DandelionQZ Jan 15, 2026
7b3bcff
chore/#115: 버전 0.6.0으로 업데이트
DandelionQZ Jan 15, 2026
d1daad7
fix/#115: 그룹 채팅 상태 태그 컴포넌트의 상태 타입 및 스타일 수정
DandelionQZ Jan 15, 2026
cd65825
feat/#115: 파티 취소 상태 태그 및 스타일 추가
DandelionQZ Jan 15, 2026
f1e52da
refactor/#115: 1:1 채팅방 정보 조회 로직 간소화
DandelionQZ Jan 15, 2026
aa09b2b
feat/#115: 그룹 채팅방 디테일 정보 조회 로직 추가
DandelionQZ Jan 15, 2026
0e645f3
feat/#115: 1:1 및 그룹 채팅방 정보에 roomType 추가
DandelionQZ Jan 15, 2026
23c0b6e
feat/#115: 1:1 및 그룹 채팅방 상세 정보에 roomType 고정 값 설정
DandelionQZ Jan 15, 2026
11a5543
feat/#115: 1:1 및 그룹 채팅방 정보에 roomDetail 타입 통합 및 상태 표시 개선
DandelionQZ Jan 15, 2026
a052483
refacto/#115r: 1:1 채팅방 정보 조회 로직 개선 및 불필요한 코드 제거
DandelionQZ Jan 15, 2026
d70e02b
feat/#115: 1:1 채팅방 참여 승인 및 거절 로직에서 파라미터를 선택적으로 변경
DandelionQZ Jan 15, 2026
6030dd2
feat/#115: 1:1 채팅방 정보 조회 로직 개선 및 그룹 채팅방 데이터 통합
DandelionQZ Jan 15, 2026
c3f083d
feat/#115: 1:1 채팅방 정보 처리 로직 개선 및 함수 리팩토링
DandelionQZ Jan 15, 2026
b908b98
feat/#115: 1:1 및 그룹 채팅방 정보 조회 로직 개선 및 코드 정리
DandelionQZ Jan 15, 2026
33a6878
feat/#115: 파티 인원 모집 완료 및 종료 로직 추가
DandelionQZ Jan 15, 2026
ed3c55d
feat/#115: 그룹 관련 파티 완료 및 정산 로직 추가
DandelionQZ Jan 15, 2026
601b8d9
fix/#115: 그룹 채팅방 완료 및 정산 로직에서 필수 파라미터 검증 추가
DandelionQZ Jan 15, 2026
cd17977
feat/#115: 그룹 채팅 완료 및 정산 뮤테이션 추가
DandelionQZ Jan 15, 2026
4dff15c
feat/#115: 그룹 채팅 상세 스키마에 참여자 타입 추가
DandelionQZ Jan 15, 2026
ad09452
fix/#115: 그룹 채팅 상태 타입을 GroupChatStatusType으로 변경 및 관련 로직 수정
DandelionQZ Jan 15, 2026
0b04773
feat/#115: 일대일 채팅방에서 그룹 채팅 상태에 따른 렌더링 로직 추가
DandelionQZ Jan 15, 2026
3e580f7
chore/#115: 그룹 채팅 레이아웃에서 불필요한 주석 제거
DandelionQZ Jan 15, 2026
489367b
feat/#115: 그룹 채팅방에서 파티 상태에 따른 모집 카드 컴포넌트 수정 및 파라미터 추가
DandelionQZ Jan 15, 2026
d9b0176
feat/#115: 그룹 채팅방에서 파티 종료 로직 추가 및 관련 훅 사용
DandelionQZ Jan 15, 2026
dc2a98b
fix/#115: 파티 완료 로직을 PATCH 메서드로 수정 및 일대일, 그룹 채팅방 리스트 쿼리에 refetchOnWind…
DandelionQZ Jan 16, 2026
d345fab
feat/#115: 채팅 화면에서 그룹 및 1:1 채팅방 데이터 조회 로직 개선 및 필터링 방식 수정
DandelionQZ Jan 16, 2026
a45362b
fix/#115: axios 설정에서 withCredentials 제거 및 401/403 에러 처리 로직 개선
DandelionQZ Jan 16, 2026
e08beea
chore/#115: 버전 0.7.0으로 업데이트
DandelionQZ Jan 16, 2026
b99ae27
feat/#115: 파티 생성 성공 시 사용자에게 알림 메시지 추가
DandelionQZ Jan 16, 2026
b793b61
fix/#115: 채팅 아이템 스타일 개선
DandelionQZ Jan 16, 2026
6d3aa39
fix/#115: 마이페이지 '참여중인 파티' 거리 표시
DandelionQZ Jan 16, 2026
f81f999
feat/#115: 채팅방 정보 조회 로직 개선 및 쿼리 무효화 방식 통일
DandelionQZ Jan 16, 2026
b48e838
fix(style)/#115: 채팅 화면 스타일 개선 - 구분선 여백 통일
DandelionQZ Jan 16, 2026
c8b4b33
feat/#115: 파티 생성 및 수정 스토어 수정
DandelionQZ Jan 16, 2026
f7b34f3
feat/#115: 채팅방 정보 처리 로직 개선 및 필수 값 검증 추가
DandelionQZ Jan 16, 2026
9f99af6
feat/#115: CreatePartyPageHeader에서 action prop 추가 및 버튼 클릭 시 동작 개선
DandelionQZ Jan 16, 2026
4c77a68
fix: 파티 수정, 장소 검색 및 라우팅/네비게이션 흐름 오류 수정
DandelionQZ Jan 16, 2026
33cd0a2
fix/#115: 1:1 채팅 프로필 이미지 파싱 로직 추가
DandelionQZ Jan 16, 2026
31f5e34
Merge branch 'develop' of https://github.com/tinybite-2025/tinybite-c…
DandelionQZ Jan 16, 2026
0b48b44
chore/#115: 버전 0.8.0으로 업데이트
DandelionQZ Jan 16, 2026
e8ac912
fix/#115: 라우터 경로를 수정하여 올바른 탭으로 리디렉션
DandelionQZ Jan 16, 2026
1336901
chore/#115: 버전 0.9.0으로 업데이트
DandelionQZ Jan 16, 2026
698273e
chore/#115: 상세화면 CTA 버튼 문구 수정
donut74 Jan 16, 2026
c7129e9
fix/#115: CTA 잘못된 분기 삭제
donut74 Jan 16, 2026
b04ac28
feat/#115: groupChatRoomId 값 추가
donut74 Jan 16, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 17 additions & 6 deletions TinyBite/api/axios.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import * as SecureStore from "expo-secure-store";
// 인증 필요 x
export const publicAxios = axios.create({
baseURL: BASE_URL,
withCredentials: true,
});

publicAxios.interceptors.request.use(
Expand All @@ -29,7 +28,6 @@ publicAxios.interceptors.request.use(
// 인증 필요 o
export const privateAxios = axios.create({
baseURL: BASE_URL,
withCredentials: true,
});

privateAxios.interceptors.request.use(
Expand Down Expand Up @@ -89,18 +87,21 @@ privateAxios.interceptors.response.use(
async (error) => {
const originalRequest = error.config;

// 401 에러이고 재시도하지 않은 요청인지 확인
// 401 | 403 에러이고 재시도하지 않은 요청인지 확인
if (
error.response?.status === 401 &&
!originalRequest._retry &&
!originalRequest.url?.includes("/refresh")
(error.response?.status === 401 || error.response?.status === 403) &&
!originalRequest._retry
) {
if (isRefreshing) {
return new Promise((resolve, reject) => {
failedQueue.push({ resolve, reject });
})
.then((token) => {
originalRequest.headers.Authorization = `Bearer ${token}`;
if (originalRequest.url?.includes(ENDPOINT.AUTH.REFRESH)) {
useAuthStore.getState().logout();
return Promise.reject(error);
}
return privateAxios(originalRequest);
})
.catch((err) => {
Expand All @@ -114,6 +115,12 @@ privateAxios.interceptors.response.use(

try {
const refreshToken = await SecureStore.getItemAsync("refreshToken");

if (!refreshToken) {
useAuthStore.getState().logout();
return Promise.reject(new Error("No refresh token"));
}

const res = await publicAxios.post(ENDPOINT.AUTH.REFRESH, {
refreshToken: refreshToken,
});
Expand All @@ -129,6 +136,10 @@ privateAxios.interceptors.response.use(
const newAccessToken = await SecureStore.getItemAsync("accessToken");
processQueue(null, newAccessToken);
originalRequest.headers.Authorization = `Bearer ${newAccessToken}`;
if (originalRequest.url?.includes(ENDPOINT.AUTH.REFRESH)) {
useAuthStore.getState().logout();
return Promise.reject(error);
}
return privateAxios(originalRequest);
} catch (refreshError) {
processQueue(refreshError, null);
Expand Down
33 changes: 33 additions & 0 deletions TinyBite/api/chatApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ import { ApiSuccess } from "@/types/api.types";
import {
GetChatMessagesParams,
GetChatMessagesResponse,
GroupChatCardSchema,
GroupChatDetailSchema,
OneToOneChatCardSchema,
OneToOneChatDetailSchema,
} from "@/types/chat.types";
import { privateAxios } from "./axios";
import { ENDPOINT } from "./urls";
Expand Down Expand Up @@ -36,3 +39,33 @@ export const getOnetoOneRoomList = async () => {
);
return res.data.data;
};

/**
* 1:1 채팅방 디테일 조회
*/
export const getOnetoOneRoomDetail = async (chatroomId: number) => {
const res = await privateAxios.get<ApiSuccess<OneToOneChatDetailSchema>>(
ENDPOINT.CHAT_ROOM.DETAIL.ONE_TO_ONE(chatroomId)
);
return res.data.data;
};

/**
* 그룹 채팅방 목록 조회
*/
export const getGroupRoomList = async () => {
const res = await privateAxios.get<ApiSuccess<GroupChatCardSchema[]>>(
ENDPOINT.CHAT_ROOM.GROUP
);
return res.data.data;
};

/**
* 그룹 채팅방 디테일 조회
*/
export const getGroupRoomDetail = async (chatroomId: number) => {
const res = await privateAxios.get<ApiSuccess<GroupChatDetailSchema>>(
ENDPOINT.CHAT_ROOM.DETAIL.GROUP(chatroomId)
);
return res.data.data;
};
62 changes: 58 additions & 4 deletions TinyBite/api/partyApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,9 +166,17 @@ export const patchParty = async ({
/* 참여중인 파티 리스트 조회 API
* @returns 참여중인 파티 리스트
*/
export const getActiveParties = async (): Promise<PartyItem[]> => {
export const getActiveParties = async (
latitude: number | undefined,
longitude: number | undefined
): Promise<PartyItem[]> => {
try {
const res = await privateAxios.get(ENDPOINT.USER.ACTIVE_PARTIES);
const res = await privateAxios.get(ENDPOINT.USER.ACTIVE_PARTIES, {
params: {
latitude,
longitude,
},
});
return res.data || [];
} catch (error) {
console.error("참여중인 파티 리스트 로딩 실패:", error);
Expand All @@ -180,9 +188,17 @@ export const getActiveParties = async (): Promise<PartyItem[]> => {
* 호스팅 중인 파티 리스트 조회 API
* @returns 호스팅 중인 파티 리스트
*/
export const getHostingParties = async (): Promise<PartyItem[]> => {
export const getHostingParties = async (
latitude: number | undefined,
longitude: number | undefined
): Promise<PartyItem[]> => {
try {
const res = await privateAxios.get(ENDPOINT.USER.HOSTING_PARTIES);
const res = await privateAxios.get(ENDPOINT.USER.HOSTING_PARTIES, {
params: {
latitude,
longitude,
},
});
return res.data || [];
} catch (error) {
console.error("호스팅 중인 파티 리스트 로딩 실패:", error);
Expand Down Expand Up @@ -270,3 +286,41 @@ export const postRequestJoinParty = async (partyId: number) => {

return res.data.data;
};

/**
* 파티 참여 승인
*/
export const postApproveJoinParty = async (
partyId: number,
participantId: number
) => {
await privateAxios.post<ApiSuccess<void>>(
ENDPOINT.PARTY.PARTICIPANTS.APPROVE(partyId, participantId)
);
};

/**
* 파티 참여 거절
*/
export const postRejectJoinParty = async (
partyId: number,
participantId: number
) => {
await privateAxios.post<ApiSuccess<void>>(
ENDPOINT.PARTY.PARTICIPANTS.REJECT(partyId, participantId)
);
};

/**
* 파티 인원 모집 완료
*/
export const postCompleteParty = async (partyId: number) => {
await privateAxios.patch<ApiSuccess<void>>(ENDPOINT.PARTY.COMPLETE(partyId));
};

/**
* 파티 종료
*/
export const postSettleParty = async (partyId: number) => {
await privateAxios.post<ApiSuccess<void>>(ENDPOINT.PARTY.SETTLE(partyId));
};
15 changes: 15 additions & 0 deletions TinyBite/api/urls.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,14 @@ export const ENDPOINT = {
SEARCH_LOG: "/api/parties/search/log",
SEARCH_LOG_DELETE: (keyword: string) =>
`/api/parties/search/log/${keyword}`,
PARTICIPANTS: {
APPROVE: (partyId: number, participantId: number) =>
`/api/parties/${partyId}/participants/${participantId}/approve`,
REJECT: (partyId: number, participantId: number) =>
`/api/parties/${partyId}/participants/${participantId}/reject`,
},
COMPLETE: (partyId: number) => `/api/parties/${partyId}/complete`,
SETTLE: (partyId: number) => `/api/parties/${partyId}/settle`,
},
FILE: {
UPLOAD_FILE: "api/v1/file/upload",
Expand All @@ -47,8 +55,15 @@ export const ENDPOINT = {
WS_SEND: "/publish/send",
},
CHAT_ROOM: {
// 채팅방 리스트 조회
ONE_TO_ONE: "/api/v1/chatroom/one-to-one",
GROUP: "/api/v1/chatroom/group",
// 채팅방 정보 조회
DETAIL: {
ONE_TO_ONE: (chatroomId: number) =>
`/api/v1/chatroom/one-to-one/${chatroomId}`,
GROUP: (chatroomId: number) => `/api/v1/chatroom/group/${chatroomId}`,
},
},
FCM: {
TOKEN: "/api/v1/fcm/token",
Expand Down
2 changes: 1 addition & 1 deletion TinyBite/app.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ module.exports = {
name: "한입만",
slug: "TinyBite",
owner: "tinybite-2025",
version: "0.4.0",
version: "0.9.0",
orientation: "portrait",
icon: "./assets/images/icon.png",
scheme: "tinybite",
Expand Down
File renamed without changes.
File renamed without changes.
83 changes: 42 additions & 41 deletions TinyBite/app/(tabs)/chat.tsx → TinyBite/app/(app)/(tabs)/chat.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
import ChatCard from "@/components/chat/ChatCard";
import { useGetOnetoOneRoomListQuery } from "@/hooks/queries/useChatRoom";
import {
useGetGroupRoomListQuery,
useGetOnetoOneRoomListQuery,
} from "@/hooks/queries/useChatRoom";
import { colors } from "@/styles/colors";
import { textStyles } from "@/styles/typography/textStyles";
import { OneToOneChatCardSchema } from "@/types/chat.types";
import {
FilterTab,
GroupChatCardSchema,
OneToOneChatCardSchema,
} from "@/types/chat.types";
import { useFocusEffect } from "expo-router";
import { useCallback, useState } from "react";
import { useCallback, useMemo, useState } from "react";
import {
FlatList,
Image,
Expand All @@ -15,10 +22,24 @@ import {
} from "react-native";
import { SafeAreaView } from "react-native-safe-area-context";

// 필터 탭 목록
const filters: FilterTab[] = ["전체", "참여중인 파티", "1:1 채팅"];

/**
* 채팅 아이템 렌더링 함수
*/
const renderChatItem = ({
item,
}: {
item: OneToOneChatCardSchema | GroupChatCardSchema;
}) => {
return <ChatCard item={item} />;
};

/**
* 필터 탭 타입 정의
* 아이템 구분선 컴포넌트 (80% 너비)
*/
type FilterTab = "전체" | "참여중인 파티" | "1:1 채팅";
const ItemSeparator = () => <View style={styles.separator} />;

/**
* 채팅 화면 컴포넌트
Expand All @@ -27,51 +48,31 @@ type FilterTab = "전체" | "참여중인 파티" | "1:1 채팅";
* - 채팅 리스트: 사용자별 채팅 아이템 표시
*/
export default function ChatScreen() {
const { data: onetoOneRoomList = [], refetch } =
useGetOnetoOneRoomListQuery();
const [selectedFilter, setSelectedFilter] = useState<FilterTab>("전체");

const groupQuery = useGetGroupRoomListQuery();
const oneToOneQuery = useGetOnetoOneRoomListQuery();

useFocusEffect(
useCallback(() => {
refetch();
}, [refetch])
groupQuery.refetch();
oneToOneQuery.refetch();
}, [])
);

// 선택된 필터 탭 상태
const [selectedFilter, setSelectedFilter] = useState<FilterTab>("전체");

// 필터 탭 목록
const filters: FilterTab[] = ["전체", "참여중인 파티", "1:1 채팅"];
const mergedData = useMemo(() => {
return [...(groupQuery.data ?? []), ...(oneToOneQuery.data ?? [])];
}, [groupQuery.data, oneToOneQuery.data]);

/**
* 필터에 맞는 데이터 필터링
*/
const filteredData: OneToOneChatCardSchema[] = onetoOneRoomList.filter(
(item) => {
const filteredData: (OneToOneChatCardSchema | GroupChatCardSchema)[] =
mergedData.filter((item) => {
if (selectedFilter === "전체") return true;
if (selectedFilter === "참여중인 파티") return item.roomType === "GROUP";
if (selectedFilter === "1:1 채팅") return item.roomType === "ONE_TO_ONE";
if (selectedFilter === "참여중인 파티") return item.roomType === "Group";
return true;
}
);
// .map((item) => ({
// id: item.chatRoomId,
// lastMessage: item.recentMessage,
// timestamp: item.recentTime,
// targetName: item.partyTitle || "", // Add missing required property
// ...item,
// }));

/**
* 채팅 아이템 렌더링 함수
*/
const renderChatItem = ({ item }: { item: OneToOneChatCardSchema }) => {
return <ChatCard item={item} />;
};

/**
* 아이템 구분선 컴포넌트 (80% 너비)
*/
const ItemSeparator = () => <View style={styles.separator} />;
});

return (
<View style={styles.container}>
Expand Down Expand Up @@ -156,6 +157,7 @@ const styles = StyleSheet.create({
flex: 1,
backgroundColor: colors.background,
},

// 상단 SafeArea 배경색 (메인 색상)
safeAreaTop: {
backgroundColor: colors.main,
Expand Down Expand Up @@ -224,8 +226,7 @@ const styles = StyleSheet.create({
separator: {
height: 1,
backgroundColor: colors.gray[4],
marginLeft: "10%",
marginRight: "10%",
marginHorizontal: 20,
},
// 빈 상태 컨테이너
emptyContainer: {
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
Loading