Skip to content

[CCI-42] 면접 수정 및 옵션 수정 API 연동 완료#4

Merged
jpark0506 merged 1 commit intomainfrom
feat/CCI-42
Jun 3, 2025
Merged

[CCI-42] 면접 수정 및 옵션 수정 API 연동 완료#4
jpark0506 merged 1 commit intomainfrom
feat/CCI-42

Conversation

@jpark0506
Copy link
Contributor

@jpark0506 jpark0506 commented Jun 2, 2025

Summary by CodeRabbit

  • New Features

    • Added the ability to update interview details, including title, schedule, visibility, participants, resume, and cover letter, directly from the interview edit page.
  • Bug Fixes

    • Improved error handling during interview updates, providing clear alerts for both success and failure scenarios.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jun 2, 2025

Walkthrough

The changes revise the updateInterviewOption API to include memberId in the payload and introduce a new updateInterview API for updating interview details. The interview edit page's save handler is updated to use these APIs asynchronously, providing user feedback and navigation on success or failure.

Changes

File(s) Change Summary
api/interview.ts Modified updateInterviewOption to include memberId in the payload; added new updateInterview function.
app/workspace/interviews/edit/[id]/page.tsx Updated handleSave to an async function using new/updated APIs; added error handling and user notifications.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant EditPage
    participant API

    User->>EditPage: Clicks "Save"
    EditPage->>API: updateInterview(interviewId, interviewData)
    API-->>EditPage: Success/Error
    EditPage->>API: updateInterviewOption(interviewId, memberId, optionData)
    API-->>EditPage: Success/Error
    alt Success
        EditPage->>User: Alert success, redirect to interview list
    else Failure
        EditPage->>User: Alert error message
    end
Loading

Possibly related PRs

Poem

A bunny hops with code so bright,
Updating interviews left and right!
With options merged and details new,
Async saves now follow through.
Alerts will cheer, errors will warn—
Another feature, neatly born!
🐇✨

✨ 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.

Copy link
Contributor

@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: 3

🔭 Outside diff range comments (1)
api/interview.ts (1)

38-47: ⚠️ Potential issue

Fix type annotation inconsistency in function signature

There's a mismatch between the function signature and the type annotation. The function parameters still accept memberId as a separate parameter, but the type annotation suggests memberId should be part of the data object.

Apply this diff to fix the type annotation:

export async function updateInterviewOption(
  interviewId: number,
  memberId: number,
-  data: InterviewOptionUpdateDTO
+  data: InterviewOptionUpdateDTO
) {
  return serverFetch.patch<
    ApiResponseInterviewOptionUpdateResponseDTO,
    InterviewOptionUpdateDTO & { memberId: number }
  >(`/interviews/${interviewId}/option`, { ...data, memberId });
}

The current implementation is correct - memberId is passed as a separate parameter and then merged into the request body. The type annotation should reflect the actual function signature.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 840e66c and f33309b.

📒 Files selected for processing (2)
  • api/interview.ts (2 hunks)
  • app/workspace/interviews/edit/[id]/page.tsx (3 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (2)
app/workspace/interviews/edit/[id]/page.tsx (1)
api/interview.ts (2)
  • updateInterview (98-111)
  • updateInterviewOption (38-47)
api/interview.ts (2)
api/types/interview-types.ts (1)
  • InterviewOptionUpdateDTO (109-121)
utils/fetch/fetch.ts (1)
  • serverFetch (135-135)
🔇 Additional comments (2)
app/workspace/interviews/edit/[id]/page.tsx (2)

13-13: LGTM!

The import statement correctly includes the required API functions for the new functionality.


112-112: LGTM!

Converting the function to async is necessary for the API integration and is properly implemented.

Comment on lines +98 to +111
export async function updateInterview(
interviewId: number,
data: {
title: string;
startAt: string;
isPublic: boolean;
maxParticipants: string;
participants: { id: number; email: string }[];
resume: string;
coverLetter: string;
}
) {
return serverFetch.put(`/interviews/${interviewId}`, data);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add return type annotation and consider creating a proper DTO interface

The function lacks a return type annotation and uses an inline object type for the data parameter.

Consider these improvements:

  1. Add proper return type annotation:
export async function updateInterview(
  interviewId: number,
  data: {
    title: string;
    startAt: string;
    isPublic: boolean;
    maxParticipants: string;
    participants: { id: number; email: string }[];
    resume: string;
    coverLetter: string;
  }
-) {
+): Promise<any> {
  return serverFetch.put(`/interviews/${interviewId}`, data);
}
  1. Create a proper DTO interface in api/types/interview-types.ts:
export interface InterviewUpdateDTO {
  title: string;
  startAt: string;
  isPublic: boolean;
  maxParticipants: string;
  participants: { id: number; email: string }[];
  resume: string;
  coverLetter: string;
}

Then update the function to use this interface for better type safety and maintainability.

🤖 Prompt for AI Agents
In api/interview.ts around lines 98 to 111, the updateInterview function lacks a
return type annotation and uses an inline object type for the data parameter. To
fix this, create an InterviewUpdateDTO interface in api/types/interview-types.ts
with the specified fields, then import and use this interface as the type for
the data parameter. Also, add an appropriate return type annotation to the
function based on the expected response from serverFetch.put for better type
safety and maintainability.

answerTime: interview.answerDuration || 3,
})
alert("면접 정보가 성공적으로 업데이트되었습니다.")
window.location.href = "/workspace/interviews"
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Use Next.js router for navigation instead of window.location.href

