Skip to content

feat: 호스트 멤버 초대 API 연동#140

Merged
Yejiin21 merged 6 commits intodevelopfrom
feat/#138/host-member-invitation
May 25, 2025
Merged

feat: 호스트 멤버 초대 API 연동#140
Yejiin21 merged 6 commits intodevelopfrom
feat/#138/host-member-invitation

Conversation

@Yejiin21
Copy link
Copy Markdown
Contributor

@Yejiin21 Yejiin21 commented May 24, 2025

호스트 멤버 초대 성공

스크린샷 2025-05-24 오후 8 56 49

멤버 초대 후 호스트 목록

스크린샷 2025-05-24 오후 8 56 55

Summary by CodeRabbit

  • 신규 기능

    • 호스트 채널에 멤버 초대 기능이 추가되었습니다.
    • 여러 명의 이메일을 입력하여 멤버를 한 번에 초대할 수 있습니다.
    • 호스트 채널 정보 저장을 위한 새로운 기능이 도입되었습니다.
  • 리팩터

    • 호스트 생성, 삭제, 정보 수정, 멤버 초대 관련 로직이 구조적으로 분리되어 관리됩니다.
    • 이메일 입력 컴포넌트가 외부 상태를 받아 관리하도록 개선되었습니다.
  • 버그 수정

    • 일부 훅(hook) 경로가 잘못 지정된 문제를 수정하였습니다.

@Yejiin21 Yejiin21 requested review from hyeeuncho and xaexunxang May 24, 2025 11:58
@Yejiin21 Yejiin21 self-assigned this May 24, 2025
@Yejiin21 Yejiin21 added the 🔧 Feature 기능 구현 label May 24, 2025
@Yejiin21 Yejiin21 linked an issue May 24, 2025 that may be closed by this pull request
2 tasks
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented May 24, 2025

Walkthrough

호스트 관련 API 함수, 타입, 커스텀 훅이 event feature에서 host feature로 이동 및 리팩토링되었습니다. 초대 기능을 위한 API, 타입, 훅이 새롭게 추가되었고, 기존 컴포넌트와 페이지는 이에 맞게 import 경로와 상태 관리 방식이 변경되었습니다.

Changes

파일/경로 요약 변경 내용 요약
src/features/event/api/host.ts,
src/features/event/hooks/useHostHook.ts,
src/features/event/model/hostCreation.ts
호스트 생성/삭제 API, 관련 타입, 커스텀 훅 삭제
src/features/host/api/host.ts,
src/features/host/model/host.ts,
src/features/host/hook/useHostHook.ts
호스트 생성/삭제 API, 타입, 커스텀 훅 host feature에 새로 추가 및 리팩토링
src/features/host/api/hostInvitation.ts,
src/features/host/model/hostInvitation.ts,
src/features/host/hook/useHostInvitation.ts,
src/features/host/hook/useInviteHostHook.ts
호스트 초대 관련 API, 타입, 커스텀 훅 신규 추가
src/features/host/hook/useHostInfoHook.ts 호스트 정보 저장 커스텀 훅 신규 추가
src/features/event/ui/EventFunnel.tsx,
src/pages/event/ui/host/HostSelectionPage.tsx
호스트 관련 훅 import 경로 event → host로 변경
src/features/menu/ui/MemberEmailInput.tsx 이메일 리스트 상태를 내부에서 외부 props로 변경, prop 타입 명시
src/pages/menu/ui/myHost/HostEditPage.tsx 초대 및 저장 로직을 새 훅으로 교체, 이메일 상태 관리 단순화, 컴포넌트 prop 전달 방식 변경

Sequence Diagram(s)

sequenceDiagram
    participant UI as HostEditPage
    participant EmailInput as MemberEmailInput
    participant Hook as useInviteMembers
    participant API as inviteMember API

    UI->>EmailInput: emails, setEmails props 전달
    UI->>Hook: useInviteMembers(hostChannelId) 호출
    UI->>Hook: inviteMembers(emails)
    loop 각 이메일마다
        Hook->>API: inviteMember(hostChannelId, { email })
        API-->>Hook: ApiResponse<null>
    end
    Hook-->>UI: 전체 성공/실패 콜백, 알림 처리
