Skip to content

[FEATURE] 저장 링크 API 연동 및 제목 수정 기능 적용#46

Merged
kbh0218 merged 8 commits into
devfrom
feat/#45-saved-links-api
May 22, 2026
Merged

[FEATURE] 저장 링크 API 연동 및 제목 수정 기능 적용#46
kbh0218 merged 8 commits into
devfrom
feat/#45-saved-links-api

Conversation

@kbh0218

@kbh0218 kbh0218 commented May 21, 2026

Copy link
Copy Markdown
Contributor

Closes #45

개요

safe/caution 검사 결과 화면과 저장 링크 목록 화면에서 기존 mock 기반 저장 링크 흐름을 실제 백엔드 Saved Link API 연동 흐름으로 교체했습니다.

분석 완료 후 전달받은 analysisId를 기준으로 POST /api/v1/saved-links를 호출해 링크를 저장하고, 저장 링크 목록은 GET /api/v1/saved-links 응답의 items, hasNext, nextCursor 구조를 기준으로 표시하도록 정리했습니다.

또한 저장 링크 카드의 더보기 메뉴에서 기존 북마크 추가 항목을 제목 수정으로 변경하고, 제목 수정 모달을 통해 PATCH /api/v1/saved-links/{id}/title API와 연동했습니다. 북마크 변경과 링크 삭제 역시 각각 PATCH /api/v1/saved-links/{id}/bookmark, DELETE /api/v1/saved-links/{id} API 호출 결과를 화면 상태에 반영하도록 변경했습니다.

주요 구현 내용

  • 저장 링크 API 전용 파일 api/saved-links.ts 추가
  • POST /api/v1/saved-links 저장 API 연동
  • GET /api/v1/saved-links 목록 조회 API 연동
  • DELETE /api/v1/saved-links/{id} 삭제 API 연동
  • PATCH /api/v1/saved-links/{id}/bookmark 북마크 변경 API 연동
  • PATCH /api/v1/saved-links/{id}/title 제목 수정 API 연동
  • 저장 링크 context의 mock 목록을 API 기반 상태로 교체
  • 목록 응답의 items, hasNext, nextCursor 상태 반영
  • 저장 링크 목록 로딩, 빈 목록, API 에러, 더 불러오기 상태 처리
  • safe/caution 결과 화면에서 analysisId, categoryId, title, description 구조로 저장 요청
  • 저장 중 중복 클릭 방지
  • danger 결과 화면에는 저장 기능 미추가
  • 저장/삭제/제목 수정 성공 시 상단 토스트 표시
  • 제목 수정 모달에서 현재 제목을 초기값으로 표시
  • 제목이 비어 있거나 500자를 초과하거나 기존 제목과 동일하면 저장 버튼 비활성화
  • 공용 Toast 컴포넌트에 placement, topOffset 옵션 추가

파일별 역할

  • api/saved-links.ts: 저장 링크 생성/조회/삭제/북마크/카테고리/제목 수정 API 타입 및 호출 함수 추가
  • context/saved-links-context.tsx: 저장 링크 API 기반 목록 상태, pagination 상태, 저장/북마크/삭제/제목 수정 액션 관리
  • app/(tabs)/(home)/scan-result.tsx: 안전 결과 화면의 실제 저장 API 호출, 저장 중 상태, 저장 성공 후 홈 이동 및 토스트 처리
  • app/(tabs)/(home)/scan-result-caution.tsx: 주의 결과 화면의 실제 저장 API 호출, 저장 중 상태, 저장 성공 후 홈 이동 및 토스트 처리
  • app/(tabs)/(home)/saved-links.tsx: 저장 링크 목록 조회 상태 표시, 북마크/삭제/제목 수정 API 연동, 제목 수정 모달 및 토스트 처리
  • app/(tabs)/(home)/index.tsx: 홈 최근 저장 링크 카드의 제목 수정/삭제/북마크 흐름 및 토스트 처리
  • components/ui/link-save-modal.tsx: 저장 중 상태, 500자 제목 제한, 중복 저장 클릭 방지 UI 반영
  • components/ui/toast.tsx: 상단 배치 옵션 및 offset 옵션 추가

해결한 이슈 목록

  • safe 결과 링크 저장 흐름 확인 및 실제 저장 API 연동
  • caution 결과 링크 저장 흐름 확인 및 실제 저장 API 연동
  • 결과 화면에서 전달받은 analysisIdPOST /api/v1/saved-links 호출
  • 저장 요청 구조를 analysisId, categoryId, title, description으로 구성
  • 저장 성공/실패/중복 저장/API 에러 피드백 처리
  • 저장 중 버튼 중복 클릭 방지
  • danger 결과 화면에는 저장 기능 미추가
  • saved-links-context.tsx의 mock 저장 링크 상태를 API 기반 상태로 교체
  • 저장 링크 목록 조회를 GET /api/v1/saved-links와 연동
  • 목록 응답의 items, hasNext, nextCursor 구조 반영
  • 목록 로딩/빈 목록/API 에러 상태 처리
  • 북마크 변경을 PATCH /api/v1/saved-links/{id}/bookmark와 연동
  • 북마크 변경 성공 시 응답의 isBookmarked 값 반영
  • 링크 삭제를 DELETE /api/v1/saved-links/{id}와 연동
  • 삭제 성공 시 목록에서 해당 링크 제거
  • 북마크/삭제 실패 시 기존 상태로 rollback 처리
  • 더보기 메뉴의 북마크 추가 항목을 제목 수정으로 변경
  • 제목 수정 클릭 시 폴더명 수정과 동일한 형태의 모달 표시
  • 제목 수정 모달에서 현재 링크 제목을 초기값으로 표시
  • 입력한 제목으로 PATCH /api/v1/saved-links/{id}/title 호출
  • 제목 수정 성공 시 응답의 title 값을 목록/context 상태에 반영
  • 빈 제목, 500자 초과, 중복 제목 등 에러 상황 안내 또는 저장 비활성화 처리
  • 제목 수정 취소 시 기존 제목과 목록 상태 유지
  • issue [FEATURE] Clerk 토큰 기반 보호 API 요청 구조 공통화 #41 공통 API 클라이언트 패턴 준수
  • 기능별 API 파일에서 API base URL 새로 생성하지 않음
  • 기능별 API 파일에서 fetch() 직접 호출하지 않음
  • 기능별 API 파일에서 Authorization 헤더 직접 주입하지 않음
  • 기능별 API 파일에서 { data: ... } 응답 직접 unwrap하지 않음
  • Clerk 세션 토큰이 필요한 API는 authenticatedApiRequest 사용
  • 보호 API 호출이 /auth/me 수동 사전 호출에 의존하지 않음
  • 204 No Content 삭제 API가 공통 클라이언트 흐름에서 처리되도록 구성

