-
Notifications
You must be signed in to change notification settings - Fork 3
Feat/111/gathering api #120
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
c0b5081
ca1b2c0
6595c3e
6591a88
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| import { fetchApi } from '@/src/utils/api'; | ||
| import { GatheringDetailType } from '@/src/types/gathering-data'; | ||
|
|
||
| // NOTE: μ½μ λν μΌ λΆλ¬μ€κΈ° | ||
| export async function GetGatheringDetail( | ||
| crewId: number, | ||
| gatheringId: number, | ||
| ): Promise<GatheringDetailType> { | ||
| const url = `/api/crews/${crewId}/gatherings/${gatheringId}`; | ||
|
|
||
| const response = await fetchApi<{ data: GatheringDetailType }>(url, { | ||
| method: 'GET', | ||
| headers: { | ||
| 'Content-Type': 'application/json', | ||
| }, | ||
| }); | ||
| return response.data; | ||
| } | ||
|
Comment on lines
+4
to
+18
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. μΈμ¦ ν ν° ν€λ μΆκ° νμ PRμμ μΈκΈλ λ‘κ·ΈμΈ ν ν° λ¬Έμ μ κ΄λ ¨νμ¬, Authorization ν€λκ° λλ½λμ΄ μμ΅λλ€. μΈμ¦μ΄ νμν API νΈμΆμμλ λ°λμ ν ν°μ ν¬ν¨ν΄μΌ ν©λλ€. λ€μκ³Ό κ°μ΄ μμ ν΄μ£ΌμΈμ: const response = await fetchApi<{ data: GatheringDetailType }>(url, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
+ 'Authorization': `Bearer ${getToken()}`,
},
});
|
||
|
|
||
| // NOTE: μ½μ μ°Έμ¬ | ||
| export async function JoinGathering(crewId: number, gatheringId: number): Promise<void> { | ||
| const url = `/api/crews/${crewId}/gatherings/${gatheringId}/join`; | ||
|
|
||
| await fetchApi(url, { | ||
| method: 'POST', | ||
| headers: { | ||
| 'Content-Type': 'application/json', | ||
| }, | ||
| }); | ||
| } | ||
|
|
||
| // NOTE: μ½μ μ·¨μ(host) | ||
| export async function CancelGathering(crewId: number, gatheringId: number): Promise<void> { | ||
| const url = `/api/crews/${crewId}/gatherings/${gatheringId}`; | ||
|
|
||
| await fetchApi(url, { | ||
| method: 'DELETE', | ||
| headers: { | ||
| 'Content-Type': 'application/json', | ||
| }, | ||
| }); | ||
| } | ||
|
|
||
| // NOTE: μ½μ μ°Έμ¬ μ·¨μ(μ°Έμ¬μ) | ||
| export async function LeaveGathering(crewId: number, gatheringId: number): Promise<void> { | ||
| const url = `/api/crews/${crewId}/gatherings/${gatheringId}/leave`; | ||
|
|
||
| await fetchApi(url, { | ||
| method: 'DELETE', | ||
| headers: { | ||
| 'Content-Type': 'application/json', | ||
| }, | ||
| }); | ||
| } | ||
|
Comment on lines
+20
to
+54
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. π οΈ Refactor suggestion API ν¨μλ€μ μΌκ΄μ± λ° μμ μ± κ°μ νμ λͺ¨λ API ν¨μλ€μμ λ€μ μ¬νλ€μ΄ κ°μ λμ΄μΌ ν©λλ€:
λ€μκ³Ό κ°μ κ°μ μ μ μλ립λλ€: // κ³΅ν΅ νμ
μ μ
interface ApiResponse<T> {
data: T;
message: string;
status: number;
}
// μ
λ ₯κ° κ²μ¦ μ νΈλ¦¬ν°
function validateIds(crewId: number, gatheringId: number) {
if (!Number.isInteger(crewId) || crewId <= 0) {
throw new Error('μ ν¨νμ§ μμ ν¬λ£¨ IDμ
λλ€');
}
if (!Number.isInteger(gatheringId) || gatheringId <= 0) {
throw new Error('μ ν¨νμ§ μμ λͺ¨μ IDμ
λλ€');
}
}
// μμ ν¨μ ꡬν
export async function JoinGathering(crewId: number, gatheringId: number): Promise<ApiResponse<void>> {
validateIds(crewId, gatheringId);
const url = `/api/crews/${crewId}/gatherings/${gatheringId}/join`;
try {
return await fetchApi<ApiResponse<void>>(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${getToken()}`,
},
});
} catch (error) {
throw new Error(`λͺ¨μ μ°Έμ¬μ μ€ν¨νμ΅λλ€: ${error.message}`);
}
} |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,12 @@ | ||
| 'use client'; | ||
|
|
||
| import { | ||
| CancelGathering, | ||
| JoinGathering, | ||
| LeaveGathering, | ||
| } from '@/src/_apis/gathering/gathering-detail-apis'; | ||
| import { ApiError } from '@/src/utils/api'; | ||
| import Toast from '@/src/components/common/toast'; | ||
| import { GatheringDetailType } from '@/src/types/gathering-data'; | ||
| import GatheringDetailModalPresenter from './presenter'; | ||
|
|
||
|
|
@@ -9,22 +16,50 @@ export interface GatheringDetailModalContainerProps { | |
| data: GatheringDetailType; | ||
| } | ||
|
|
||
| // NOTE: ν μ€νΈλ λ‘κ·ΈμΈ ν ν ν°μ΄ μλ΄κ²¨μ μΆν μ§ννκ² μ΅λλ€! | ||
|
|
||
| export default function GatheringDetailModalContainer({ | ||
| opened, | ||
| close, | ||
| data, | ||
| }: GatheringDetailModalContainerProps) { | ||
| const handleJoin = () => { | ||
| // TODO : λͺ¨μ μ°Έμ¬νκΈ° API μ°κ²° | ||
| close(); | ||
| const showToast = (message: string, type: 'success' | 'error' | 'warning') => { | ||
| Toast({ message, type }); | ||
| }; | ||
| const handleExit = () => { | ||
| // TODO : λͺ¨μ νν΄νκΈ° API μ°κ²° | ||
| close(); | ||
|
|
||
| const handleJoin = async () => { | ||
| try { | ||
| await JoinGathering(data.crewId, data.id); | ||
| showToast('μ½μμ μ°Έμ¬νμ΅λλ€.', 'success'); | ||
| close(); | ||
| } catch (error) { | ||
| if (error instanceof ApiError) { | ||
| showToast(`μ°Έμ¬ μ€ μλ¬ λ°μ: ${error.message}`, 'error'); | ||
| } | ||
| } | ||
| }; | ||
| const handleDelete = () => { | ||
| // TODO : λͺ¨μ μμ νκΈ° API μ°κ²° | ||
| close(); | ||
|
|
||
| const handleExit = async () => { | ||
| try { | ||
| await LeaveGathering(data.crewId, data.id); | ||
| close(); | ||
| } catch (error) { | ||
| if (error instanceof ApiError) { | ||
| showToast(`μ°Έμ¬ μ·¨μ μ€ μλ¬ λ°μ: ${error.message}`, 'error'); | ||
| } | ||
| } | ||
| }; | ||
|
|
||
| const handleDelete = async () => { | ||
| try { | ||
| await CancelGathering(data.crewId, data.id); | ||
| showToast('μ½μμ μμ νμ΅λλ€.', 'success'); | ||
| close(); | ||
| } catch (error) { | ||
| if (error instanceof ApiError) { | ||
| showToast(`μ½μ μμ μ€ μλ¬ λ°μ: ${error.message}`, 'error'); | ||
| } | ||
| } | ||
|
Comment on lines
+30
to
+62
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. π οΈ Refactor suggestion API νΈλ€λ¬μ μΌκ΄μ± κ°μ μ΄ νμν©λλ€.
λ€μκ³Ό κ°μ κ°μ μ¬νμ μ μλ립λλ€: const handleExit = async () => {
try {
await LeaveGathering(data.crewId, data.id);
+ showToast('μ½μ μ°Έμ¬λ₯Ό μ·¨μνμ΅λλ€.', 'success');
close();
} catch (error) {μλ¬ μ²λ¦¬λ₯Ό μν μ νΈλ¦¬ν° ν¨μλ₯Ό μΆκ°νλ©΄ μ’μ κ² κ°μ΅λλ€: const handleApiError = (error: unknown, context: string) => {
if (error instanceof ApiError) {
showToast(`${context} μ€ μλ¬ λ°μ: ${error.message}`, 'error');
}
};μ΄λ₯Ό νμ©νμ¬ κ° νΈλ€λ¬μ μλ¬ μ²λ¦¬λ₯Ό λ¨μνν μ μμ΅λλ€: } catch (error) {
- if (error instanceof ApiError) {
- showToast(`μ½μ μμ μ€ μλ¬ λ°μ: ${error.message}`, 'error');
- }
+ handleApiError(error, 'μ½μ μμ ');
} |
||
| }; | ||
|
|
||
| return ( | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,38 +1,23 @@ | ||
| 'use client'; | ||
|
|
||
| import { useEffect, useState } from 'react'; | ||
| import { ReviewListData, getReviewList } from '@/src/_apis/detail/get-review-list'; | ||
| import CrewReviewList from './crew-review-list'; | ||
| import RatingDisplay from './rating-display'; | ||
|
|
||
| export default function CrewReviewSection() { | ||
| const [reviewData, setReviewData] = useState<ReviewListData | null>(null); | ||
| const [currentPage, setCurrentPage] = useState(1); | ||
| const limit = 5; | ||
|
|
||
| useEffect(() => { | ||
| async function fetchReviewData() { | ||
| const data = await getReviewList(currentPage, limit); | ||
| setReviewData(data); | ||
| } | ||
| fetchReviewData(); | ||
| }, [currentPage]); | ||
|
|
||
| const handlePageChange = (page: number) => setCurrentPage(page); | ||
|
|
||
| if (!reviewData) return <div>Loading...</div>; | ||
| // TODO: review μΆν μΆκ° | ||
|
|
||
| return ( | ||
| <div className="space-y-6 rounded-lg bg-white"> | ||
| <div className="mx-4 flex justify-center py-11"> | ||
| <RatingDisplay reviewRateInfo={reviewData.info} /> | ||
| {/* <RatingDisplay reviewRateInfo={reviewData.info} /> */} | ||
| </div> | ||
| <CrewReviewList | ||
| {/* <CrewReviewList | ||
| reviews={reviewData.data} | ||
| totalPages={reviewData.totalPages} | ||
| currentPage={currentPage} | ||
| onPageChange={handlePageChange} | ||
| /> | ||
| /> */} | ||
| </div> | ||
| ); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π οΈ Refactor suggestion
API μλ¬ μ²λ¦¬ κ°μ νμ
fetchApi μ νΈλ¦¬ν°λ₯Ό μ¬μ©ν λ λ€νΈμν¬ μ€λ₯λ μλ² μ€λ₯μ λν μ²λ¦¬κ° λλ½λμ΄ μμ΅λλ€. κ° API ν¨μμμ try-catchλ₯Ό μ¬μ©νμ¬ μλ¬λ₯Ό μ μ ν μ²λ¦¬νλ κ²μ΄ μ’μ΅λλ€.
λ€μκ³Ό κ°μ΄ μλ¬ νμ μ μ μνκ³ μ²λ¦¬νλ κ²μ μΆμ²λ립λλ€: