Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
120 changes: 106 additions & 14 deletions apps/web/src/generated/api/endpoints/voteboard/voteboard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,28 @@ import type {
import { customInstance } from '../../../../lib/api-client';

/**
* 투표 게시글의 상세 정보를 조회합니다. 비로그인 사용자도 조회 가능합니다.
* 투표 게시글의 상세 정보를 조회합니다.

**특징:**
- 조회 시 조회수 자동 증가
- 인증/비인증 사용자 모두 조회 가능
- 인증 여부에 따라 isLiked, canEdit, canDelete 값 변경
- 투표 참여 여부에 따라 selectedOptionIds 값 변경

**인증 사용자:**
- isAuthorized: true
- isLiked: boolean (좋아요 상태)
- canEdit: boolean (수정 권한 - 작성자인 경우 true)
- canDelete: boolean (삭제 권한 - 작성자인 경우 true)
- selectedOptionIds: 투표한 옵션 ID 목록 (투표 전이면 빈 배열)

**비인증 사용자:**
- isAuthorized: false
- isLiked: null
- canEdit: null
- canDelete: null
- selectedOptionIds: 빈 배열

* @summary 투표 게시글 상세 조회
*/
export const getVotePost = (
Expand Down Expand Up @@ -203,17 +224,62 @@ export function useGetVotePost<

/**
* 투표 게시글을 수정합니다. 투표 옵션은 수정할 수 없습니다.

**수정 가능 항목:**
- 카테고리
- 제목, 내용
- 이미지 (추가/삭제)
- 투표 설정 (투표 시작 전에만 가능)

**Multipart 업로드**

* @summary 투표 게시글 수정
*/
export const updateVotePost = (
votesboardId: number,
votePostUpdateRequest: VotePostUpdateRequest,
) => {
const formData = new FormData();
if (votePostUpdateRequest.category !== undefined) {
formData.append(`category`, votePostUpdateRequest.category);
}
if (votePostUpdateRequest.title !== undefined) {
formData.append(`title`, votePostUpdateRequest.title);
}
if (votePostUpdateRequest.content !== undefined) {
formData.append(`content`, votePostUpdateRequest.content);
}
if (votePostUpdateRequest.images !== undefined) {
votePostUpdateRequest.images.forEach((value) =>
formData.append(`images`, value),
);
}
if (votePostUpdateRequest.deleteImageIds !== undefined) {
votePostUpdateRequest.deleteImageIds.forEach((value) =>
formData.append(`deleteImageIds`, value.toString()),
);
}
if (votePostUpdateRequest.endTime !== undefined) {
formData.append(`endTime`, votePostUpdateRequest.endTime);
}
if (votePostUpdateRequest.allowRevote !== undefined) {
formData.append(
`allowRevote`,
votePostUpdateRequest.allowRevote.toString(),
);
}
if (votePostUpdateRequest.allowMultipleChoice !== undefined) {
formData.append(
`allowMultipleChoice`,
votePostUpdateRequest.allowMultipleChoice.toString(),
);
}

return customInstance<void>({
url: `/community/votesboard/${votesboardId}`,
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
data: votePostUpdateRequest,
headers: { 'Content-Type': 'multipart/form-data' },
data: formData,
});
};

Expand Down Expand Up @@ -832,32 +898,57 @@ export function useGetVotePostsByCursor<
/**
* 새로운 투표 게시글을 작성합니다.

**제약사항:**
- 투표 옵션: 최소 2개, 최대 5개
- 제목: 최대 100자
- 내용: 최대 5000자
- 이미지: 최대 5개
- 마감 시간: 현재 시간보다 미래여야 함
**특징:**
- 2-5개의 투표 옵션 필수
- 이미지 업로드 지원 (최대 4장)
- 투표 마감 시간 설정 필수
- 재투표 허용 여부 설정
- 중복 선택 허용 여부 설정
- Multipart 방식으로 이미지와 텍스트 데이터를 함께 전송
- 카테고리 필수 선택

**권한:** 로그인 사용자만 가능
**지원 파일 형식:** jpg, jpeg, png, gif, webp
**최대 파일 크기:** 5MB per image

* @summary 투표 게시글 작성
*/
export const createVotePost = (
votePostCreateRequest: VotePostCreateRequest,
signal?: AbortSignal,
) => {
const formData = new FormData();
formData.append(`category`, votePostCreateRequest.category);
formData.append(`title`, votePostCreateRequest.title);
formData.append(`content`, votePostCreateRequest.content);
votePostCreateRequest.voteOptions.forEach((value) =>
formData.append(`voteOptions`, JSON.stringify(value)),
);
formData.append(`endTime`, votePostCreateRequest.endTime);
formData.append(
`allowRevote`,
votePostCreateRequest.allowRevote.toString(),
);
formData.append(
`allowMultipleChoice`,
votePostCreateRequest.allowMultipleChoice.toString(),
);
if (votePostCreateRequest.images !== undefined) {
votePostCreateRequest.images.forEach((value) =>
formData.append(`images`, value),
);
}

return customInstance<VotePostIdResponse>({
url: `/community/votesboard`,
method: 'POST',
headers: { 'Content-Type': 'application/json' },
data: votePostCreateRequest,
headers: { 'Content-Type': 'multipart/form-data' },
data: formData,
signal,
});
};

export const getCreateVotePostMutationOptions = <
TError = ErrorResponse | ErrorResponse,
TError = ErrorResponse | ErrorResponse | ErrorResponse,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Expand Down Expand Up @@ -898,14 +989,15 @@ export type CreateVotePostMutationResult = NonNullable<
>;
export type CreateVotePostMutationBody = VotePostCreateRequest;
export type CreateVotePostMutationError =
| ErrorResponse
| ErrorResponse
| ErrorResponse;

/**
* @summary 투표 게시글 작성
*/
export const useCreateVotePost = <
TError = ErrorResponse | ErrorResponse,
TError = ErrorResponse | ErrorResponse | ErrorResponse,
TContext = unknown,
>(
options?: {
Expand Down
4 changes: 4 additions & 0 deletions apps/web/src/generated/api/models/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,13 +93,17 @@ export * from './userTypeRequestUserType';
export * from './voteOptionRequest';
export * from './voteOptionResponse';
export * from './votePostCreateRequest';
export * from './votePostCreateRequestCategory';
export * from './votePostDetailResponse';
export * from './votePostDetailResponseCategory';
export * from './votePostDetailResponseVoteStatus';
export * from './votePostIdResponse';
export * from './votePostListResponse';
export * from './votePostSummaryResponse';
export * from './votePostSummaryResponseCategory';
export * from './votePostSummaryResponseVoteStatus';
export * from './votePostUpdateRequest';
export * from './votePostUpdateRequestCategory';
export * from './voteRequest';
export * from './voteboardCommentCreateRequest';
export * from './voteboardCommentCreateResponse';
Expand Down
15 changes: 9 additions & 6 deletions apps/web/src/generated/api/models/votePostCreateRequest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,15 @@
* 소소한 아이디어 공유 플랫폼의 백엔드 API 문서입니다.
* OpenAPI spec version: v1.0.0
*/
import type { VotePostCreateRequestCategory } from './votePostCreateRequestCategory';
import type { VoteOptionRequest } from './voteOptionRequest';

/**
* 투표 게시글 생성 요청
*/
export interface VotePostCreateRequest {
/** 게시글 카테고리 */
category: VotePostCreateRequestCategory;
/**
* 게시글 제목
* @minLength 0
Expand All @@ -23,12 +26,6 @@ export interface VotePostCreateRequest {
* @maxLength 5000
*/
content: string;
/**
* 이미지 URL 목록 (최대 5개)
* @minItems 0
* @maxItems 5
*/
imageUrls?: string[];
/**
* 투표 옵션 목록 (2-5개)
* @minItems 2
Expand All @@ -41,4 +38,10 @@ export interface VotePostCreateRequest {
allowRevote: boolean;
/** 중복 선택 허용 여부 (true: 여러 옵션 동시 선택 가능, 최대 n-1개 / false: 하나의 옵션만 선택 가능) */
allowMultipleChoice: boolean;
/**
* 첨부 이미지 파일들 (최대 4장)
* @minItems 0
* @maxItems 4
*/
images?: Blob[];
}
23 changes: 23 additions & 0 deletions apps/web/src/generated/api/models/votePostCreateRequestCategory.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* Generated by orval v7.13.0 🍺
* Do not edit manually.
* SoSo API 명세서
* 소소한 아이디어 공유 플랫폼의 백엔드 API 문서입니다.
* OpenAPI spec version: v1.0.0
*/

/**
* 게시글 카테고리
*/
export type VotePostCreateRequestCategory =
(typeof VotePostCreateRequestCategory)[keyof typeof VotePostCreateRequestCategory];

// eslint-disable-next-line @typescript-eslint/no-redeclare
export const VotePostCreateRequestCategory = {
'daily-hobby': 'daily-hobby',
restaurant: 'restaurant',
'living-convenience': 'living-convenience',
'neighborhood-news': 'neighborhood-news',
startup: 'startup',
others: 'others',
} as const;
20 changes: 14 additions & 6 deletions apps/web/src/generated/api/models/votePostDetailResponse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
* OpenAPI spec version: v1.0.0
*/
import type { UserSummaryResponse } from './userSummaryResponse';
import type { VotePostDetailResponseCategory } from './votePostDetailResponseCategory';
import type { ImageInfo } from './imageInfo';
import type { VoteOptionResponse } from './voteOptionResponse';
import type { VotePostDetailResponseVoteStatus } from './votePostDetailResponseVoteStatus';

Expand All @@ -15,14 +17,16 @@ import type { VotePostDetailResponseVoteStatus } from './votePostDetailResponseV
export interface VotePostDetailResponse {
/** 게시글 ID */
id: number;
/** 작성자 정보 */
author: UserSummaryResponse;
/** 카테고리 */
category: VotePostDetailResponseCategory;
/** 게시글 제목 */
title: string;
/** 게시글 내용 */
content: string;
/** 작성자 정보 */
author: UserSummaryResponse;
/** 이미지 URL 목록 */
imageUrls?: string[];
/** 첨부된 이미지 정보 목록 */
images: ImageInfo[];
/** 투표 옵션 목록 */
voteOptions: VoteOptionResponse[];
/** 현재 사용자가 선택한 옵션 ID 목록 (미투표 시 빈 리스트) */
Expand All @@ -43,11 +47,15 @@ export interface VotePostDetailResponse {
commentCount: number;
/** 좋아요 수 */
likeCount: number;
/** 현재 사용자가 게시글 수정 권한이 있는지 여부 (비인증 사용자인 경우 null, 작성자인 경우 true) */
canEdit: boolean;
/** 현재 사용자가 게시글 삭제 권한이 있는지 여부 (비인증 사용자인 경우 null, 작성자인 경우 true) */
canDelete: boolean;
/** 생성일시 */
createdDate: string;
/** 수정일시 */
lastModifiedDate: string;
liked?: boolean;
/** 현재 사용자의 좋아요 여부 (비로그인 시 false) */
authorized?: boolean;
/** 현재 사용자의 좋아요 여부 (비인증 사용자인 경우 null) */
isLiked: boolean;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* Generated by orval v7.13.0 🍺
* Do not edit manually.
* SoSo API 명세서
* 소소한 아이디어 공유 플랫폼의 백엔드 API 문서입니다.
* OpenAPI spec version: v1.0.0
*/

/**
* 카테고리
*/
export type VotePostDetailResponseCategory =
(typeof VotePostDetailResponseCategory)[keyof typeof VotePostDetailResponseCategory];

// eslint-disable-next-line @typescript-eslint/no-redeclare
export const VotePostDetailResponseCategory = {
'daily-hobby': 'daily-hobby',
restaurant: 'restaurant',
'living-convenience': 'living-convenience',
'neighborhood-news': 'neighborhood-news',
startup: 'startup',
others: 'others',
} as const;
11 changes: 9 additions & 2 deletions apps/web/src/generated/api/models/votePostSummaryResponse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
* OpenAPI spec version: v1.0.0
*/
import type { UserSummaryResponse } from './userSummaryResponse';
import type { VotePostSummaryResponseCategory } from './votePostSummaryResponseCategory';
import type { VotePostSummaryResponseVoteStatus } from './votePostSummaryResponseVoteStatus';
import type { VoteOptionResponse } from './voteOptionResponse';

Expand All @@ -15,10 +16,16 @@ import type { VoteOptionResponse } from './voteOptionResponse';
export interface VotePostSummaryResponse {
/** 게시글 ID */
id: number;
/** 게시글 제목 */
title: string;
/** 작성자 정보 */
author: UserSummaryResponse;
/** 카테고리 */
category: VotePostSummaryResponseCategory;
/** 게시글 제목 */
title: string;
/** 첫 번째 이미지 URL (썸네일용) */
thumbnailUrl?: string;
/** 이미지 개수 */
imageCount: number;
/** 조회수 */
viewCount: number;
/** 댓글 수 */
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* Generated by orval v7.13.0 🍺
* Do not edit manually.
* SoSo API 명세서
* 소소한 아이디어 공유 플랫폼의 백엔드 API 문서입니다.
* OpenAPI spec version: v1.0.0
*/

/**
* 카테고리
*/
export type VotePostSummaryResponseCategory =
(typeof VotePostSummaryResponseCategory)[keyof typeof VotePostSummaryResponseCategory];

// eslint-disable-next-line @typescript-eslint/no-redeclare
export const VotePostSummaryResponseCategory = {
'daily-hobby': 'daily-hobby',
restaurant: 'restaurant',
'living-convenience': 'living-convenience',
'neighborhood-news': 'neighborhood-news',
startup: 'startup',
others: 'others',
} as const;
Loading