Loading
sequenceDiagram
    participant UI as HostEditPage
    participant InfoHook as useHostInfoSave
    participant API as updateHostInfo API

    UI->>InfoHook: useHostInfoSave(hostChannelId, hostInfo, desc)
    UI->>InfoHook: handleSave()
    InfoHook->>API: updateHostInfo(hostChannelId, data)
    API-->>InfoHook: ApiResponse<null>
    InfoHook-->>UI: 성공/실패 알림, 쿼리 무효화
Loading

Possibly related PRs

Suggested reviewers

  • xaexunxang

Poem

🐇
코드가 hop hop, 폴더를 넘어
호스트 훅과 API, 새 집을 찾아
초대장 전송, 이메일도 척척
상태는 props로, 관리도 깔끔!
오늘도 릴리즈는 토끼처럼 빠르게
리팩토링의 들판을 뛰어넘어요!
🥕

Note

⚡️ AI Code Reviews for VS Code, Cursor, Windsurf

CodeRabbit now has a plugin for VS Code, Cursor and Windsurf. This brings AI code reviews directly in the code editor. Each commit is reviewed immediately, finding bugs before the PR is raised. Seamless context handoff to your AI code agent ensures that you can easily incorporate review feedback.
Learn more here.

✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@github-actions
Copy link
Copy Markdown

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (5)
src/features/host/model/host.ts (1)

1-13: 코드 중복 제거를 고려해보세요.

HostCreationRequestUpdateHostChannelInfoRequest 인터페이스가 동일한 구조를 가지고 있습니다. 공통 인터페이스를 만들거나 하나의 인터페이스를 재사용하는 것을 고려해보세요.

다음과 같이 리팩토링할 수 있습니다:

+export interface HostChannelInfo {
+  profileImageUrl: string;
+  hostChannelName: string;
+  hostEmail: string;
+  channelDescription: string;
+}
+
-export interface HostCreationRequest {
-  profileImageUrl: string;
-  hostChannelName: string;
-  hostEmail: string;
-  channelDescription: string;
-}
+export interface HostCreationRequest extends HostChannelInfo {}

-export interface UpdateHostChannelInfoRequest {
-  profileImageUrl: string;
-  hostChannelName: string;
-  hostEmail: string;
-  channelDescription: string;
-}
+export interface UpdateHostChannelInfoRequest extends HostChannelInfo {}
src/features/host/hook/useHostInfoHook.ts (1)

13-33: 사용자 경험 개선을 위한 피드백 방식 변경을 고려해보세요.

현재 alert를 사용한 피드백은 브라우저의 기본 알림창을 사용하여 사용자 경험이 좋지 않을 수 있습니다. toast 알림이나 다른 UI 컴포넌트 사용을 권장합니다.

또한 hostInfo?.result.id 검증만으로는 부족할 수 있습니다. 다른 필수 필드들도 함께 검증하는 것을 고려해보세요.

  const handleSave = () => {
-   if (!hostInfo?.result.id) return;
+   if (!hostInfo?.result?.id || !hostInfo?.result?.hostChannelName) {
+     // toast나 다른 UI 컴포넌트로 알림 표시
+     return;
+   }

    const updatedData = {
      hostChannelId,
      profileImageUrl: hostInfo.result.profileImageUrl,
      hostChannelName: hostInfo.result.hostChannelName,
      hostEmail: hostInfo.result.email,
      channelDescription,
    };

    mutate(updatedData, {
      onSuccess: () => {
        queryClient.invalidateQueries({ queryKey: ['hostInfo', hostChannelId] });
-       alert('저장되었습니다.');
+       // toast 알림 사용
      },
      onError: () => {
-       alert('저장에 실패했습니다.');
+       // toast 알림 사용
      },
    });
  };
src/features/host/hook/useInviteHostHook.ts (1)

14-25: Promise 생성 방식을 단순화할 수 있습니다.

현재 각 이메일에 대해 수동으로 Promise를 생성하고 있는데, 더 간단한 방식으로 개선할 수 있습니다.