Using window.location.href causes a full page reload, which is not optimal in a Next.js application.

Import and use Next.js router:

+import { useRouter } from 'next/navigation'

export default function EditInterviewPage({ params }: { params: { id: string } }) {
+  const router = useRouter()
  // ... other code

  const handleSave = async () => {
    // ... existing code
    try {
      // ... API calls
      alert("면접 정보가 성공적으로 업데이트되었습니다.")
-      window.location.href = "/workspace/interviews"
+      router.push("/workspace/interviews")
    } catch (err: any) {
      alert(err?.message || "면접 정보 업데이트에 실패했습니다.")
    }
  }

This provides better performance and maintains the SPA behavior.

🤖 Prompt for AI Agents
In app/workspace/interviews/edit/[id]/page.tsx at line 147, replace the use of
window.location.href for navigation with Next.js router's push method. Import
the useRouter hook from 'next/navigation', initialize the router, and use
router.push('/workspace/interviews') to navigate without a full page reload,
preserving SPA behavior and improving performance.

Comment on lines +129 to 150
try {
// 1. 면접 정보 수정
await updateInterview(Number(interviewId), {
title,
startAt: `${date}T${time}`,
isPublic,
maxParticipants,
participants,
resume: selectedResume,
coverLetter: selectedCoverLetter,
})
// 2. 면접 옵션 수정
await updateInterviewOption(Number(interviewId), interview.hostId || 1, {
voiceType: interview.voiceType || 'FEMALE20',
questionNumber: interview.questionNumber || 10,
answerTime: interview.answerDuration || 3,
})
alert("면접 정보가 성공적으로 업데이트되었습니다.")
window.location.href = "/workspace/interviews"
} catch (err: any) {
alert(err?.message || "면접 정보 업데이트에 실패했습니다.")
}
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Address potential runtime errors with hardcoded fallback values

The API calls use hardcoded fallback values that may not exist in the interview object, which could cause runtime errors or unexpected behavior.

Issues identified:

  1. interview.hostId || 1 - if hostId is undefined, using 1 as fallback could assign the interview to the wrong user
  2. interview.voiceType || 'FEMALE20' - hardcoded fallback may not match user preferences
  3. interview.questionNumber || 10 and interview.answerDuration || 3 - hardcoded defaults may not be appropriate

Additionally, consider these improvements:

// 2. 면접 옵션 수정
await updateInterviewOption(Number(interviewId), interview.hostId || 1, {
-  voiceType: interview.voiceType || 'FEMALE20',
-  questionNumber: interview.questionNumber || 10,
-  answerTime: interview.answerDuration || 3,
+  voiceType: interview.voiceType,
+  questionNumber: interview.questionNumber,
+  answerTime: interview.answerDuration,
})

Add proper validation before the API calls to ensure required fields exist, or fetch these values from a proper source rather than using hardcoded defaults.


🏁 Script executed:

#!/bin/bash
# Search for where these interview properties are defined or used elsewhere
rg -A 3 -B 3 "hostId|voiceType|questionNumber|answerDuration" --type ts --type tsx

Length of output: 112


Let’s inspect the component to verify how interview is defined and whether those fields are guaranteed:


🏁 Script executed:

#!/bin/bash
# Show the top of the edit page component to find the interview fetch and its type
sed -n '1,200p' app/workspace/interviews/edit/\[id\]/page.tsx

Length of output: 6407


🏁 Script executed:

#!/bin/bash
# Locate the definition of updateInterviewOption to inspect required parameters
rg -n "updateInterviewOption" -t ts -t tsx

Length of output: 70


🏁 Script executed:

#!/bin/bash
# Search for updateInterviewOption definition across .ts and .tsx files without type filters
rg -n "updateInterviewOption" -g '*.ts' -g '*.tsx'

Length of output: 363


🏁 Script executed:

#!/bin/bash
# Display the definition and signature of updateInterviewOption
sed -n '1,200p' api/interview.ts

Length of output: 2890


Ensure interview option fields are loaded and validated before saving

Right now the mock interview object on mount doesn’t include hostId, voiceType, questionNumber, or answerDuration, so your handleSave call always falls back to the hard-coded values:

  • interview.hostId || 1 will always be 1, which could assign the option update to the wrong user.
  • interview.voiceType || 'FEMALE20', interview.questionNumber || 10, and interview.answerDuration || 3 may override real settings with arbitrary defaults.

Action items:

  • Fetch the existing interview options (including hostId, voiceType, questionNumber, answerDuration) when the page loads and merge them into your interview state.
  • In handleSave (app/workspace/interviews/edit/[id]/page.tsx), remove the hard-coded fallbacks and require those fields to be present:
    // 2. 면접 옵션 수정
  • await updateInterviewOption(Number(interviewId), interview.hostId || 1, {
  • voiceType: interview.voiceType || 'FEMALE20',
  • questionNumber: interview.questionNumber || 10,
  • answerTime: interview.answerDuration || 3,
  • })
  • // Derive hostId from logged-in user or fetched data
  • await updateInterviewOption(
  • Number(interviewId),
  • interview.hostId!,
  • {
  • voiceType: interview.voiceType!,
    
  • questionNumber: interview.questionNumber!,
    
  • answerTime: interview.answerDuration!,
    
  • }
  • )
  • Add validation before saving to ensure none of those fields are undefined (e.g., show an error if any are missing).

By loading real option values up‐front and validating them, you’ll avoid assigning the interview to the wrong user or overwriting true settings with defaults.

📝 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
try {
// 1. 면접 정보 수정
await updateInterview(Number(interviewId), {
title,
startAt: `${date}T${time}`,
isPublic,
maxParticipants,
participants,
resume: selectedResume,
coverLetter: selectedCoverLetter,
})
// 2. 면접 옵션 수정
await updateInterviewOption(Number(interviewId), interview.hostId || 1, {
voiceType: interview.voiceType || 'FEMALE20',
questionNumber: interview.questionNumber || 10,
answerTime: interview.answerDuration || 3,
})
alert("면접 정보가 성공적으로 업데이트되었습니다.")
window.location.href = "/workspace/interviews"
} catch (err: any) {
alert(err?.message || "면접 정보 업데이트에 실패했습니다.")
}
try {
// 1. 면접 정보 수정
await updateInterview(Number(interviewId), {
title,
startAt: `${date}T${time}`,
isPublic,
maxParticipants,
participants,
resume: selectedResume,
coverLetter: selectedCoverLetter,
})
// Derive hostId from logged-in user or fetched data
await updateInterviewOption(
Number(interviewId),
interview.hostId!,
{
voiceType: interview.voiceType!,
questionNumber: interview.questionNumber!,
answerTime: interview.answerDuration!,
}
)
alert("면접 정보가 성공적으로 업데이트되었습니다.")
window.location.href = "/workspace/interviews"
} catch (err: any) {
alert(err?.message || "면접 정보 업데이트에 실패했습니다.")
}
🤖 Prompt for AI Agents
In app/workspace/interviews/edit/[id]/page.tsx around lines 129 to 150, the code
uses hardcoded fallback values for interview options like hostId, voiceType,
questionNumber, and answerDuration, which can cause incorrect data updates. To
fix this, fetch and merge the actual interview option values into the interview
state when the page loads, remove the hardcoded defaults in the
updateInterviewOption call, and add validation before saving to ensure these
fields are defined, showing an error if any are missing.

@jpark0506 jpark0506 merged commit 2ebb7fd into main Jun 3, 2025
1 check passed
@jpark0506 jpark0506 deleted the feat/CCI-42 branch June 3, 2025 16:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant