Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
b163175
Malsami-FE 버전 관리 : docs : v0.1.21 README 버전 정보 업데이트 [skip ci]
actions-user Sep 5, 2025
7528332
공지사항 섹션 수정 : refactor : 빌드오류 확인 및 가이드라인 보강 https://github.com/Sejong-…
Cassiiopeia Sep 6, 2025
7d07a89
Merge pull request #640 from Sejong-Balsamic/20250820_#594_기능개선_메인페이지…
Cassiiopeia Sep 6, 2025
def2d93
Malsami-FE 버전 정보 관리: chore: 버전 0.1.22 [skip ci]
actions-user Sep 6, 2025
8eee6fd
UI 수정 : feat : ui 수정 https://github.com/Sejong-Balsamic/Malsami-FE/is…
thswogh Oct 1, 2025
4d90a56
Merge pull request #642 from Sejong-Balsamic/20250829_#633_기능추가_자료_자료…
thswogh Oct 1, 2025
5debd5b
Malsami-FE 버전 정보 관리: chore: 버전 0.1.23 [skip ci]
actions-user Oct 1, 2025
d8a42fe
PIN공지사항 API 개발에 대한 연결 : feat : 공지사항 리스트 구현, 기본적인 구현 (고도화예정) https://g…
Cassiiopeia Oct 1, 2025
b7f88a0
Merge branch 'main' of https://github.com/Sejong-Balsamic/Malsami-FE
Cassiiopeia Oct 1, 2025
28469c4
PIN공지사항 API 개발에 대한 연결 : feat : 공지사항 상세보기 구현 https://github.com/Sejong…
Cassiiopeia Oct 1, 2025
11b5cde
PIN공지사항 API 개발에 대한 연결 : feat : 공지사항 상세보기 좋아요에 대한 css로직 개선 https://git…
Cassiiopeia Oct 1, 2025
2c4c1d1
자료필터링 UI 기능 수정 : feat : 필터링 UI개선 및 라벨 리네임 https://github.com/Sejong-B…
thswogh Oct 1, 2025
0e22810
자료필터링 UI 기능 수정 : feat : 하드코딩된 색상값 변경 https://github.com/Sejong-Balsam…
thswogh Oct 1, 2025
cf095cc
Merge pull request #645 from Sejong-Balsamic/20251001_#643_기능개선_자료필터링…
thswogh Oct 1, 2025
d676f8d
Malsami-FE 버전 정보 관리: chore: 버전 0.1.24 [skip ci]
actions-user Oct 1, 2025
98fe0f6
PIN공지사항 API 개발에 대한 연결 : feat : 댓글 작성이 불가능한 글입니다 문구 추가 및 스켈레톤 추가 https…
Cassiiopeia Oct 1, 2025
43fbc70
PIN공지사항 API 개발에 대한 연결 : feat : 댓글 작성이 불가능한 글입니다 문구 추가 및 스켈레톤 추가2 http…
Cassiiopeia Oct 1, 2025
9dbbc02
PIN공지사항 API 개발에 대한 연결 : feat : 공지사항 좋아요 기능 pai 연결 https://github.com/…
Cassiiopeia Oct 1, 2025
38ac09c
PIN공지사항 API 개발에 대한 연결 : refactor : UPPER_SNAKE_CASE 변경 https://github…
Cassiiopeia Oct 1, 2025
841c3de
Merge pull request #644 from Sejong-Balsamic/20251001_#544_기능추가_공지사항_…
Cassiiopeia Oct 1, 2025
34a8a6f
Malsami-FE 버전 정보 관리: chore: 버전 0.1.25 [skip ci]
actions-user Oct 1, 2025
f144529
Malsami-FE 버전 관리 : docs : v0.1.25 릴리즈 문서 업데이트 (PR #646)
actions-user Oct 1, 2025
c54b719
Merge remote-tracking branch 'origin/deploy'
actions-user Oct 1, 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
42 changes: 39 additions & 3 deletions CHANGELOG.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,47 @@
{
"metadata": {
"lastUpdated": "2025-09-05T17:08:34Z",
"currentVersion": "0.1.21",
"lastUpdated": "2025-10-01T13:31:52Z",
"currentVersion": "0.1.25",
"projectType": "react",
"totalReleases": 14
"totalReleases": 15
},
"releases": [
{
"version": "0.1.25",
"project_type": "react",
"date": "2025-10-01",
"pr_number": 646,
"raw_summary": "Summary by CodeRabbit\n\nNew Features\n\n공지사항 상세 페이지 추가(로딩 스켈레톤 포함) 및 좋아요/취소 기능 지원\n고정(핀) 공지 다건 표기 및 목록 상단 노출\n\n\nStyle\n\n공지 카드/핀 카드 레이아웃 개선 및 접근성 향상(키보드 포커스·라벨)\n필터링 바텀시트/태그/버튼의 타이포그래피·색상 토큰·레이아웃 정리\n문서 카드 최소 높이 제거로 가변 높이 지원\n\n\nDocumentation\n\n빌드 성공/실패 기준 가이드 추가\n\n\nChores\n\n앱 및 동기화 버전 갱신 (README, package, version 설정)",
"parsed_changes": {
"new_features": {
"title": "New Features",
"items": [
"공지사항 상세 페이지 추가(로딩 스켈레톤 포함) 및 좋아요/취소 기능 지원",
"고정(핀) 공지 다건 표기 및 목록 상단 노출"
]
},
"style": {
"title": "Style",
"items": [
"공지 카드/핀 카드 레이아웃 개선 및 접근성 향상(키보드 포커스·라벨)",
"필터링 바텀시트/태그/버튼의 타이포그래피·색상 토큰·레이아웃 정리",
"문서 카드 최소 높이 제거로 가변 높이 지원"
]
},
"documentation": {
"title": "Documentation",
"items": [
"빌드 성공/실패 기준 가이드 추가"
]
},
"chores": {
"title": "Chores",
"items": [
"앱 및 동기화 버전 갱신 (README, package, version 설정)"
]
}
}
},
{
"version": "0.1.21",
"project_type": "react",
Expand Down
25 changes: 23 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,28 @@
# Changelog

**현재 버전:** 0.1.21
**마지막 업데이트:** 2025-09-05T17:08:34Z
**현재 버전:** 0.1.25
**마지막 업데이트:** 2025-10-01T13:31:52Z

---

## [0.1.25] - 2025-10-01

**PR:** #646

**New Features**
- 공지사항 상세 페이지 추가(로딩 스켈레톤 포함) 및 좋아요/취소 기능 지원
- 고정(핀) 공지 다건 표기 및 목록 상단 노출

**Style**
- 공지 카드/핀 카드 레이아웃 개선 및 접근성 향상(키보드 포커스·라벨)
- 필터링 바텀시트/태그/버튼의 타이포그래피·색상 토큰·레이아웃 정리
- 문서 카드 최소 높이 제거로 가변 높이 지원

**Documentation**
- 빌드 성공/실패 기준 가이드 추가

**Chores**
- 앱 및 동기화 버전 갱신 (README, package, version 설정)

---

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<!-- 수정하지마세요 자동으로 동기화 됩니다 -->

<!-- 수정하지마세요 자동으로 동기화 됩니다 -->
## 최신 버전 : v0.1.17 (2025-08-27)
## 최신 버전 : v0.1.21 (2025-09-05)

[전체 버전 기록 보기](CHANGELOG.md)

Expand Down
76 changes: 76 additions & 0 deletions claude.md
Original file line number Diff line number Diff line change
Expand Up @@ -570,6 +570,82 @@ source ~/.zshrc && npm run build

⚠️ **이 두 명령어를 실행하지 않으면 코드 검토를 통과하지 못합니다!** ⚠️

### 🔍 빌드 성공/실패 판단 기준 (매우 중요!)

#### ✅ 빌드 성공 판단 기준

다음 **모든** 조건을 만족해야 빌드 성공:

1. **컴파일 성공 메시지**:
```
✓ Compiled successfully
```

2. **.next 디렉토리 생성 확인**:
```bash
ls -la .next/ # 디렉토리와 빌드 파일들이 존재해야 함
```

3. **치명적 에러 없음**:
- `Error: ` 메시지 없음
- `Failed to compile.` 후에 실제 Error가 없음
- TypeScript 에러 없음

#### ❌ 빌드 실패 판단 기준

다음 **하나라도** 발견되면 빌드 실패:

1. **컴파일 실패**:
```
✗ Failed to compile
Error: [실제 에러 메시지]
```

2. **TypeScript 에러**:
```
Type error: Property 'xxx' does not exist on type 'yyy'
```

3. **Module not found 에러**:
```
Module not found: Can't resolve 'xxx'
```

4. **.next 디렉토리 미생성**: 빌드 완료 후 .next 폴더가 없음

#### ⚠️ ESLint 경고는 빌드 성공!

**중요**: ESLint 경고는 빌드 실패가 아닙니다!

```bash
# 이런 메시지들은 빌드 성공 (경고일 뿐):
Warning: Unexpected console statement. no-console
Warning: Using `<img>` could result in slower LCP @next/next/no-img-element
Warning: Do not use Array index in keys react/no-array-index-key

# 실제 컴파일도 성공했다면:
✓ Compiled successfully
```

#### 🤖 Claude의 빌드 판단 프로세스

1. **`npm run build` 실행**
2. **출력에서 `✓ Compiled successfully` 확인**
3. **`.next` 디렉토리 존재 확인**: `ls -la .next/`
4. **실제 Error 메시지 스캔** (Warning 제외)
5. **최종 판단**:
- 성공: "빌드가 성공적으로 완료되었습니다"
- 실패: "빌드 실패: [구체적인 에러 원인]"

#### 📋 빌드 확인 체크리스트

- [ ] `✓ Compiled successfully` 메시지 확인
- [ ] `.next/` 디렉토리 생성 확인
- [ ] TypeScript 에러 없음 확인
- [ ] Module not found 에러 없음 확인
- [ ] ESLint 경고와 실제 에러 구분
- [ ] 빌드 최종 상태 정확히 보고

### 일반 CLI 사용법

```bash
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "malsami-fe",
"version": "0.1.21",
"version": "0.1.25",
"private": true,
"scripts": {
"dev": "next dev",
Expand Down
6 changes: 6 additions & 0 deletions public/icons/pushpinBlue.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 10 additions & 0 deletions src/apis/likeApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { DocumentCommand } from "@/types/api/requests/documentCommand";
import { DocumentDto } from "@/types/api/responses/documentDto";
import { CommentCommand } from "@/types/api/requests/commentCommand";
import { CommentDto } from "@/types/api/responses/commentDto";
import { NoticePostCommand } from "@/types/api/requests/noticePostCommand";
import { NoticePostDto } from "@/types/api/responses/noticePostDto";
import { postApiRequest } from "./apiUtils";

export const likeApi = {
Expand All @@ -15,6 +17,14 @@ export const likeApi = {
documentBoardLike: async (command: Partial<DocumentCommand>): Promise<DocumentDto> =>
postApiRequest<DocumentCommand, DocumentDto>("/api/document/like", command),

// 공지사항 좋아요
noticeBoardLike: async (command: Partial<NoticePostCommand>): Promise<NoticePostDto> =>
postApiRequest<NoticePostCommand, NoticePostDto>("/api/notice/like", command),

// 공지사항 좋아요 취소
cancelNoticeBoardLike: async (command: Partial<NoticePostCommand>): Promise<void> =>
postApiRequest<NoticePostCommand, void>("/api/notice/like/cancel", command),

// 댓글 좋아요
commentLike: async (command: Partial<CommentCommand>): Promise<CommentDto> =>
postApiRequest<CommentCommand, CommentDto>("/api/comment/like", command),
Expand Down
10 changes: 9 additions & 1 deletion src/apis/noticePostApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,16 @@ import { postApiRequest } from "./apiUtils";

export const noticePostApi = {
// 필터링된 공지사항 게시글 조회
getFilteredNoticePosts: async (command: Partial<NoticePostCommand>): Promise<NoticePostDto> =>
fetchFilteredNoticePosts: async (command: Partial<NoticePostCommand>): Promise<NoticePostDto> =>
postApiRequest<NoticePostCommand, NoticePostDto>("/api/notice/filter", command),

// 단일 공지사항 상세 조회
fetchNoticePost: async (command: Partial<NoticePostCommand>): Promise<NoticePostDto> =>
postApiRequest<NoticePostCommand, NoticePostDto>("/api/notice/get", command),

// PIN된 공지사항 조회
fetchPinnedNoticePosts: async (): Promise<NoticePostDto> =>
postApiRequest<NoticePostCommand, NoticePostDto>("/api/notice/get/pinned", {}),
};

export default noticePostApi;
1 change: 0 additions & 1 deletion src/app/board/document/sub/my-faculty/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,6 @@ export default function MyFacultyDocumentPage() {
onReset={handleFilterReset}
onConfirm={handleDocumentConfirm}
currentFiltering={currentFiltering}
activeColor="#0CD4AE"
trigger={<div />}
/>
</div>
Expand Down
109 changes: 109 additions & 0 deletions src/app/notice/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
"use client";

import axios from "axios";
import ScrollToTopOnLoad from "@/components/common/ScrollToTopOnLoad";
import CommonHeader from "@/components/header/CommonHeader";
import { RIGHT_ITEM } from "@/types/header";
import NoticeDetail from "@/components/notice/NoticeDetail";
import { useParams, useRouter } from "next/navigation";
import { useEffect, useState } from "react";
import { NoticePostCommand } from "@/types/api/requests/noticePostCommand";
import NoticeDetailSkeleton from "@/components/common/skeletons/NoticeDetailSkeleton";
import useCommonToast from "@/global/hook/useCommonToast";
import noticePostApi from "@/apis/noticePostApi";
import { NoticePostDto } from "@/types/api/responses/noticePostDto";

export default function Page() {
const router = useRouter();
const { showWarningToast } = useCommonToast();

// URL 파라미터 가져옴
const params = useParams();
const postId = Array.isArray(params.id) ? params.id[0] : params.id;

// 상태 관리
const [noticeDetails, setNoticeDetails] = useState<NoticePostDto | null>(null);
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState<string | null>(null);

// API 호출 (postId 변경 시마다)
useEffect(() => {
let isMounted = true;

if (postId) {
const fetchData = async () => {
try {
setIsLoading(true);
setError(null);
const command: Partial<NoticePostCommand> = {
noticePostId: postId,
};
const data = await noticePostApi.fetchNoticePost(command);

if (isMounted) {
setNoticeDetails(data);
}
} catch (innerError) {
if (isMounted && !error) {
if (axios.isAxiosError(innerError)) {
// 인증 관련 에러(401, 403)는 appClient에서 처리하므로 여기서는 router.back()만 실행
if (innerError.response?.status === 401 || innerError.response?.status === 403) {
if (typeof window !== "undefined" && window.history.length > 1) {
router.back();
} else {
router.replace("/");
}
} else if (innerError.response?.data?.errorCode === "MISSING_REFRESH_TOKEN") {
// MISSING_REFRESH_TOKEN 에러도 appClient에서 모달 처리
if (typeof window !== "undefined" && window.history.length > 1) {
router.back();
} else {
router.replace("/");
}
} else {
// 다른 에러는 기존 로직 유지
const message = innerError.response?.data?.errorMessage || "알 수 없는 오류가 발생했습니다.";
showWarningToast(message);
setError(message);
if (typeof window !== "undefined" && window.history.length > 1) {
router.back();
} else {
router.replace("/");
}
}
} else {
showWarningToast("예상치 못한 오류가 발생했습니다.");
if (typeof window !== "undefined" && window.history.length > 1) {
router.back();
} else {
router.replace("/");
}
}
}
} finally {
if (isMounted) {
setIsLoading(false);
}
}
};

fetchData();
}
return () => {
isMounted = false;
};
}, [postId, router, showWarningToast]);

// 오류 상태 처리
if (error) return <p>오류가 발생했습니다. 다시 시도해주세요.</p>;

return (
<div className="mx-auto min-h-screen w-full max-w-[640px]">
<ScrollToTopOnLoad />
<CommonHeader title="공지사항" rightType={RIGHT_ITEM.NONE} />
<div>
{isLoading ? <NoticeDetailSkeleton /> : noticeDetails && <NoticeDetail noticePostDto={noticeDetails} />}
</div>
</div>
);
}
Loading
Loading