체크 사항

  • 커밋/코딩 컨벤션에 맞게 작성
  • 프론트 API 클라이언트 사용 규칙 준수
  • 저장 링크 API 파일에서 직접 fetch() 호출 없음
  • 저장 링크 API 파일에서 직접 API base URL 생성 없음
  • 저장 링크 API 파일에서 직접 Authorization 헤더 주입 없음
  • 저장 링크 API 파일에서 { data: ... } 응답 직접 unwrap 없음

참고

카테고리/폴더 API 실제 연동은 이번 PR 범위에서 제외했습니다.

저장 링크 목록 화면의 폴더 필터 칩은 기존 화면 흐름을 유지하되, 저장 링크 API 호출 함수에서는 categoryId, bookmarked, cursor, size query를 지원하도록 준비했습니다.

DELETE /api/v1/saved-links/{id}는 백엔드가 204 No Content를 반환하는 계약이므로, 공통 API 클라이언트의 204 처리 흐름을 그대로 사용합니다.

스크린샷

  • 북마크 추가 버튼 대신 제목 수정 버튼을 삽입
image
  • 링크 삭제 누를 때 뜨는 확인창
image
  • 삭제 후 뜨는 toast 화면
image

@kbh0218 kbh0218 requested review from minsoo0506 and sunm2n May 21, 2026 15:41
@kbh0218 kbh0218 self-assigned this May 21, 2026
@kbh0218 kbh0218 added the feature 기능개발 label May 21, 2026

@sunm2n sunm2n left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

제목 수정 모달 UI가 두 파일에 완전 중복

index.tsx와 saved-links.tsx에 동일한 Modal JSX, renameStyles, handleTitleCancel, handleTitleConfirm, openTitleModal, titleSubmitDisabled 로직이 똑같아 보입니다.
별도의 TitleEditModal 컴포넌트 또는 useTitleEdit 훅으로 추출하는 것을 제안드립니다.

  // components/ui/title-edit-modal.tsx 로 추출 권장
  interface TitleEditModalProps {
    editingLink: SavedLink | null;
    onConfirm: (id: number, title: string) => Promise<void>;
    onClose: () => void;
  }

@sunm2n

sunm2n commented May 22, 2026

Copy link
Copy Markdown
Contributor

전체적으로 모달 중복을 제외하면은 잘 짜여진 거 같습니다! 모달 중복만 확인하시고 머지해도 문제 없을 거 같습니다 수고하셨습니다!

Comment thread api/saved-links.ts Outdated
params.set('bookmarked', String(query.bookmarked));
}

if (query.cursor) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

다른 필드는 != null로 체크하면서 cursor만 falsy check를 사용합니다.
일관성을 위해 if (query.cursor != null)로 통일 하는 것이 어떨가 합니다.

  // 현재
  if (query.cursor) { ... }

  // 권장
  if (query.cursor != null) { ... }

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

반영했습니다!

categoryId, bookmarked, size와 일관되도록 cursor 조건도 query.cursor != null로 변경했습니다.

@kbh0218

kbh0218 commented May 22, 2026

Copy link
Copy Markdown
Contributor Author

제목 수정 모달 UI가 두 파일에 완전 중복

index.tsx와 saved-links.tsx에 동일한 Modal JSX, renameStyles, handleTitleCancel, handleTitleConfirm, openTitleModal, titleSubmitDisabled 로직이 똑같아 보입니다. 별도의 TitleEditModal 컴포넌트 또는 useTitleEdit 훅으로 추출하는 것을 제안드립니다.

  // components/ui/title-edit-modal.tsx 로 추출 권장
  interface TitleEditModalProps {
    editingLink: SavedLink | null;
    onConfirm: (id: number, title: string) => Promise<void>;
    onClose: () => void;
  }

반영했습니다!

중복되던 제목 수정 모달 UI와 상태/검증 로직을 components/ui/title-edit-modal.tsxTitleEditModal 컴포넌트로 추출했습니다. index.tsxsaved-links.tsx에서는 수정 대상 링크 상태와 저장 성공 토스트만 관리하도록 정리했습니다.

기존 동작인 입력 focus, 저장 중 닫기 방지, 빈 값/500자 초과/동일 제목 저장 비활성화, 실패 Alert 흐름은 유지했습니다.

@kbh0218 kbh0218 merged commit cd6418c into dev May 22, 2026
@kbh0218 kbh0218 deleted the feat/#45-saved-links-api branch May 22, 2026 15:32
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.

[FEATURE] 저장 링크 API 연동 및 제목 수정 기능 적용

2 participants