From 153a82e9aeea076bd96aafbcd5c79648efa08d8c Mon Sep 17 00:00:00 2001 From: manNomi Date: Sat, 14 Feb 2026 22:37:10 +0900 Subject: [PATCH 1/6] =?UTF-8?q?fix:=20react19=20ref=20=ED=83=80=EC=9E=85?= =?UTF-8?q?=20=EC=8B=9C=EA=B7=B8=EB=8B=88=EC=B2=98=20=ED=98=B8=ED=99=98?= =?UTF-8?q?=EC=84=B1=20=EB=B3=B4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/(home)/_ui/NewsSection/_hooks/useSectionHadnler.ts | 4 ++-- .../_ui/MentorFindSection/_hooks/useSelectedTab.ts | 2 +- .../_ui/ImageInputFiled/_hooks/useImageInputHandler.ts | 2 +- apps/web/src/app/university/application/ScoreSearchBar.tsx | 2 +- .../components/mentor/ChannelSelct/_hooks/useSelectHandler.ts | 2 +- .../web/src/components/ui/BottomSheet/hooks/useHandleModal.ts | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/web/src/app/(home)/_ui/NewsSection/_hooks/useSectionHadnler.ts b/apps/web/src/app/(home)/_ui/NewsSection/_hooks/useSectionHadnler.ts index 57d935d2..f10e3dea 100644 --- a/apps/web/src/app/(home)/_ui/NewsSection/_hooks/useSectionHadnler.ts +++ b/apps/web/src/app/(home)/_ui/NewsSection/_hooks/useSectionHadnler.ts @@ -1,14 +1,14 @@ import { type RefObject, useEffect, useRef, useState } from "react"; interface UseSectionHandlerReturn { - sectionRef: RefObject; + sectionRef: RefObject; visible: boolean; } const useSectionHandler = (): UseSectionHandlerReturn => { const [visible, setVisible] = useState(false); - const sectionRef = useRef(null); + const sectionRef = useRef(null); useEffect(() => { if (!sectionRef.current) return; diff --git a/apps/web/src/app/mentor/_ui/MentorClient/_ui/MentorFindSection/_hooks/useSelectedTab.ts b/apps/web/src/app/mentor/_ui/MentorClient/_ui/MentorFindSection/_hooks/useSelectedTab.ts index 4c65cd6f..8f1295d8 100644 --- a/apps/web/src/app/mentor/_ui/MentorClient/_ui/MentorFindSection/_hooks/useSelectedTab.ts +++ b/apps/web/src/app/mentor/_ui/MentorClient/_ui/MentorFindSection/_hooks/useSelectedTab.ts @@ -3,7 +3,7 @@ import { type RefObject, useRef, useState } from "react"; import { FilterTab } from "@/types/mentor"; interface UseSelectedTabReturn { - listRef: RefObject; + listRef: RefObject; selectedTab: FilterTab; handleSelectTab: (tab: FilterTab) => void; } diff --git a/apps/web/src/app/my/modify/_ui/ModifyContent/_ui/ImageInputFiled/_hooks/useImageInputHandler.ts b/apps/web/src/app/my/modify/_ui/ModifyContent/_ui/ImageInputFiled/_hooks/useImageInputHandler.ts index 25fd7b21..f01c2cfd 100644 --- a/apps/web/src/app/my/modify/_ui/ModifyContent/_ui/ImageInputFiled/_hooks/useImageInputHandler.ts +++ b/apps/web/src/app/my/modify/_ui/ModifyContent/_ui/ImageInputFiled/_hooks/useImageInputHandler.ts @@ -6,7 +6,7 @@ import { convertUploadedImageUrl } from "@/utils/fileUtils"; interface ImageInputHandlerReturn { selectedImage: File | undefined; imagePreviewUrl: string | null; - fileInputRef: RefObject; + fileInputRef: RefObject; handleImageSelect: () => void; handleFileChange: (event: ChangeEvent) => void; } diff --git a/apps/web/src/app/university/application/ScoreSearchBar.tsx b/apps/web/src/app/university/application/ScoreSearchBar.tsx index f202fc71..2f402fe0 100644 --- a/apps/web/src/app/university/application/ScoreSearchBar.tsx +++ b/apps/web/src/app/university/application/ScoreSearchBar.tsx @@ -3,7 +3,7 @@ import { IconSearchFilled } from "@/public/svgs"; type ScoreSearchBarProps = { onClick: () => void; - textRef: RefObject; + textRef: RefObject; searchHandler: (_e: React.FormEvent) => void; }; diff --git a/apps/web/src/components/mentor/ChannelSelct/_hooks/useSelectHandler.ts b/apps/web/src/components/mentor/ChannelSelct/_hooks/useSelectHandler.ts index 2b03daf9..8f03f1d1 100644 --- a/apps/web/src/components/mentor/ChannelSelct/_hooks/useSelectHandler.ts +++ b/apps/web/src/components/mentor/ChannelSelct/_hooks/useSelectHandler.ts @@ -5,7 +5,7 @@ import type { ChannelType } from "@/types/mentor"; interface useSelectHandlerReturn { isOpen: boolean; - dropdownRef: RefObject; + dropdownRef: RefObject; handleChannelChange: (val: ChannelType | null) => void; toggleDropdown: () => void; } diff --git a/apps/web/src/components/ui/BottomSheet/hooks/useHandleModal.ts b/apps/web/src/components/ui/BottomSheet/hooks/useHandleModal.ts index 9ebb4154..3b0e5f6f 100644 --- a/apps/web/src/components/ui/BottomSheet/hooks/useHandleModal.ts +++ b/apps/web/src/components/ui/BottomSheet/hooks/useHandleModal.ts @@ -6,7 +6,7 @@ const isInteractiveElement = (el: EventTarget | null): boolean => { }; interface UseHandleModalReturn { - elementRef: RefObject; + elementRef: RefObject; isVisible: boolean; translateY: number; isDraggingRef: MutableRefObject; From 6a35a8f5d6cf44a129a3b4a87646a4a28435861f Mon Sep 17 00:00:00 2001 From: manNomi Date: Sat, 14 Feb 2026 22:37:24 +0900 Subject: [PATCH 2/6] =?UTF-8?q?feat:=20=EC=B1=84=ED=8C=85=20=EC=9D=B4?= =?UTF-8?q?=EB=AF=B8=EC=A7=80=20CDN=20=ED=98=B8=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=ED=83=80=EC=9E=85=20=EC=B2=98=EB=A6=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ChatContent/_ui/ChatMessageBox/index.tsx | 1 + apps/web/src/components/ui/FallbackImage.tsx | 35 +++++++++++++++++-- .../src/components/ui/ProfileWithBadge.tsx | 4 +-- 3 files changed, 36 insertions(+), 4 deletions(-) diff --git a/apps/web/src/app/mentor/chat/[chatId]/_ui/ChatContent/_ui/ChatMessageBox/index.tsx b/apps/web/src/app/mentor/chat/[chatId]/_ui/ChatContent/_ui/ChatMessageBox/index.tsx index 0c3815ad..d4483e02 100644 --- a/apps/web/src/app/mentor/chat/[chatId]/_ui/ChatContent/_ui/ChatMessageBox/index.tsx +++ b/apps/web/src/app/mentor/chat/[chatId]/_ui/ChatContent/_ui/ChatMessageBox/index.tsx @@ -29,6 +29,7 @@ const ChatMessageBox = ({ message, currentUserId = 1, partnerNickname = "상대
첨부 이미지 = { + default: process.env.NEXT_PUBLIC_IMAGE_URL || DEFAULT_CDN_HOST, + upload: process.env.NEXT_PUBLIC_UPLOADED_IMAGE_URL || UPLOAD_CDN_HOST, +}; + +const resolveCdnUrl = (src: string, cdnHostType?: CdnHostType) => { + const trimmedSrc = src.trim(); + + if (trimmedSrc.length === 0) return ""; + if (trimmedSrc.startsWith("http://") || trimmedSrc.startsWith("https://")) return trimmedSrc; + if (trimmedSrc.startsWith("blob:") || trimmedSrc.startsWith("data:")) return trimmedSrc; + if (trimmedSrc.startsWith("//")) return `https:${trimmedSrc}`; + if (!cdnHostType) return trimmedSrc; + + const normalizedHost = CDN_HOSTS[cdnHostType].replace(/\/+$/, ""); + const normalizedPath = trimmedSrc.replace(/^\/+/, ""); + + return `${normalizedHost}/${normalizedPath}`; +}; type FallbackImageProps = React.ComponentProps & { fallbackSrc?: string; + cdnHostType?: CdnHostType; }; -const FallbackImage = ({ src, fallbackSrc = DEFAULT_FALLBACK_SRC, onError, ...props }: FallbackImageProps) => { +const FallbackImage = ({ + src, + fallbackSrc = DEFAULT_FALLBACK_SRC, + cdnHostType, + onError, + ...props +}: FallbackImageProps) => { const [failedSource, setFailedSource] = useState(null); - const normalizedSrc = typeof src === "string" ? src.trim() || fallbackSrc : src; + const normalizedSrc = typeof src === "string" ? resolveCdnUrl(src, cdnHostType) || fallbackSrc : src; const sourceKey = typeof normalizedSrc === "string" ? normalizedSrc : JSON.stringify(normalizedSrc); const hasError = failedSource === sourceKey; const resolvedSrc = hasError ? fallbackSrc : normalizedSrc; diff --git a/apps/web/src/components/ui/ProfileWithBadge.tsx b/apps/web/src/components/ui/ProfileWithBadge.tsx index c17bf3b5..e92c2b39 100644 --- a/apps/web/src/components/ui/ProfileWithBadge.tsx +++ b/apps/web/src/components/ui/ProfileWithBadge.tsx @@ -1,6 +1,5 @@ import Image from "@/components/ui/FallbackImage"; import { IconDefaultProfile, IconGraduation } from "@/public/svgs/mentor"; -import { convertUploadedImageUrl } from "@/utils/fileUtils"; interface ProfileWithBadgeProps { profileImageUrl?: string | null; @@ -32,7 +31,8 @@ const ProfileWithBadge = ({ {profileImageUrl ? ( 프로필 이미지 Date: Sat, 14 Feb 2026 22:43:08 +0900 Subject: [PATCH 3/6] =?UTF-8?q?chore:=20pre-push=20=EA=B2=80=EC=A6=9D?= =?UTF-8?q?=EC=9D=84=20CI=20=ED=8C=8C=EC=9D=B4=ED=94=84=EB=9D=BC=EC=9D=B8?= =?UTF-8?q?=EA=B3=BC=20=EB=8F=99=EA=B8=B0=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .husky/pre-push | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.husky/pre-push b/.husky/pre-push index 1c24bed2..c1f62e3d 100755 --- a/.husky/pre-push +++ b/.husky/pre-push @@ -1,4 +1,4 @@ -echo "🏗️ Running CI parity builds before push..." +echo "🏗️ Running CI parity checks before push..." UPSTREAM=$(git rev-parse --abbrev-ref --symbolic-full-name "@{upstream}" 2>/dev/null || true) @@ -33,10 +33,13 @@ for FILE in $CHANGED_FILES; do done if [ "$RUN_WEB" -eq 1 ]; then + pnpm --filter @solid-connect/web run ci:check NODE_ENV=production pnpm --filter @solid-connect/web run build fi if [ "$RUN_ADMIN" -eq 1 ]; then + pnpm --filter @solid-connect/admin run lint + pnpm --filter @solid-connect/admin run format NODE_ENV=production pnpm --filter @solid-connect/admin run build fi @@ -44,4 +47,4 @@ if [ "$RUN_WEB" -eq 0 ] && [ "$RUN_ADMIN" -eq 0 ]; then echo "ℹ️ No CI-targeted changes detected; skipping parity builds." fi -echo "✅ CI parity builds passed!" +echo "✅ CI parity checks passed!" From 98b498875919f49ab975af76d5891413eac0f5ff Mon Sep 17 00:00:00 2001 From: manNomi Date: Sat, 14 Feb 2026 23:03:13 +0900 Subject: [PATCH 4/6] =?UTF-8?q?chore:=20admin=20CI=20=EC=B2=B4=ED=81=AC?= =?UTF-8?q?=EC=99=80=20Biome=20=EC=9B=8C=ED=81=AC=ED=94=8C=EB=A1=9C?= =?UTF-8?q?=EC=9A=B0=EB=A5=BC=20=ED=86=B5=EC=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .husky/pre-commit | 3 +- .husky/pre-push | 3 +- apps/admin/package.json | 5 +- docs/development-workflow.md | 70 ++++++++++++----------- docs/skills/biome-unification-ci-skill.md | 59 +++++++++++++++++++ 5 files changed, 102 insertions(+), 38 deletions(-) create mode 100644 docs/skills/biome-unification-ci-skill.md diff --git a/.husky/pre-commit b/.husky/pre-commit index cb0b5765..68038af8 100644 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -24,8 +24,7 @@ if [ "$RUN_WEB" -eq 1 ]; then fi if [ "$RUN_ADMIN" -eq 1 ]; then - pnpm --filter @solid-connect/admin run lint - pnpm --filter @solid-connect/admin run format + pnpm --filter @solid-connect/admin run ci:check fi if [ "$RUN_WEB" -eq 0 ] && [ "$RUN_ADMIN" -eq 0 ]; then diff --git a/.husky/pre-push b/.husky/pre-push index c1f62e3d..f49f8c48 100755 --- a/.husky/pre-push +++ b/.husky/pre-push @@ -38,8 +38,7 @@ if [ "$RUN_WEB" -eq 1 ]; then fi if [ "$RUN_ADMIN" -eq 1 ]; then - pnpm --filter @solid-connect/admin run lint - pnpm --filter @solid-connect/admin run format + pnpm --filter @solid-connect/admin run ci:check NODE_ENV=production pnpm --filter @solid-connect/admin run build fi diff --git a/apps/admin/package.json b/apps/admin/package.json index 76c004de..5a51fa7f 100644 --- a/apps/admin/package.json +++ b/apps/admin/package.json @@ -7,8 +7,9 @@ "build": "vite build", "preview": "vite preview", "test": "vitest run", - "format": "biome format", - "lint": "biome lint", + "format": "biome format --write .", + "format:check": "biome format .", + "lint": "biome check --write .", "lint:check": "biome check .", "typecheck": "tsc --noEmit", "typecheck:ci": "tsc --noEmit", diff --git a/docs/development-workflow.md b/docs/development-workflow.md index 3dfd57f5..252a3732 100644 --- a/docs/development-workflow.md +++ b/docs/development-workflow.md @@ -84,8 +84,7 @@ feat : 로그인 업데이트 # ❌ 콜론 앞에 공백 - 커밋 전 GitHub CI 품질 검사와 동일한 체크를 실행합니다. - 실행 명령: - `pnpm --filter @solid-connect/web run ci:check` - - `pnpm --filter @solid-connect/admin run lint` - - `pnpm --filter @solid-connect/admin run format` + - `pnpm --filter @solid-connect/admin run ci:check` #### pre-push @@ -98,7 +97,7 @@ feat : 로그인 업데이트 # ❌ 콜론 앞에 공백 ```bash # Husky 재설치 -npm run prepare +pnpm run prepare # 실행 권한 부여 (macOS/Linux) chmod +x .husky/commit-msg @@ -112,36 +111,44 @@ chmod +x .husky/pre-commit ### 개발 ```bash -npm run dev # 개발 서버 실행 -npm run build # 프로덕션 빌드 -npm run start # 프로덕션 서버 실행 +pnpm dev # 터보레포 전체 개발 서버 실행 +pnpm build # 터보레포 전체 빌드 +pnpm --filter @solid-connect/web run dev +pnpm --filter @solid-connect/admin run dev ``` ### 린트 ```bash -npm run lint # ESLint 실행 -npm run lint:fix # ESLint 자동 수정 +pnpm --filter @solid-connect/web run lint # Biome check + write +pnpm --filter @solid-connect/web run lint:check # Biome check only +pnpm --filter @solid-connect/admin run lint # Biome check + write +pnpm --filter @solid-connect/admin run lint:check ``` ### 포맷팅 ```bash -npm run format # Prettier로 코드 포맷팅 -npm run format:check # Prettier 포맷팅 체크 (CI용) +pnpm --filter @solid-connect/web run format +pnpm --filter @solid-connect/web run format:check +pnpm --filter @solid-connect/admin run format +pnpm --filter @solid-connect/admin run format:check ``` ### 타입 체크 ```bash -npm run typecheck # TypeScript 타입 체크 +pnpm typecheck +pnpm --filter @solid-connect/web run typecheck +pnpm --filter @solid-connect/admin run typecheck ``` ### 통합 명령어 ```bash -npm run lint:all # lint + format:check + typecheck -npm run fix:all # lint:fix + format (자동 수정) +pnpm ci:check +pnpm --filter @solid-connect/web run ci:check +pnpm --filter @solid-connect/admin run ci:check ``` ### 추천 워크플로우 @@ -149,7 +156,8 @@ npm run fix:all # lint:fix + format (자동 수정) 코드 수정 후 커밋 전에: ```bash -npm run fix:all # 모든 자동 수정 적용 +pnpm --filter @solid-connect/web run lint +pnpm --filter @solid-connect/admin run lint ``` --- @@ -166,8 +174,7 @@ npm run fix:all # 모든 자동 수정 적용 #### 1. Lint & Type Check -- ESLint 실행 -- Prettier 포맷팅 체크 +- Biome check 실행 - TypeScript 타입 체크 #### 2. Build @@ -180,10 +187,9 @@ npm run fix:all # 모든 자동 수정 적용 ### CI 실패 대응 -1. **ESLint 실패**: `npm run lint:fix`로 자동 수정 -2. **Prettier 실패**: `npm run format`으로 자동 수정 -3. **타입 체크 실패**: TypeScript 오류 직접 수정 -4. **빌드 실패**: 빌드 로그 확인 후 오류 수정 +1. **Biome 실패**: `pnpm --filter @solid-connect/ run lint`로 자동 수정 +2. **타입 체크 실패**: TypeScript 오류 직접 수정 +3. **빌드 실패**: 빌드 로그 확인 후 오류 수정 --- @@ -196,7 +202,7 @@ npm run fix:all # 모든 자동 수정 적용 git checkout -b feat/new-feature # 2. 개발 서버 실행 -npm run dev +pnpm dev # 3. 코드 작성... ``` @@ -205,12 +211,12 @@ npm run dev ```bash # 자동 수정 및 검증 -npm run fix:all +pnpm ci:check # 또는 개별 실행 -npm run lint:fix -npm run format -npm run typecheck +pnpm --filter @solid-connect/web run lint +pnpm --filter @solid-connect/admin run lint +pnpm typecheck ``` ### 3. 커밋 @@ -261,13 +267,14 @@ git push --force-with-lease origin branch-name ```bash # 1. 로컬에서 동일한 검증 실행 -npm run lint:all +pnpm ci:check # 2. 자동 수정 시도 -npm run fix:all +pnpm --filter @solid-connect/web run lint +pnpm --filter @solid-connect/admin run lint # 3. 빌드 테스트 -npm run build +pnpm build # 4. 수정 후 다시 푸시 git add . @@ -283,7 +290,7 @@ git push ```bash # 1. Husky 재설치 -npm run prepare +pnpm run prepare # 2. .husky/commit-msg 파일 확인 cat .husky/commit-msg @@ -301,7 +308,7 @@ chmod +x .husky/commit-msg ```bash # node_modules 삭제 후 재설치 rm -rf node_modules -npm install +pnpm install ``` --- @@ -311,5 +318,4 @@ npm install - [Husky Documentation](https://typicode.github.io/husky/) - [Commitlint Documentation](https://commitlint.js.org/) - [Conventional Commits](https://www.conventionalcommits.org/) -- [ESLint Documentation](https://eslint.org/) -- [Prettier Documentation](https://prettier.io/) +- [Biome Documentation](https://biomejs.dev/) diff --git a/docs/skills/biome-unification-ci-skill.md b/docs/skills/biome-unification-ci-skill.md new file mode 100644 index 00000000..f5142109 --- /dev/null +++ b/docs/skills/biome-unification-ci-skill.md @@ -0,0 +1,59 @@ +# Skill: Biome 단일 품질체크 표준화 (Web/Admin/CI) + +## 목적 + +- 모노레포 전체를 Biome 기반 품질체크 흐름으로 통일한다. +- 로컬(Husky)과 GitHub Actions의 실행 명령을 동일하게 유지한다. + +## 표준 명령 + +### Web + +- 자동 수정: `pnpm --filter @solid-connect/web run lint` +- 체크 전용: `pnpm --filter @solid-connect/web run lint:check` +- 타입 체크: `pnpm --filter @solid-connect/web run typecheck:ci` +- CI 체크: `pnpm --filter @solid-connect/web run ci:check` + +### Admin + +- 자동 수정: `pnpm --filter @solid-connect/admin run lint` +- 체크 전용: `pnpm --filter @solid-connect/admin run lint:check` +- 타입 체크: `pnpm --filter @solid-connect/admin run typecheck` +- CI 체크: `pnpm --filter @solid-connect/admin run ci:check` + +### Root (Turbo) + +- 전체 CI 체크: `pnpm ci:check` +- 전체 타입 체크: `pnpm typecheck` +- 전체 빌드: `pnpm build` + +## 적용 원칙 + +1. CI에서는 `--write`를 사용하지 않는다. +2. 수동 포맷/린트 수정은 로컬에서만 실행한다. +3. 신규 패키지 추가 시 `lint`, `lint:check`, `typecheck`, `ci:check` 스크립트를 동일 규칙으로 맞춘다. +4. Husky pre-commit/push와 GitHub Actions가 같은 스크립트를 호출하도록 유지한다. + +## 작업 절차 + +1. package 스크립트 점검 + - `lint`는 자동 수정, `lint:check`는 체크 전용으로 분리 + - `ci:check`는 `lint:check + typecheck` 조합으로 고정 +2. CI 워크플로우 점검 + - 앱별 품질 단계에서 `pnpm --filter run ci:check` 사용 +3. Husky 훅 점검 + - pre-commit: 변경된 앱의 `ci:check` + - pre-push: 변경된 앱의 `ci:check` + `build` + +## 검증 체크리스트 + +1. `pnpm --filter @solid-connect/web run ci:check` +2. `pnpm --filter @solid-connect/admin run ci:check` +3. `pnpm ci:check` +4. `pnpm build` + +## 실패 대응 + +- Biome 오류: 각 앱에서 `pnpm --filter run lint` 후 재실행 +- 타입 오류: 해당 앱 `typecheck` 로그 기준으로 타입 수정 +- CI/로컬 불일치: `.husky/*`와 `.github/workflows/ci.yml`의 실행 명령을 같은 값으로 재정렬 From 3893fe421241bf8b2302b2f7c1b60a34fa97fec5 Mon Sep 17 00:00:00 2001 From: manNomi Date: Sat, 14 Feb 2026 23:25:10 +0900 Subject: [PATCH 5/6] =?UTF-8?q?fix:=20react19=20ref=20=ED=83=80=EC=9E=85?= =?UTF-8?q?=20=EC=8B=9C=EA=B7=B8=EB=8B=88=EC=B2=98=20=ED=98=B8=ED=99=98?= =?UTF-8?q?=EC=84=B1=20=EB=B3=B4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/app/(home)/_ui/NewsSection/_hooks/useSectionHadnler.ts | 2 +- .../MentorClient/_ui/MentorFindSection/_hooks/useSelectedTab.ts | 2 +- .../_ui/ImageInputFiled/_hooks/useImageInputHandler.ts | 2 +- apps/web/src/app/university/application/ScorePageContent.tsx | 2 +- .../components/mentor/ChannelSelct/_hooks/useSelectHandler.ts | 2 +- apps/web/src/components/ui/BottomSheet/hooks/useHandleModal.ts | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/web/src/app/(home)/_ui/NewsSection/_hooks/useSectionHadnler.ts b/apps/web/src/app/(home)/_ui/NewsSection/_hooks/useSectionHadnler.ts index f10e3dea..23cfcadb 100644 --- a/apps/web/src/app/(home)/_ui/NewsSection/_hooks/useSectionHadnler.ts +++ b/apps/web/src/app/(home)/_ui/NewsSection/_hooks/useSectionHadnler.ts @@ -8,7 +8,7 @@ interface UseSectionHandlerReturn { const useSectionHandler = (): UseSectionHandlerReturn => { const [visible, setVisible] = useState(false); - const sectionRef = useRef(null); + const sectionRef = useRef(null!); useEffect(() => { if (!sectionRef.current) return; diff --git a/apps/web/src/app/mentor/_ui/MentorClient/_ui/MentorFindSection/_hooks/useSelectedTab.ts b/apps/web/src/app/mentor/_ui/MentorClient/_ui/MentorFindSection/_hooks/useSelectedTab.ts index 8f1295d8..6aff076b 100644 --- a/apps/web/src/app/mentor/_ui/MentorClient/_ui/MentorFindSection/_hooks/useSelectedTab.ts +++ b/apps/web/src/app/mentor/_ui/MentorClient/_ui/MentorFindSection/_hooks/useSelectedTab.ts @@ -10,7 +10,7 @@ interface UseSelectedTabReturn { const useSelectedTab = (): UseSelectedTabReturn => { const [selectedTab, setSelectedTab] = useState(FilterTab.ALL); - const listRef = useRef(null); + const listRef = useRef(null!); const handleSelectTab = (tab: FilterTab) => { setSelectedTab(tab); diff --git a/apps/web/src/app/my/modify/_ui/ModifyContent/_ui/ImageInputFiled/_hooks/useImageInputHandler.ts b/apps/web/src/app/my/modify/_ui/ModifyContent/_ui/ImageInputFiled/_hooks/useImageInputHandler.ts index f01c2cfd..d989d94e 100644 --- a/apps/web/src/app/my/modify/_ui/ModifyContent/_ui/ImageInputFiled/_hooks/useImageInputHandler.ts +++ b/apps/web/src/app/my/modify/_ui/ModifyContent/_ui/ImageInputFiled/_hooks/useImageInputHandler.ts @@ -22,7 +22,7 @@ const useImageInputHandler = (initImagePreview: string | null): ImageInputHandle }); const [imagePreviewUrl, setImagePreviewUrl] = useState(null); - const fileInputRef = useRef(null); + const fileInputRef = useRef(null!); useEffect(() => { if (initImagePreview) { diff --git a/apps/web/src/app/university/application/ScorePageContent.tsx b/apps/web/src/app/university/application/ScorePageContent.tsx index 63c65956..d7be963f 100644 --- a/apps/web/src/app/university/application/ScorePageContent.tsx +++ b/apps/web/src/app/university/application/ScorePageContent.tsx @@ -22,7 +22,7 @@ interface ScoreData { const ScorePageContent = () => { const router = useRouter(); - const searchRef = useRef(null); + const searchRef = useRef(null!); const [searchActive, setSearchActive] = useState(false); const [preference, setPreference] = useState<"1순위" | "2순위" | "3순위">("1순위"); diff --git a/apps/web/src/components/mentor/ChannelSelct/_hooks/useSelectHandler.ts b/apps/web/src/components/mentor/ChannelSelct/_hooks/useSelectHandler.ts index 8f03f1d1..f4b87a62 100644 --- a/apps/web/src/components/mentor/ChannelSelct/_hooks/useSelectHandler.ts +++ b/apps/web/src/components/mentor/ChannelSelct/_hooks/useSelectHandler.ts @@ -21,7 +21,7 @@ const useSelectHandler = ({ onChannelChange, }: UseSelectHandlerProps): useSelectHandlerReturn => { const [isOpen, setIsOpen] = useState(false); - const dropdownRef = useRef(null); + const dropdownRef = useRef(null!); const { field } = useController({ name, control, defaultValue: null }); diff --git a/apps/web/src/components/ui/BottomSheet/hooks/useHandleModal.ts b/apps/web/src/components/ui/BottomSheet/hooks/useHandleModal.ts index 3b0e5f6f..589dea66 100644 --- a/apps/web/src/components/ui/BottomSheet/hooks/useHandleModal.ts +++ b/apps/web/src/components/ui/BottomSheet/hooks/useHandleModal.ts @@ -23,7 +23,7 @@ const useHandleModal = (onClose: () => void, snap: number[] = [0]): UseHandleMod const startYRef = useRef(0); // 시작 Y좌표 const currentYRef = useRef(0); // 현재 Y좌표 const isDraggingRef = useRef(false); // 드래그 상태 - const elementRef = useRef(null); + const elementRef = useRef(null!); const snapPoints = useMemo((): number[] => { if (typeof window === "undefined") return [0]; // SSR 대응 From 7a037c10ef9bdbd55aa71ac22c8699e3cae2bf0c Mon Sep 17 00:00:00 2001 From: manNomi Date: Mon, 16 Feb 2026 17:35:46 +0900 Subject: [PATCH 6/6] =?UTF-8?q?fix:=20bottom=20sheet=20ref=20=ED=83=80?= =?UTF-8?q?=EC=9E=85=20=EB=B0=98=ED=99=98=20=EB=88=84=EB=9D=BD=20=EB=B3=B5?= =?UTF-8?q?=EA=B5=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/web/src/components/ui/BottomSheet/hooks/useHandleModal.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/web/src/components/ui/BottomSheet/hooks/useHandleModal.ts b/apps/web/src/components/ui/BottomSheet/hooks/useHandleModal.ts index 67ac8fb7..589dea66 100644 --- a/apps/web/src/components/ui/BottomSheet/hooks/useHandleModal.ts +++ b/apps/web/src/components/ui/BottomSheet/hooks/useHandleModal.ts @@ -1,4 +1,4 @@ -import { type MutableRefObject, useCallback, useEffect, useMemo, useRef, useState } from "react"; +import { type MutableRefObject, type RefObject, useCallback, useEffect, useMemo, useRef, useState } from "react"; // 드래그 핸들에서 제외해야 하는 인터랙티브 엘리먼트 판별 const isInteractiveElement = (el: EventTarget | null): boolean => { @@ -115,6 +115,7 @@ const useHandleModal = (onClose: () => void, snap: number[] = [0]): UseHandleMod }, [isVisible, translateY, snapPoints, handleClose]); return { + elementRef, isVisible, translateY, isDraggingRef,