Skip to content
Merged
Show file tree
Hide file tree
Changes from 41 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
43df442
fix: 리액션 API를 백엔드 명세에 맞게 마이그레이션 (#122)
AndyH0ng Feb 6, 2026
18e24e9
refactor: deprecated Slide 타입을 SlideListItem으로 마이그레이션 (#122)
AndyH0ng Feb 6, 2026
cc6b96c
fix: MSW 단일 슬라이드 조회에 prevSlideId/nextSlideId 추가 (#122)
AndyH0ng Feb 6, 2026
3e8ca27
fix: analytics 목 데이터에서 slide.id → slide.slideId 수정 (#122)
AndyH0ng Feb 6, 2026
b13c8ce
chore: MSW 백엔드 코드 반영 (#122)
AndyH0ng Feb 6, 2026
6ad4d73
refactor: useOpinions 마이그레이션 (#122)
AndyH0ng Feb 6, 2026
fb84674
chore: 목데이터 UUID 매칭 못해도 댓글 삭제하도록 수정 (#122)
AndyH0ng Feb 6, 2026
8c801f7
refactor: 미사용 훅 제거 및 내부 전용 export 정리 (#122)
AndyH0ng Feb 6, 2026
7f627a3
refactor: 3계층 아키텍처 위반 수정 (#122)
AndyH0ng Feb 6, 2026
7319629
feat: TextField 공용 컴포넌트 구현 (#122)
AndyH0ng Feb 6, 2026
0dc834f
feat: 제목 수정 팝오버 공용 컴포넌트 구현 (#122)
AndyH0ng Feb 6, 2026
97cda1f
design: 볼륨 인디케이터 Figma에 맞게 구현 (#122)
AndyH0ng Feb 6, 2026
612449e
design: 하드웨어 테스트 페이지 레이아웃 리디자인 (#122)
AndyH0ng Feb 6, 2026
9108a19
design: 하드웨어 테스트 페이지 헤더 리디자인 (#122)
AndyH0ng Feb 6, 2026
69db36c
design: 영상 녹화 시 로고 누를 때 종료 모달 뜨도록 설정 (#122)
AndyH0ng Feb 6, 2026
279dfc4
design: 많은 피드백을 받은 슬라이드 카드 최소 높이 설정 (#122)
AndyH0ng Feb 6, 2026
4dbda22
feat: 토스트 유틸 클래스 교체 (#122)
AndyH0ng Feb 7, 2026
dd0770e
chore: 녹화 중단 모달 텍스트 수정 (#122)
AndyH0ng Feb 7, 2026
a51ab90
docs: 주석 제거 (#122)
AndyH0ng Feb 7, 2026
7038258
design: 표시되는 스켈레톤 수 조절 (#122)
AndyH0ng Feb 7, 2026
07161b7
design: 피드백 모바일 화면 리액션 버튼 리디자인 (#122)
AndyH0ng Feb 7, 2026
47356d7
design: 피드백 모바일 화면 리액션 버튼 리디자인 (#122)
AndyH0ng Feb 7, 2026
2964431
refactor: readOnly → readOnlyContent로 교체 (#122)
AndyH0ng Feb 7, 2026
c640b68
design: selected 시 페이드 효과 (#122)
AndyH0ng Feb 7, 2026
f63b853
refactor: 제목 편집 컴포넌트 readOnly 시 불필요한 훅 제거 (#122)
AndyH0ng Feb 7, 2026
65013c1
Merge branch 'develop' into refactor/type-migration-122
AndyH0ng Feb 7, 2026
cb8c527
fix: 빌드 오류 해결 (#122)
AndyH0ng Feb 7, 2026
2e17601
docs: 주석 추가 (#122)
AndyH0ng Feb 7, 2026
f888450
Merge branch 'develop' into refactor/type-migration-122
AndyH0ng Feb 7, 2026
5e6dfb0
chore: 빌드 오류 해결 (#122)
AndyH0ng Feb 7, 2026
936a1c2
refactor: 코드 리뷰 반영 (#122)
AndyH0ng Feb 7, 2026
6dfeb13
refactor: emojiType 레코드로 저장 (#122)
AndyH0ng Feb 7, 2026
41b288c
refactor: type → emojiType로 변경 (#122)
AndyH0ng Feb 7, 2026
385de42
feat: timestampMs로 마이그레이션 (#122)
AndyH0ng Feb 7, 2026
3bb9f05
fix: 빌드 오류 해결 (#122)
AndyH0ng Feb 7, 2026
f1f06f7
fix: reaction/summary 엔드포인트 백엔드랑 맞춤 (#122)
AndyH0ng Feb 7, 2026
fc6e905
fix: 엔드포인트 백엔드랑 맞춤 (#122)
AndyH0ng Feb 7, 2026
1e0f80c
chore: 불필요한 엔드포인트 제거 (#122)
AndyH0ng Feb 7, 2026
1948c75
chore: 불필요한 엔드포인트 제거 (#122)
AndyH0ng Feb 7, 2026
24224b1
feat: 댓글 수정 구현 (#122)
AndyH0ng Feb 7, 2026
a42d336
feat: 댓글 API 연결 (#122)
AndyH0ng Feb 7, 2026
32e1255
feat: 컨테이너에서 댓글 호출 (#122)
AndyH0ng Feb 7, 2026
ad228d7
fix: 안쓰는 import 제거 (#122)
AndyH0ng Feb 7, 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
8 changes: 4 additions & 4 deletions src/api/dto/comments.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,15 @@ export interface CreateCommentResponseDto {
* 댓글 작성자 정보
*/
export interface CommentUserDto {
id: string;
userId: string;
nickName: string;
}

/**
* 사용자 정보 포함 댓글
*/
export interface CommentWithUserDto {
id: string;
commentId: string;
content: string;
user: CommentUserDto;
createdAt: string;
Expand All @@ -79,7 +79,7 @@ export interface GetSlideCommentsResponseDto {
* 댓글 생성/수정 응답
*/
export interface CommentResponseDto {
id: string;
commentId: string;
content: string;
parentId?: string;
userId: string;
Expand All @@ -94,7 +94,7 @@ export type GetReplyListResponseDto = CommentResponseDto[];
* 댓글 수정
*/
export interface UpdateCommentResponseDto {
id: string;
commentId: string;
content: string;
userId: string;
createdAt: string;
Expand Down
10 changes: 8 additions & 2 deletions src/api/dto/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,19 @@ export type {
GetScriptVersionHistoryResponseDto,
RestoreScriptResponseDto,
} from './scripts.dto';
export type { ToggleSlideReactionDto } from './reactions.dto';
export type {
ReadReactionCountDto,
ToggleSlideReactionDto,
ToggleSlideReactionResponseDto,
ToggleVideoReactionDto,
ToggleVideoReactionResponseDto,
} from './reactions.dto';
export type { RestoreScriptRequestDto } from './analytics.dto';
export type { UpdateProjectDto } from './presentations.dto';
// export type { UploadFileResponseDto } from './files.dto';
export type {
ChunkUploadResponseDto,
CreateOpinionDto,
CreateCommentDto,
FinishVideoRequestDto,
FinishVideoResponseDto,
StartVideoRequestDto,
Expand Down
40 changes: 25 additions & 15 deletions src/api/dto/reactions.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,44 @@ import type { ReactionType } from '@/types/script';
* 슬라이드 리액션 토글 요청 DTO
*/
export interface ToggleSlideReactionDto {
type: ReactionType;
emojiType: ReactionType;
}

/**
* 슬라이드 리액션 토글 응답 DTO
*/
export interface ToggleSlideReactionResponseDto {
active: boolean;
}

/**
* 영상 리액션 토글 요청 DTO
*/
export interface ToggleVideoReactionDto {
emojiType: ReactionType;
timestampMs: number;
}

/**
* 영상 리액션 토글 응답 DTO
*/
export interface ToggleVideoReactionResponseDto {
active: boolean;
}

/**
* 특정 슬라이드에 달린 모든 이모지 리액션을 집계하여 반환 Dto
*/
export interface ReadReactionCountDto {
slideId: string;
reactions: {
fire: number;
good: number;
bad: number;
sleepy: number;
confused: number;
};
reactions: Record<ReactionType, number>;
}

/**
* 프로젝트 전체 슬라이드 리액션 집계 조회 Dto
*/
export interface ReadReactionSummaryDto {
projectId: string;
totalReactions: {
fire: number;
good: number;
bad: number;
sleepy: number;
confused: number;
};
totalReactions: Record<ReactionType, number>;
totalCount: number;
}
4 changes: 2 additions & 2 deletions src/api/dto/video.dto.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
/**
* 영상 타임스탬프 댓글 생성
*/
export interface CreateOpinionDto {
export interface CreateCommentDto {
content: string;
/** 답글인 경우 부모 의견 내용 고쳐라이D */
/** 답글인 경우 부모 댓글 ID */
parentId?: string;
}

Expand Down
2 changes: 1 addition & 1 deletion src/api/endpoints/analytics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* @file analytics.ts
* @description 인사이트 페이지 관련 API 엔드포인트
*/
import { apiClient } from '@/api';
import { apiClient } from '@/api/client';
import type {
ReadProjectAnalyticsSummaryDto,
ReadRecentCommentListResponseDto,
Expand Down
2 changes: 1 addition & 1 deletion src/api/endpoints/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* @file auth.ts
* @description 인증 관련 API 엔드포인트
*/
import { apiClient } from '@/api';
import { apiClient } from '@/api/client';
import type { SocialLoginSuccessResponseDto } from '@/api/dto';
import type { ApiResponse } from '@/types/api';

Expand Down
2 changes: 1 addition & 1 deletion src/api/endpoints/comments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* @file comments.ts
* @description 댓글 관련 API 엔드포인트
*/
import { apiClient } from '@/api';
import { apiClient } from '@/api/client';
import type {
CommentResponseDto,
GetReplyListResponseDto,
Expand Down
26 changes: 2 additions & 24 deletions src/api/endpoints/presentations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,10 @@
* 서버와 통신하는 함수들을 정의합니다.
* 이 함수들은 직접 호출하지 않고, hooks/queries에서 사용합니다.
*/
import { apiClient } from '@/api';
import { apiClient } from '@/api/client';
import type { UpdateProjectDto } from '@/api/dto';
import type { ApiResponse, ConversionStatusResponse } from '@/types/api';
import type {
CreatePresentationRequest,
CreatePresentationSuccess,
Presentation,
PresentationListResponse,
ProjectUpdateResponse,
Expand Down Expand Up @@ -67,26 +65,6 @@ export async function updatePresentation(
throw new Error(response.data.error.reason);
}

/**
* 프로젝트 생성 (POST)
*
* @param data - 생성할 프로젝트 데이터
* @returns CreatePresentationSuccess - 생성된 프로젝트 정보
*/
export async function createPresentation(
data: CreatePresentationRequest,
): Promise<CreatePresentationSuccess> {
const response = await apiClient.post<ApiResponse<CreatePresentationSuccess>>(
`/presentations`,
data,
);

if (response.data.resultType === 'SUCCESS') {
return response.data.success;
}
throw new Error(response.data.error.reason);
}

/**
* 프로젝트 삭제 (DELETE)
*
Expand All @@ -108,7 +86,7 @@ export async function deletePresentation(projectId: string): Promise<void> {
*/
export async function getConversionStatus(projectId: string): Promise<ConversionStatusResponse> {
const response = await apiClient.get<ApiResponse<ConversionStatusResponse>>(
`/presentations/${projectId}/conversion-status`,
`/presentations/${projectId}/status`,
);

if (response.data.resultType === 'SUCCESS') {
Expand Down
57 changes: 37 additions & 20 deletions src/api/endpoints/reactions.ts
Original file line number Diff line number Diff line change
@@ -1,51 +1,68 @@
/**
* @file reactions.ts * @description Slide reaction APIs.
/**
* @file reactions.ts
* @description 슬라이드 리액션 관련 API 엔드포인트
*/
import { apiClient } from '@/api';
import { apiClient } from '@/api/client';
import type { ToggleSlideReactionDto } from '@/api/dto';
import type { ReadReactionCountDto, ReadReactionSummaryDto } from '@/api/dto/reactions.dto';
import type { ApiResponse } from '@/api/handlers';
import type { Reaction } from '@/types/script';
import type {
ReadReactionCountDto,
ReadReactionSummaryDto,
ToggleSlideReactionResponseDto,
} from '@/api/dto/reactions.dto';
import type { ApiResponse } from '@/types/api';

/**
* Toggle a reaction for a slide.
* 슬라이드 리액션 토글
*
* @param slideId - 슬라이드 ID
* @param data - 리액션 데이터
* @returns 업데이트된 리액션 배열
* @returns { active: boolean } - 토글 후 활성 상태
*/
export async function toggleReaction(
slideId: string,
data: ToggleSlideReactionDto,
): Promise<Reaction[]> {
const { data: response } = await apiClient.post<ApiResponse<Reaction[]>>(
): Promise<ToggleSlideReactionResponseDto> {
const { data: response } = await apiClient.post<ApiResponse<ToggleSlideReactionResponseDto>>(
`/slides/${slideId}/reactions/toggle`,
data,
);
return response.success;

if (response.resultType === 'SUCCESS') {
return response.success;
}
throw new Error(response.error.reason);
}

/**
* Get reaction summary counts for a slide.
* 슬라이드 리액션 집계 조회
*
* @param slideId - 슬라이드 ID
* @returns Record<ReactionType, number> - 이모지별 카운트
*/
export async function getSlideReactionSummary(slideId: string) {
const { data } = await apiClient.get<ApiResponse<ReadReactionCountDto>>(
`/slides/${slideId}/reactions/summary`,
);

// ⚠️ 핵심: success 안에 있는 reactions 객체만 리턴! (없으면 빈 객체)
return data.success?.reactions ?? {};
if (data.resultType === 'SUCCESS') {
return data.success.reactions;
}
throw new Error(data.error.reason);
}

// 슬라이드 이모지 피드백 분포 - 인사이트 페이지
/**
* 프로젝트 전체 슬라이드 리액션 집계 조회
*
* @param projectId - 프로젝트 ID
* @returns ReactionSummaryDto - 이모지별 총 카운트
*/
export async function getTotalReactions(projectId: string): Promise<ReadReactionSummaryDto> {
const response = await apiClient.get<ApiResponse<ReadReactionSummaryDto>>(
const { data } = await apiClient.get<ApiResponse<ReadReactionSummaryDto>>(
`/presentations/${projectId}/slides/reactions/summary`,
);
// 데이터가 없으면 에러 발생 (null 반환 방지)
if (!response.data.success) {
throw new Error('슬라이드 이모지 피드백 분포를 불러올 수 없습니다.');

if (data.resultType === 'SUCCESS') {
return data.success;
}
return response.data.success;
throw new Error(data.error.reason);
}
2 changes: 1 addition & 1 deletion src/api/endpoints/scripts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* @file scripts.ts
* @description 대본 관련 API 엔드포인트
*/
import { apiClient } from '@/api';
import { apiClient } from '@/api/client';
import type {
GetScriptResponseDto,
GetScriptVersionHistoryResponseDto,
Expand Down
37 changes: 1 addition & 36 deletions src/api/endpoints/slides.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* 서버와 통신하는 함수들을 정의합니다.
* 이 함수들은 직접 호출하지 않고, hooks/queries에서 사용합니다.
*/
import { apiClient } from '@/api';
import { apiClient } from '@/api/client';
import type {
GetSlideResponseDto,
UpdateSlideResponseDto,
Expand Down Expand Up @@ -72,38 +72,3 @@ export async function updateSlide(
}
throw new Error(response.data.error.reason);
}

/**
* 슬라이드 생성
*
* @param projectId - 프로젝트 ID
* @param data - 생성할 슬라이드 데이터
* @returns 생성된 슬라이드
*/
export async function createSlide(
projectId: string,
data: { title: string; script?: string },
): Promise<GetSlideResponseDto> {
const response = await apiClient.post<ApiResponse<GetSlideResponseDto>>(
`/presentations/${projectId}/slides`,
data,
);

if (response.data.resultType === 'SUCCESS') {
return response.data.success;
}
throw new Error(response.data.error.reason);
}

/**
* 슬라이드 삭제
*
* @param slideId - 삭제할 슬라이드 ID
*/
export async function deleteSlide(slideId: string): Promise<void> {
const response = await apiClient.delete<ApiResponse<null>>(`/presentations/slides/${slideId}`);

if (response.data.resultType === 'FAILURE') {
throw new Error(response.data.error.reason);
}
}
Loading
Loading