Skip to content
Merged
Show file tree
Hide file tree
Changes from 60 commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
f8f0a63
feat(member): 문의 페이지 UI 스타일 개발(#274)
seoJing May 27, 2025
570ffdd
feat(member): 문의 페이지 UI 스타일 개발(#274)
seoJing May 27, 2025
6472867
feat(member): 문의 페이지 UI 스타일 개발(#274)
seoJing May 27, 2025
33560df
docs(member): 불필요한 주석 제거
seoJing May 29, 2025
44355b8
refactor(member): head.ts로 Table.Header 상수 관리 추가(#274)
seoJing May 29, 2025
2ae1e28
refactor(member): self-closing 가능한 태그 정리(#274)
seoJing May 29, 2025
1ef6021
refactor: 불필요한 태그 삭제(#274)
seoJing May 29, 2025
23daf66
refactor: 불필요한 상수 삭제(#274)
seoJing May 29, 2025
9c44924
refactor: 불필요한 export 삭제(#274)
seoJing May 29, 2025
10af027
refactor: 문의 한글 맵핑 적용 및 상수 관리(#274)
seoJing May 29, 2025
ccc1f03
refactor: static 값들을 mock/data로 이동(#274)
seoJing May 29, 2025
728074a
refactor: 반복되는 데이터 구조분해 적용(#274)
seoJing May 29, 2025
9dc12ef
refactor(member): 불필요한 중복 코드 제거(#274)
seoJing Jun 1, 2025
00be60e
style(member): 문의 리스트 테이블 스타일 변경(#274)
seoJing Jun 1, 2025
5d40ff1
refactor(member): 매직 넘버 제거(#274)
seoJing Jun 1, 2025
6abd535
refactor(member): 반복되는 데이터 구조분해 적용(#274)
seoJing Jun 1, 2025
4248c71
docs(member): 문의 유의사항 문구 변경(#274)
seoJing Jun 1, 2025
77af395
refactor(member): static 값들을 mock/data로 이동(#274)
seoJing Jun 1, 2025
38f0ada
refactor(member): 중첩 삼항연산자 제거(#274)
seoJing Jun 1, 2025
c67ce82
refactor(member): faq 카테고리 변경(#274)
seoJing Jun 1, 2025
060ccfb
docs(member): 오탈자 수정(#274)
seoJing Jun 1, 2025
879fddb
docs(member): 오탈자 수정(#274)
seoJing Jun 1, 2025
74e53f9
docs(member): 오탈자 수정
seoJing Jun 17, 2025
b919fc7
refactor(member): support 페이지를 membershipFee로 리네이밍
seoJing Jun 18, 2025
aba1718
refactor(member): support 페이지를 membershipFee로 리네이밍
seoJing Jun 18, 2025
19a8e96
refactor(member): imquiry 페이지를 support로 리네이밍
seoJing Jun 18, 2025
14d1b69
refactor(member): support 페이지를 membershipFee로 리네이밍
seoJing Jun 18, 2025
ed6da58
refactor(member): imquiry 페이지를 support로 리네이밍
seoJing Jun 18, 2025
1633d12
refactor(member): inquiry 페이지를 support로 리네이밍
seoJing Jun 18, 2025
401729b
refactor(member): 도서관 페이지에서 버튼 클릭 시 경로를 membershipFee로 변경
seoJing Jul 6, 2025
662d907
refactor(member): '나의 문의' 세션 위치 변경 (문의 목록 > 마이페이지)
seoJing Jul 6, 2025
2cd1c80
refactor(member): 테이블 가로 스크롤 지원
seoJing Jul 6, 2025
3f592e5
refactor(member): 레이아웃 개선 및 버튼 정렬 수정
seoJing Jul 6, 2025
27fd4fc
docs(member): faq 문구 변경
seoJing Jul 6, 2025
3f60ad2
docs(member): 문의 안내 문구 변경
seoJing Jul 6, 2025
8e0dc66
refactor(member): 오류 이미지 업로더 항상 표시하도록 수정
seoJing Jul 6, 2025
b59d589
refactor(member): 문의 작성 페이지에 문의 네비게이션 추가
seoJing Jul 6, 2025
fc9c512
feat(member): support 페이지 mock 데이터를 API 연동으로 교체
seoJing Aug 2, 2025
cc1f12d
refactor(member): supportTableRow를 컴포넌트 및 훅으로 분리
seoJing Aug 2, 2025
ab4a315
chore(member): support 테이블 헤더 '카테고리 / 상태'를 '상태'로 수정
seoJing Aug 2, 2025
376aee6
chore(member): support 옵션 상수에서 'INQURIY' 오탈자를 'INQUIRY'로 수정
seoJing Aug 2, 2025
669a7ee
feat(member): 답변 상태 및 제목/내용 길이 제한 상수 정의
seoJing Aug 2, 2025
fc92174
refactor(member): support 타입 중복 개선 및 통합
seoJing Aug 2, 2025
36b384f
refactor(member): getSupports 네이밍을 getSupportList로 변경
seoJing Aug 9, 2025
0b5a9fb
refactor(member): 엔드포인트 UPLOADEDFILE_SUPPORT '/' 제거
seoJing Aug 9, 2025
0aa9ed8
refactor(member): support 타입 불필요한 옵셔널 정리
seoJing Aug 9, 2025
1121487
refactor(member): 에러 메시지 DEFAULT로 변경
seoJing Aug 9, 2025
58a6578
refactor(member): 불필요한 useMemo 제거
seoJing Aug 9, 2025
bcf7871
refactor(member): 불필요한 useCallback 제거 및 최적화
seoJing Aug 9, 2025
78d52cc
refactor(member): useSupportWriteMutation 무효화 최적화
seoJing Aug 9, 2025
dc3c46a
refactor(member): 쿼리스트링 함수 정의 및 HistorySection 경로 상수화
seoJing Aug 9, 2025
0db4c49
refactor(member): import type 적용
seoJing Aug 9, 2025
6f1c304
docs(member): support 문구 변경
seoJing Aug 9, 2025
086b46e
refactor(member): 시멘틱 태그 처리
seoJing Aug 9, 2025
4d96475
refactor(member): early return 적용 및 최적화
seoJing Aug 9, 2025
35f801a
refactor(member): 불필요한 주석 제거
seoJing Aug 9, 2025
2b9c6dd
Revert "refactor(member): support 타입 불필요한 옵셔널 정리"
seoJing Aug 9, 2025
f7279d6
refactor(member): support 타입 불필요한 옵셔널 정리
seoJing Aug 9, 2025
25a641c
refactor(member): support state 상수 관리
seoJing Aug 9, 2025
fd1b573
refactor(member): useSupportListQuery, useSupportListUi 제거 및 최적화
seoJing Aug 9, 2025
1004005
refactor(member): createURLWithQueryString 제거 및 createPagination으로 교체
seoJing Aug 10, 2025
08b6309
refactor(member): supportListSection 의존성 및 안정성 개선
seoJing Aug 10, 2025
1153b58
refactor(member): 답변 시간이 맞지 않았던 버그 수정
seoJing Sep 15, 2025
cfa90af
refactor(member): 문의 수정 시에 익명 여부를 선택할 수 있었던 문제 수정
seoJing Sep 15, 2025
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
1 change: 1 addition & 0 deletions apps/member/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
"eslint-plugin-react-refresh": "^0.4.5",
"postcss": "^8.4.33",
"prettier": "^3.1.1",
"prettier-plugin-tailwindcss": "^0.5.13",
"tailwindcss": "^3.4.1",
"typescript": "^5.2.2",
"vite": "^5.0.8"
Expand Down
135 changes: 135 additions & 0 deletions apps/member/src/api/support.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import { createPagination } from '@clab-platforms/utils';

import { END_POINT } from '@constants/api';

import type {
BaseResponse,
ResponsePagination,
WithPaginationParams,
} from '@type/api';
import type {
Support,
SupportAnswerRequest,
SupportDetail,
SupportWriteRequest,
} from '@type/support';

import { server } from './server';
import {
postFilesSupportImages,
postUploadedFileBoard,
uploadFiles,
} from './uploadedFile';

export interface PostSupportsWriteParams extends SupportWriteRequest {
file?: File;
}
export interface PatchSupportsParams extends SupportWriteRequest {
id: number;
file?: File;
}
export interface PostAnswersParams extends SupportAnswerRequest {
id: number;
}
export interface PatchAnswersParams extends SupportAnswerRequest {
id: number;
}

/**
* 내가 작성한 문의 조회
*/
export async function getMySupports({ page, size }: WithPaginationParams) {
const { data } = await server.get<ResponsePagination<Support>>({
url: createPagination(END_POINT.MY_SUPPORTS, { page, size }),
});

return data;
}

/**
* 문의 목록 조회
*/
export async function getSupportList({ page, size }: WithPaginationParams) {
const { data } = await server.get<ResponsePagination<Support>>({
url: createPagination(END_POINT.SUPPORTS, { page, size }),
});
return data;
}

/**
* 문의 작성
*/
export async function postSupportsWrite(data: PostSupportsWriteParams) {
if (data.file) {
const files = await uploadFiles([data.file], postUploadedFileBoard);
if (!files?.[0]?.fileUrl) {
throw new Error('파일 업로드에 실패했습니다.');
}
data.imageUrl = files[0].fileUrl;
}

return server.post<SupportWriteRequest, BaseResponse<number>>({
url: END_POINT.SUPPORTS,
body: data,
});
}

/**
* 문의 상세 조회
*/
export function getSupportsDetail(id: number) {
return server.get<BaseResponse<SupportDetail>>({
url: END_POINT.SUPPORTS_ITEM(id),
});
}

/**
* 문의 수정
*/
export async function patchSupports({
id,
file,
...data
}: PatchSupportsParams) {
if (file) {
const uploadedFile = await uploadFiles([file], postFilesSupportImages);
if (!uploadedFile?.[0]?.fileUrl) {
throw new Error('파일 업로드에 실패했습니다.');
}
data.imageUrl = uploadedFile[0].fileUrl;
}

return server.patch<SupportWriteRequest, BaseResponse<number>>({
url: END_POINT.SUPPORTS_ITEM(id),
body: data,
});
}

/**
* 문의 삭제
*/
export function deleteSupports(id: number) {
return server.del<never, BaseResponse<number>>({
url: END_POINT.SUPPORTS_ITEM(id),
});
}

/**
* 답변 작성
*/
export async function postAnswersWrite({ id, ...data }: PostAnswersParams) {
return server.post<SupportAnswerRequest, BaseResponse<number>>({
url: END_POINT.ANSWERS_ITEM(id),
body: data,
});
}

/**
* 답변 수정
*/
export async function patchAnswers({ id, ...data }: PatchAnswersParams) {
return server.patch<SupportAnswerRequest, BaseResponse<number>>({
url: END_POINT.ANSWERS_ITEM(id),
body: data,
});
}
12 changes: 12 additions & 0 deletions apps/member/src/api/uploadedFile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,3 +154,15 @@ export async function postUploadedFileSubmit({

return data;
}

/**
* 문의 이미지 업로드
*/
export async function postFilesSupportImages(multipartFile: FormData) {
const { data } = await server.post<FormData, BaseResponse<ResponseFile[]>>({
url: createURL(END_POINT.UPLOADEDFILE_SUPPORT, STORAGE_PERIOD(5)), // 문의 이미지는 5년간 보관
body: multipartFile,
});

return data;
}
8 changes: 7 additions & 1 deletion apps/member/src/components/common/Nav/Nav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,17 @@ const Nav = () => {
>
도서관
</Menubar.Item>
<Menubar.Item
selected={pathName.startsWith(PATH.MEMBERSHIP_FEE)}
onClick={() => handleMenubarItemClick(PATH.MEMBERSHIP_FEE)}
>
회비
</Menubar.Item>
<Menubar.Item
selected={pathName.startsWith(PATH.SUPPORT)}
onClick={() => handleMenubarItemClick(PATH.SUPPORT)}
>
회비
문의
</Menubar.Item>
{data.roleLevel! >= ROLE_LEVEL.ADMIN && (
<>
Expand Down
8 changes: 7 additions & 1 deletion apps/member/src/components/common/Sidebar/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,17 @@ const Sidebar = () => {
>
도서관
</Menubar.Item>
<Menubar.Item
selected={pathName.startsWith(PATH.MEMBERSHIP_FEE)}
onClick={() => handleMenubarItemClick(PATH.MEMBERSHIP_FEE)}
>
회비
</Menubar.Item>
<Menubar.Item
selected={pathName.startsWith(PATH.SUPPORT)}
onClick={() => handleMenubarItemClick(PATH.SUPPORT)}
>
회비
문의
</Menubar.Item>
{data.roleLevel! >= ROLE_LEVEL.ADMIN && (
<>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Table } from '@clab-platforms/design-system';
import ActionButton from '@components/common/ActionButton/ActionButton';
import Pagination from '@components/common/Pagination/Pagination';
import Section from '@components/common/Section/Section';
import MembershipStatusBadge from '@components/membership/MembershipStatusBadge/MembershipStatusBadge';
import MembershipStatusBadge from '@components/membership/membershipStatusBadge/MembershipStatusBadge';

import { ROLE_LEVEL } from '@constants/state';
import { usePagination } from '@hooks/common/usePagination';
Expand All @@ -23,7 +23,7 @@ interface Props {
hasPermission?: boolean;
}

export function SupportHistorySection({
export function MembershipFeeHistorySection({
title,
size: defaultSize,
withPagination,
Expand Down Expand Up @@ -98,7 +98,7 @@ export function SupportHistorySection({
);
}

export function SupportHistorySectionSkeleton() {
export function MembershipFeeHistorySectionSkeleton() {
return (
<Section className="h-96 animate-pulse">
<Section.Header title={TITLE} />
Expand Down
6 changes: 6 additions & 0 deletions apps/member/src/constants/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ export const END_POINT = {
`/v1/files/notices/${groupId}`,
UPLOADEDFILE_ACTIVITY_ASSIGNMENT: (groupId: number) =>
`/v1/files/assignments/${groupId}`,
UPLOADEDFILE_SUPPORT: '/v1/files/supports',
// -- 활동그룹 멤버
ACTIVITY_GROUP_MEMBER: (id: number) => `/v1/activity-group/member/${id}`,
ACTIVITY_GROUP_MEMBER_MY: `/v1/activity-group/member/my`,
Expand Down Expand Up @@ -114,6 +115,11 @@ export const END_POINT = {
RECRUITMENT: `/v1/recruitments`,
// -- 해시태그
HASHTAG: `/v1/hashtags`,
// -- 문의
SUPPORTS: `/v1/supports`,
SUPPORTS_ITEM: (supportId: number) => `/v1/supports/${supportId}`,
MY_SUPPORTS: `/v1/supports/my-supports`,
ANSWERS_ITEM: (supportId: number) => `/v1/supports/${supportId}/answer`,
} as const;

/**
Expand Down
1 change: 1 addition & 0 deletions apps/member/src/constants/head.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export const TABLE_HEAD = {
'생성',
] as const,
MEMBER_MANAGE_TABLE: ['번호', '학번', '이름', '상태'],
SUPPORT_TABLE: ['번호', '제목', '문의자', '문의일', '상태'],
} as const;
/**
* 관리자 페이지에서 기능을 나타내는 상수
Expand Down
15 changes: 15 additions & 0 deletions apps/member/src/constants/key.ts
Original file line number Diff line number Diff line change
Expand Up @@ -302,3 +302,18 @@ export const RECRUITMENT_QUERY_KEY = {
ALL: ['Application'],
LIST: () => [...APPLICATION_QUERY_KEY.ALL, 'list'],
} as const;

/**
* 문의 관련 쿼리 키
*/
export const SUPPORT_QUERY_KEY = {
ALL: ['Support'],
MY: () => [...SUPPORT_QUERY_KEY.ALL, 'my'],
DETAILS: () => [...SUPPORT_QUERY_KEY.ALL, 'details'],
COLLECTIONS: () => [...SUPPORT_QUERY_KEY.ALL, 'collections'],
DETAIL: (id: number) => [...SUPPORT_QUERY_KEY.DETAILS(), id],
COLLECTION: (pagination: WithPaginationParams) => [
...SUPPORT_QUERY_KEY.COLLECTIONS(),
pagination,
],
} as const;
5 changes: 4 additions & 1 deletion apps/member/src/constants/path.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,15 @@ export const PATH = {
BLOG_DETAIL: '/blog/:id',
LIBRARY: '/library',
LIBRARY_DETAIL: '/library/:id',
SUPPORT: '/support',
MEMBERSHIP_FEE: '/membershipFee',
SITEMAP: '/sitemap',
MANAGE: '/manage',
LOGIN: '/login',
AUTH: '/auth',
APPLICATION: '/application',
SUPPORT: '/support',
SUPPORT_WRITE: '/support/write',
SUPPORT_LIST: '/support/list',
} as const;
/**
* 페이지의 URL을 생성하는 함수입니다.
Expand Down
20 changes: 19 additions & 1 deletion apps/member/src/constants/select.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,12 @@ import type {
CommunityCategoryKorType,
CommunityCategoryType,
} from '@type/community';
import type {
SupportCategoryKorType,
SupportCategoryType,
} from '@type/support';

import { APPLICATION_TYPE } from './state';
import { APPLICATION_TYPE, SUPPORT_CATEGORY_STATE } from './state';

type Options<N = string, V = string> = {
name: N;
Expand Down Expand Up @@ -70,3 +74,17 @@ export const SELECT_ACTIVITY_GROUP_CATEGORY_TYPE = {
STUDY: 'STUDY',
PROJECT: 'PROJECT',
} as const;

export const SELECT_OPTIONS_INQUIRY_TYPE: Options<
SupportCategoryKorType,
SupportCategoryType
>[] = [
{
name: '버그',
value: SUPPORT_CATEGORY_STATE.BUG,
},
{
name: '문의',
value: SUPPORT_CATEGORY_STATE.INQUIRY,
},
] as const;
30 changes: 30 additions & 0 deletions apps/member/src/constants/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,3 +142,33 @@ export const APPLICATION_TYPE = {
OPERATION: 'OPERATION',
CORE_TEAM: 'CORE_TEAM',
} as const;

/**
* 문의 카테고리를 정의합니다.
*/
export const SUPPORT_CATEGORY_STATE = {
BUG: 'BUG',
INQUIRY: 'INQUIRY',
} as const;
/**
* 문의 답변 상태를 정의합니다.
*/
export const SUPPORT_ANSWER_STATE = {
PENDING: 'PENDING',
COMPLETED: 'COMPLETED',
} as const;
/**
* 문의 제목의 최대 길이
* 100자
*/
export const SUPPORT_TITLE_MAX_LENGTH = 100;
/**
* 문의 내용의 최대 길이
* 5000자
*/
export const SUPPORT_CONTENT_MAX_LENGTH = 5000;
/**
* 문의 답변의 최대 길이
* 5000자
*/
export const SUPPORT_ANSWER_MAX_LENGTH = 5000;
4 changes: 2 additions & 2 deletions apps/member/src/hooks/modal/useMembershipInfoModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import { DetailsList } from '@clab-platforms/design-system';
import { formatWon } from '@clab-platforms/utils';

import Image from '@components/common/Image/Image';
import MembershipCategoryBadge from '@components/membership/MembershipCategoryBadge/MembershipCategoryBadge';
import MembershipStatusBadge from '@components/membership/MembershipStatusBadge/MembershipStatusBadge';
import MembershipCategoryBadge from '@components/membership/membershipCategoryBadge/MembershipCategoryBadge';
import MembershipStatusBadge from '@components/membership/membershipStatusBadge/MembershipStatusBadge';

import { MODAL_TITLE } from '@constants/modal';
import { UseModalResult, useModal } from '@hooks/common/useModal';
Expand Down
1 change: 1 addition & 0 deletions apps/member/src/hooks/queries/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export * from './blog';
export * from './board';
export * from './book-loan';
export * from './comment';
export * from './support';
export * from './my';
export * from './schedule';
export * from './queryClient';
Expand Down
8 changes: 8 additions & 0 deletions apps/member/src/hooks/queries/support/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export * from './useSupportList';
export * from './useAnswerModifyMutation';
export * from './useAnswerWriteMutation';
export * from './useMySupports';
export * from './useSupportDeleteMutation';
export * from './useSupportDetail';
export * from './useSupportModifyMutation';
export * from './useSupportWriteMutation';
Loading
Loading