- const invitationPromises = emails.map(
-   email =>
-     new Promise((resolve, reject) => {
-       inviteMember(
-         { email },
-         {
-           onSuccess: resolve,
-           onError: reject,
-         }
-       );
-     })
- );
+ const invitationPromises = emails.map(email => 
+   new Promise((resolve, reject) => {
+     inviteMember({ email }, { onSuccess: resolve, onError: reject });
+   })
+ );
src/features/host/hook/useHostHook.ts (1)

14-19: 기존 훅과의 타입 일관성을 고려해보세요.

useUpdateHostChannelInfo 훅은 제네릭 타입이 명시되지 않은 반면, 새로 추가된 훅들은 명시적인 제네릭 타입을 사용하고 있습니다. 일관성을 위해 이 훅도 제네릭 타입을 명시하는 것을 권장합니다.

export const useUpdateHostChannelInfo = (hostChannelId: number) => {
-  const mutation = useMutation({
+  const mutation = useMutation<ApiResponse<null>, Error, UpdateHostChannelInfoRequest>({
    mutationFn: (dto: UpdateHostChannelInfoRequest) => updateHostInfo(hostChannelId, dto),
  });
  return mutation;
};
src/features/host/api/host.ts (1)

9-12: 기존 함수와의 일관성을 위해 타입 명시를 권장합니다.

updateHostInfo 함수도 반환 타입을 명시하여 다른 API 함수들과의 일관성을 유지하는 것이 좋겠습니다.

-export const updateHostInfo = async (hostChannelId: number, dto: UpdateHostChannelInfoRequest) => {
+export const updateHostInfo = async (hostChannelId: number, dto: UpdateHostChannelInfoRequest): Promise<ApiResponse<null>> => {
  const response = await axiosClient.put(`/host-channels/${hostChannelId}`, dto);
  return response.data;
};
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 49c3bdb and ef22e1c.

📒 Files selected for processing (15)
  • src/features/event/api/host.ts (0 hunks)
  • src/features/event/hooks/useHostHook.ts (0 hunks)
  • src/features/event/model/hostCreation.ts (0 hunks)
  • src/features/event/ui/EventFunnel.tsx (1 hunks)
  • src/features/host/api/host.ts (1 hunks)
  • src/features/host/api/hostInvitation.ts (1 hunks)
  • src/features/host/hook/useHostHook.ts (1 hunks)
  • src/features/host/hook/useHostInfoHook.ts (1 hunks)
  • src/features/host/hook/useHostInvitation.ts (1 hunks)
  • src/features/host/hook/useInviteHostHook.ts (1 hunks)
  • src/features/host/model/host.ts (1 hunks)
  • src/features/host/model/hostInvitation.ts (1 hunks)
  • src/features/menu/ui/MemberEmailInput.tsx (1 hunks)
  • src/pages/event/ui/host/HostSelectionPage.tsx (1 hunks)
  • src/pages/menu/ui/myHost/HostEditPage.tsx (3 hunks)
💤 Files with no reviewable changes (3)
  • src/features/event/model/hostCreation.ts
  • src/features/event/api/host.ts
  • src/features/event/hooks/useHostHook.ts
🧰 Additional context used
🧬 Code Graph Analysis (4)
src/features/host/api/hostInvitation.ts (2)
src/features/host/model/hostInvitation.ts (1)
  • HostInvitationRequest (1-3)
src/shared/types/api/http-client.ts (1)
  • axiosClient (6-13)
src/features/host/hook/useHostInvitation.ts (3)
src/shared/types/api/apiResponse.ts (1)
  • ApiResponse (1-5)
src/features/host/model/hostInvitation.ts (1)
  • HostInvitationRequest (1-3)
src/features/host/api/hostInvitation.ts (1)
  • inviteMember (4-7)
src/features/host/hook/useHostHook.ts (3)
src/shared/types/api/apiResponse.ts (1)
  • ApiResponse (1-5)
src/features/host/model/host.ts (2)
  • HostCreationRequest (1-6)
  • UpdateHostChannelInfoRequest (8-13)
src/features/host/api/host.ts (3)
  • createHost (4-7)
  • updateHostInfo (9-12)
  • deleteHost (14-17)
src/features/host/api/host.ts (2)
src/features/host/model/host.ts (2)
  • HostCreationRequest (1-6)
  • UpdateHostChannelInfoRequest (8-13)
src/shared/types/api/http-client.ts (1)
  • axiosClient (6-13)
🔇 Additional comments (14)
src/features/host/model/hostInvitation.ts (1)

1-3: 인터페이스 정의가 적절합니다!

호스트 멤버 초대를 위한 간단하고 명확한 인터페이스입니다. 타입 정의가 올바르고 네이밍 컨벤션을 잘 따르고 있습니다.

src/pages/event/ui/host/HostSelectionPage.tsx (1)

7-7: 올바른 import 경로 업데이트입니다.

호스트 관련 기능이 event feature에서 host feature로 이동한 리팩토링에 맞춰 import 경로가 정확히 업데이트되었습니다.

src/features/event/ui/EventFunnel.tsx (1)

14-14: 리팩토링에 따른 적절한 import 경로 변경입니다.

호스트 생성 훅이 host feature로 이동한 것에 맞춰 import 경로가 올바르게 업데이트되었습니다.

src/features/host/model/host.ts (1)

1-6: 호스트 생성 인터페이스가 잘 정의되었습니다.

호스트 채널 생성에 필요한 모든 속성이 적절히 포함되어 있습니다.

src/features/host/api/hostInvitation.ts (1)

1-7: 호스트 멤버 초대 API 함수가 올바르게 구현되었습니다.

REST API 패턴을 잘 따르고 있으며, 기존 프로젝트의 HTTP 클라이언트 사용 방식과 일관성을 유지하고 있습니다. 타입 안전성도 잘 확보되어 있습니다.

src/features/host/hook/useHostInvitation.ts (1)

1-12: 구현이 깔끔하고 타입 안전성이 잘 보장되고 있습니다.

단일 책임 원칙을 잘 따르고 있으며, React Query의 useMutation을 적절히 활용한 간결한 구현입니다. 타입 정의도 명확하고 API 함수 호출 구조가 직관적입니다.

src/features/menu/ui/MemberEmailInput.tsx (1)

4-9: State lifting을 통한 좋은 리팩토링입니다.

이메일 상태 관리를 부모 컴포넌트로 이동시켜 재사용성과 제어권을 향상시켰습니다. props interface의 타입 정의도 명확하고 적절합니다.

src/features/host/hook/useHostHook.ts (2)

6-12: 타입 안전성이 잘 구현된 새로운 훅입니다.

useHostCreation 훅은 명시적인 제네릭 타입을 사용하여 타입 안전성을 보장하고 있습니다. ApiResponse<null>, Error, HostCreationRequest 타입이 명확히 정의되어 있어 좋습니다.


21-27: 타입 안전성이 잘 구현된 삭제 훅입니다.

useHostDeletion 훅도 명시적인 제네릭 타입을 사용하여 타입 안전성을 보장하고 있습니다. 숫자 타입의 hostChannelId를 받아 삭제 API를 호출하는 구조가 명확합니다.

src/pages/menu/ui/myHost/HostEditPage.tsx (5)

10-11: 새로운 훅 import가 잘 구성되었습니다.

호스트 정보 저장과 멤버 초대를 위한 새로운 훅들이 명확하게 import되어 관심사의 분리가 잘 이루어졌습니다.


18-18: 상태 관리가 단순화되어 좋습니다.

이전의 복잡한 태그 관리에서 단순한 이메일 배열로 변경되어 상태 관리가 명확해졌습니다.


22-24: 훅 사용 패턴이 일관성 있게 구현되었습니다.

새로운 훅들의 사용 패턴이 일관성 있게 구현되어 있고, 필요한 매개변수들이 적절히 전달되고 있습니다.


122-122: props 전달 방식이 개선되었습니다.

MemberEmailInput 컴포넌트에 emailssetEmails를 props로 전달하는 방식으로 변경되어 컴포넌트 간의 데이터 흐름이 명확해졌습니다.


128-128: 이벤트 핸들러 연결이 적절히 구현되었습니다.

새로운 handleInviteMembers 함수가 버튼의 onClick 이벤트에 적절히 연결되어 있습니다.

Comment on lines +4 to +7
export const inviteMember = async (hostChannelId: number, data: HostInvitationRequest) => {
const response = await axiosClient.post(`/host-channels/${hostChannelId}/members`, data);
return response.data;
};
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

에러 처리 방식을 확인해주세요.

현재 함수에서는 별도의 에러 처리가 없습니다. 이것이 의도된 것인지, 아니면 호출하는 훅에서 처리하는지 확인해보세요. API 호출 실패 시 적절한 에러 메시지나 처리가 필요할 수 있습니다.

다음 스크립트로 관련 훅의 에러 처리 방식을 확인해보겠습니다:


🏁 Script executed:

#!/bin/bash
# Description: 호스트 초대 관련 훅에서 에러 처리 방식 확인

# inviteMember 함수를 사용하는 훅들 찾기
rg -A 10 "inviteMember" --type ts

# React Query의 에러 처리 패턴 확인
rg -A 5 "onError" src/features/host/hook/

Length of output: 5843


에러 처리 방식 보완 필요
현재 inviteMembers 호출 시 API 오류에 대한 사용자 알림이 없어, onError 콜백을 전달하지 않으면 에러가 묵살됩니다. useInviteHostHook에 기본 에러 처리 로직을 추가하거나, 호출부에서 onError 콜백을 명시적으로 전달해 주세요.

검토/수정 위치:

  • src/features/host/hook/useInviteHostHook.ts
    inviteMembers.catch()에서 기본 알림(alert 등) 추가
  • src/pages/menu/ui/myHost/HostEditPage.tsx
    inviteMembers(emails, onSuccess) 호출 시 onError 콜백 전달 예:
    inviteMembers(
      emails,
      () => setEmails([]),
      () => alert('초대에 실패했습니다.')
    );
🤖 Prompt for AI Agents
In src/features/host/api/hostInvitation.ts lines 4 to 7, the inviteMember
function lacks error handling, which can cause API call failures to be silently
ignored. To fix this, ensure that the function either includes try-catch blocks
to handle errors and provide meaningful messages or that the calling hooks
explicitly pass onError callbacks to handle errors. Additionally, update
src/features/host/hook/useInviteHostHook.ts to add default error handling in the
inviteMembers catch block, such as showing an alert, and modify
src/pages/menu/ui/myHost/HostEditPage.tsx to pass an onError callback when
calling inviteMembers to notify users on failure.

Comment on lines +8 to +37
const inviteMembers = (emails: string[], onSuccess?: () => void, onError?: () => void) => {
if (emails.length === 0) {
alert('초대할 이메일을 입력해주세요.');
return;
}

const invitationPromises = emails.map(
email =>
new Promise((resolve, reject) => {
inviteMember(
{ email },
{
onSuccess: resolve,
onError: reject,
}
);
})
);

Promise.all(invitationPromises)
.then(() => {
alert('초대가 전송되었습니다.');
queryClient.invalidateQueries({ queryKey: ['hostInfo', hostChannelId] });
onSuccess?.();
})
.catch(() => {
alert('초대 중 일부 실패했습니다.');
onError?.();
});
};
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Promise 처리 방식 개선과 사용자 피드백 향상을 고려해보세요.

현재 구현에서 몇 가지 개선할 점이 있습니다:

  1. Promise.all 사용의 문제점: 하나의 초대가 실패하면 전체가 실패로 처리됩니다. Promise.allSettled를 사용하여 개별 결과를 처리하는 것을 고려해보세요.

  2. 사용자 피드백: alert 대신 toast나 다른 UI 컴포넌트 사용을 권장합니다.

  3. 더 상세한 에러 정보: 어떤 이메일이 실패했는지 사용자에게 알려주면 좋겠습니다.

- Promise.all(invitationPromises)
+ Promise.allSettled(invitationPromises)
    .then((results) => {
+     const failures = results.filter(result => result.status === 'rejected');
+     const successes = results.filter(result => result.status === 'fulfilled');
      
+     if (failures.length === 0) {
-       alert('초대가 전송되었습니다.');
+       // toast: '모든 초대가 성공적으로 전송되었습니다.'
        queryClient.invalidateQueries({ queryKey: ['hostInfo', hostChannelId] });
        onSuccess?.();
+     } else if (successes.length > 0) {
+       // toast: `${successes.length}명 초대 성공, ${failures.length}명 실패`
+       queryClient.invalidateQueries({ queryKey: ['hostInfo', hostChannelId] });
+       onSuccess?.();
+     } else {
+       // toast: '모든 초대가 실패했습니다.'
+       onError?.();
+     }
    })
-   .catch(() => {
-     alert('초대 중 일부 실패했습니다.');
-     onError?.();
-   });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const inviteMembers = (emails: string[], onSuccess?: () => void, onError?: () => void) => {
if (emails.length === 0) {
alert('초대할 이메일을 입력해주세요.');
return;
}
const invitationPromises = emails.map(
email =>
new Promise((resolve, reject) => {
inviteMember(
{ email },
{
onSuccess: resolve,
onError: reject,
}
);
})
);
Promise.all(invitationPromises)
.then(() => {
alert('초대가 전송되었습니다.');
queryClient.invalidateQueries({ queryKey: ['hostInfo', hostChannelId] });
onSuccess?.();
})
.catch(() => {
alert('초대 중 일부 실패했습니다.');
onError?.();
});
};
const inviteMembers = (emails: string[], onSuccess?: () => void, onError?: () => void) => {
if (emails.length === 0) {
alert('초대할 이메일을 입력해주세요.');
return;
}
const invitationPromises = emails.map(
email =>
new Promise((resolve, reject) => {
inviteMember(
{ email },
{
onSuccess: resolve,
onError: reject,
}
);
})
);
Promise.allSettled(invitationPromises)
.then((results) => {
const failures = results.filter(r => r.status === 'rejected');
const successes = results.filter(r => r.status === 'fulfilled');
if (failures.length === 0) {
// toast: '모든 초대가 성공적으로 전송되었습니다.'
queryClient.invalidateQueries({ queryKey: ['hostInfo', hostChannelId] });
onSuccess?.();
} else if (successes.length > 0) {
// toast: `${successes.length}명 초대 성공, ${failures.length}명 실패`
queryClient.invalidateQueries({ queryKey: ['hostInfo', hostChannelId] });
onSuccess?.();
} else {
// toast: '모든 초대가 실패했습니다.'
onError?.();
}
});
};
🤖 Prompt for AI Agents
In src/features/host/hook/useInviteHostHook.ts between lines 8 and 37, replace
Promise.all with Promise.allSettled to handle each invitation result
individually so that one failure does not reject all. Collect and identify which
emails failed and provide this detailed feedback to the user. Also, replace
alert calls with a toast or UI notification component for better user
experience.

Comment on lines +4 to +7
export const createHost = async (data: HostCreationRequest) => {
const response = await axiosClient.post('/host-channels', data);
return response.data;
};
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

에러 처리와 반환 타입 명시를 고려해보세요.

createHost 함수는 구조적으로는 잘 작성되었지만, 에러 처리와 반환 타입이 명시되지 않았습니다. API 호출 실패 시의 처리와 타입 안전성을 위해 개선을 권장합니다.

-export const createHost = async (data: HostCreationRequest) => {
+export const createHost = async (data: HostCreationRequest): Promise<ApiResponse<null>> => {
+  try {
    const response = await axiosClient.post('/host-channels', data);
    return response.data;
+  } catch (error) {
+    throw error;
+  }
};
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const createHost = async (data: HostCreationRequest) => {
const response = await axiosClient.post('/host-channels', data);
return response.data;
};
export const createHost = async (data: HostCreationRequest): Promise<ApiResponse<null>> => {
try {
const response = await axiosClient.post('/host-channels', data);
return response.data;
} catch (error) {
throw error;
}
};
🤖 Prompt for AI Agents
In src/features/host/api/host.ts around lines 4 to 7, the createHost function
lacks error handling and does not explicitly specify its return type. To fix
this, add a try-catch block around the axiosClient.post call to handle potential
API call failures gracefully, and define the function's return type to ensure
type safety and clarity about the expected response structure.

Comment on lines +14 to +17
export const deleteHost = async (hostChannelId: number) => {
const response = await axiosClient.delete(`/host-channels/${hostChannelId}`);
return response.data;
};
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

에러 처리와 반환 타입 명시를 고려해보세요.

deleteHost 함수도 createHost와 마찬가지로 에러 처리와 반환 타입 명시가 필요합니다.

-export const deleteHost = async (hostChannelId: number) => {
+export const deleteHost = async (hostChannelId: number): Promise<ApiResponse<null>> => {
+  try {
    const response = await axiosClient.delete(`/host-channels/${hostChannelId}`);
    return response.data;
+  } catch (error) {
+    throw error;
+  }
};
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const deleteHost = async (hostChannelId: number) => {
const response = await axiosClient.delete(`/host-channels/${hostChannelId}`);
return response.data;
};
export const deleteHost = async (hostChannelId: number): Promise<ApiResponse<null>> => {
try {
const response = await axiosClient.delete(`/host-channels/${hostChannelId}`);
return response.data;
} catch (error) {
throw error;
}
};
🤖 Prompt for AI Agents
In src/features/host/api/host.ts around lines 14 to 17, the deleteHost function
lacks error handling and does not explicitly specify its return type. Add a
try-catch block to handle potential errors from the axios delete request, and
define the function's return type to match the expected response data structure
for better type safety and clarity.

Comment on lines +35 to 39
const handleInviteMembers = () => {
if (!hostInfo?.result.id) return;

const updatedData = {
hostChannelId,
profileImageUrl: hostInfo.result.profileImageUrl,
hostChannelName: hostInfo.result.hostChannelName,
hostEmail: hostInfo.result.email,
channelDescription,
};

mutate(updatedData, {
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: ['hostInfo', hostChannelId],
});
alert('저장되었습니다.');
},
onError: () => {
alert('저장에 실패했습니다.');
},
});
};

const handleAddClick = () => {
if (inputValue.trim() && !tags.includes(inputValue.trim())) {
setTags([...tags, inputValue.trim()]);
setInputValue('');
}
inviteMembers(emails, () => setEmails([]));
};
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

에러 처리 및 사용자 피드백 개선을 고려해보세요.

handleInviteMembers 함수는 기본적인 기능은 잘 구현되었지만, 에러 처리와 사용자 피드백이 부족합니다. 초대 실패 시의 처리와 성공/실패에 대한 사용자 알림을 추가하는 것을 권장합니다.

const handleInviteMembers = () => {
  if (!hostInfo?.result.id) return;

-  inviteMembers(emails, () => setEmails([]));
+  inviteMembers(emails, {
+    onSuccess: () => {
+      setEmails([]);
+      // 성공 토스트 메시지 표시
+    },
+    onError: (error) => {
+      // 에러 토스트 메시지 표시
+      console.error('멤버 초대 실패:', error);
+    }
+  });
};
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const handleInviteMembers = () => {
if (!hostInfo?.result.id) return;
const updatedData = {
hostChannelId,
profileImageUrl: hostInfo.result.profileImageUrl,
hostChannelName: hostInfo.result.hostChannelName,
hostEmail: hostInfo.result.email,
channelDescription,
};
mutate(updatedData, {
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: ['hostInfo', hostChannelId],
});
alert('저장되었습니다.');
},
onError: () => {
alert('저장에 실패했습니다.');
},
});
};
const handleAddClick = () => {
if (inputValue.trim() && !tags.includes(inputValue.trim())) {
setTags([...tags, inputValue.trim()]);
setInputValue('');
}
inviteMembers(emails, () => setEmails([]));
};
const handleInviteMembers = () => {
if (!hostInfo?.result.id) return;
inviteMembers(emails, {
onSuccess: () => {
setEmails([]);
// 성공 토스트 메시지 표시
},
onError: (error) => {
// 에러 토스트 메시지 표시
console.error('멤버 초대 실패:', error);
}
});
};
🤖 Prompt for AI Agents
In src/pages/menu/ui/myHost/HostEditPage.tsx around lines 35 to 39, the
handleInviteMembers function lacks error handling and user feedback. Modify the
function to handle possible errors from inviteMembers by adding a callback or
promise handling that detects success or failure. On success, clear the emails
and show a success notification to the user; on failure, display an error
message to inform the user about the invite failure.

Copy link
Copy Markdown
Member

@hyeeuncho hyeeuncho left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM~

@Yejiin21 Yejiin21 merged commit 73864e5 into develop May 25, 2025
2 checks passed
@Yejiin21 Yejiin21 deleted the feat/#138/host-member-invitation branch May 25, 2025 12:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🔧 Feature 기능 구현

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[feat] 호스트 멤버 초대 API 연동

2 participants