diff --git a/.cli/_task_context.md b/.cli/_task_context.md deleted file mode 100644 index 69b0b76..0000000 --- a/.cli/_task_context.md +++ /dev/null @@ -1,5 +0,0 @@ -- TASK_ID: 0023 -- TASK_TITLE: 종료 버튼 길게 누르기 진행선 비주얼 어색함 개선(원형 대안 적용) -- TASK_SLUG: finish-hold-visual-alt-for-non-circle-button -- DATE: 2026-02-14 -- FILES: src/app/debrief/page.tsx, src/features/flight-session/model/useFlightSession.ts, src/widgets/flight-hud/ui/FlightHudWidget.tsx, AGENTS.md diff --git a/.cli/changelog.md b/.cli/changelog.md deleted file mode 100644 index 803e79d..0000000 --- a/.cli/changelog.md +++ /dev/null @@ -1,130 +0,0 @@ -# Changelog - -> 규칙 -> -> - 새 작업이 끝나면 맨 위(최신)에 추가한다. -> - 날짜 섹션이 없으면 새로 만든다. -> - 각 항목은 3~5줄 이내로 짧게. -> - “무엇이 바뀌었는지”와 “영향 범위(파일)”만 남긴다. - -## 2026-02-14 - -- [0023] 종료 버튼 길게 누르기 진행선 비주얼 어색함 개선(원형 대안 적용) - - Summary: 종료 버튼의 원형 진행선을 제거하고 버튼 형태와 일치하는 수평 fill 진행 피드백으로 교체해 hold 인터랙션 시각 일관성을 개선 - - Summary: 2초 hold 규칙, 조기 해제 시 즉시 초기화, 완료 시 회고 모달 오픈 등 기존 종료 플로우 동작은 유지 - - Files: src/app/debrief/page.tsx, src/features/flight-session/model/useFlightSession.ts, src/widgets/flight-hud/ui/FlightHudWidget.tsx, AGENTS.md - -- [0022] Flight 종료 버튼 2초 길게 누르기(hold-to-confirm) + 원형 진행선 + 종료 모달 오픈 - - Summary: Flight 종료 버튼을 단순 클릭에서 2초 hold-to-confirm 상호작용으로 전환하고, 진행률을 conic-gradient 외곽 진행선으로 시각화 - - Summary: 2초 미만 해제 시 진행 상태를 즉시 초기화하고 아무 종료 동작도 발생하지 않게 유지, 2초 도달 시 기존 회고 모달 오픈/저장 흐름 재사용 - - Files: src/app/debrief/page.tsx, src/features/flight-session/model/useFlightSession.ts, src/widgets/flight-hud/ui/FlightHudWidget.tsx, AGENTS.md - -- [0021] Flight 종료 후 회고를 모달로 전환하고 회고 폼 항목/아이콘 정리 - - Summary: Flight HUD 종료 버튼을 페이지 이동 대신 회고 모달 오픈으로 전환하고 저장/취소 흐름을 화면 내에서 처리하도록 구성 - - Summary: 회고 폼에서 Next 항목을 제거하고 상태 라벨의 이모지를 제거해 문구 톤을 정리, 저장 시 기존과 동일하게 히스토리 저장 후 /log 이동 유지 - - Files: src/app/debrief/page.tsx, src/features/flight-session/model/useFlightSession.ts, src/widgets/flight-hud/ui/FlightHudWidget.tsx, AGENTS.md - -- [0020] Flight 화면 "이번 항해 목표" 뷰 UI/UX 개선 - - Summary: Flight HUD 목표 영역을 카드형 레이아웃으로 전환해 라벨(이번 항해 목표)과 본문을 분리하고 정보 위계를 명확화 - - Summary: 긴 목표 문구 대응을 위해 줄바꿈과 최대 높이/세로 스크롤 처리 및 대비/여백/행간을 조정해 가독성을 개선 - - Files: src/features/flight-session/model/useFlightSession.ts, src/widgets/flight-hud/ui/FlightHudWidget.tsx, AGENTS.md - -- [0019] 오리온/쌍둥이자리 카운트다운 타이머를 HH:MM:SS로 표시 - - Summary: 카운트다운 항로 타이머 포맷 로직을 HH:MM:SS 고정으로 단순화해 오리온/쌍둥이자리 초기값 및 진행 표시를 3단 자리수로 통일 - - Summary: 타이머 감소 속도/종료 조건은 유지하고 표시 포맷만 조정해 카운트다운 동작 회귀를 방지 - - Files: src/features/flight-session/model/useFlightSession.ts, src/widgets/flight-hud/ui/FlightHudWidget.tsx, AGENTS.md - -## 2026-02-13 - -- [0018] 우주정거장(무제한 체류) 타이머 count-up 복구 및 HH:MM:SS 표시 - - Summary: 우주정거장 항로(duration=0)에서 타이머를 카운트다운이 아닌 count-up으로 계산해 1초 단위 증가를 복구 - - Summary: station 타이머 포맷을 HH:MM:SS로 고정하고 카운트다운 항로의 완료 판정 문구 분기를 분리해 회귀를 방지 - - Files: src/features/flight-session/model/useFlightSession.ts, src/widgets/flight-hud/ui/FlightHudWidget.tsx, AGENTS.md - -- [0017] Enter로 진행 — 탑승(미션 설정) & 회고(항해일지) 폼을 form submit로 처리 - - Summary: 탑승 미션 폼을 form submit 구조로 전환해 Enter 입력이 “도킹 완료(출항)”과 동일한 로직을 호출하도록 정리 - - Summary: 회고 화면을 form submit 기반으로 통일하고 상태 선택 버튼을 non-submit으로 고정해 Enter 저장 흐름을 안정화 - - Files: src/app/debrief/page.tsx, src/features/boarding/ui/BoardingMissionForm.tsx - -- [0016] Lobby 목표 설정 화면을 모달로 전환 + 메모 기능 제거(동작 유지) - - Summary: 로비의 “바로 출항” 동선을 페이지 이동(`/boarding`)에서 모달 기반 목표 설정으로 전환하고 ESC/배경클릭/취소 닫기를 지원 - - Summary: boarding 생성 경로를 `features/boarding`으로 통합하고 메모 입력 UI/상태/저장 필드를 제거해 출항 로직을 단일화 - - Files: src/app/boarding/page.tsx, src/widgets/lobby-routes/ui/LobbyRoutesPanel.tsx, src/features/boarding/index.ts, src/features/boarding/model/startVoyage.ts, src/features/boarding/ui/BoardingMissionForm.tsx, .cli/docs/architecture.md - -- [0015] FSD 정착 2차 — 잔재 import 제거/중복 정리 + widgets public API 고정 + 분리작업 준비 - - Summary: pages/widgets/features/shared import 경로를 정리해 `@/lib`, `@/types`, `@/components` 직접 참조를 제거하고 단일 소스를 shared·features로 통일 - - Summary: widgets별 `index.ts` public API를 추가하고 Home/Flight 페이지를 widgets 조합 전용으로 고정, 구 브릿지 파일(components/lib/types) 정리 - - Files: src/app/page.tsx, src/app/flight/page.tsx, src/app/boarding/page.tsx, src/app/debrief/page.tsx, src/app/log/page.tsx, src/app/log/[id]/page.tsx, src/app/settings/page.tsx, src/components/ui/button.tsx, src/components/ui/card.tsx, src/components/ui/dialog.tsx, src/components/ui/input.tsx, src/components/ui/separator.tsx, src/components/FlightBackground.tsx, src/components/LobbyBackground.tsx, src/lib/constants.ts, src/lib/store.ts, src/lib/utils.ts, src/types/index.ts, src/shared/types/index.ts, src/shared/config/routes.ts, src/shared/config/starfield.ts, src/shared/lib/store.ts, src/shared/lib/cn.ts, src/shared/lib/math/number.ts, src/shared/lib/motion/prefersReducedMotion.ts, src/features/lobby-session/model/useLobbyRedirect.ts, src/features/lobby-starfield/index.ts, src/features/lobby-starfield/model/constellationData.ts, src/features/lobby-starfield/ui/ConstellationScene.tsx, src/features/lobby-starfield/ui/StarGlint.tsx, src/features/flight-starfield/index.ts, src/features/flight-starfield/model/types.ts, src/features/flight-starfield/model/starfieldModel.ts, src/features/flight-starfield/lib/projection.ts, src/features/flight-starfield/ui/FlightStarfieldCanvas.tsx, src/features/flight-session/model/useFlightSession.ts, src/widgets/lobby-background/index.ts, src/widgets/lobby-background/ui/LobbyBackgroundWidget.tsx, src/widgets/lobby-routes/index.ts, src/widgets/lobby-routes/ui/LobbyRoutesPanel.tsx, src/widgets/flight-background/index.ts, src/widgets/flight-background/ui/FlightBackgroundWidget.tsx, src/widgets/flight-hud/index.ts, src/widgets/flight-hud/ui/FlightHudWidget.tsx - -- [0014] FSD 1차 구조로 리팩토링(동작 동일) — lobby/flight 시각 컴포넌트 및 로직 분리 - - Summary: Home/Flight 페이지를 조합 전용으로 축소하고 배경/스타필드/HUD/리다이렉트 로직을 features·widgets 구조로 분리 - - Summary: 로비 글린트/플라이트 캔버스 로직과 스타필드 타입·튜닝값·모션 유틸을 shared/config·shared/lib·features/model/lib로 정리 - - Files: src/app/page.tsx, src/app/flight/page.tsx, src/shared/config/starfield.ts, src/shared/lib/math/number.ts, src/shared/lib/motion/prefersReducedMotion.ts, src/features/lobby-session/model/useLobbyRedirect.ts, src/features/lobby-starfield/model/constellationData.ts, src/features/lobby-starfield/ui/ConstellationScene.tsx, src/features/lobby-starfield/ui/StarGlint.tsx, src/features/flight-starfield/model/types.ts, src/features/flight-starfield/model/starfieldModel.ts, src/features/flight-starfield/lib/projection.ts, src/features/flight-starfield/ui/FlightStarfieldCanvas.tsx, src/features/flight-session/model/useFlightSession.ts, src/widgets/lobby-background/ui/LobbyBackgroundWidget.tsx, src/widgets/lobby-routes/ui/LobbyRoutesPanel.tsx, src/widgets/flight-background/ui/FlightBackgroundWidget.tsx, src/widgets/flight-hud/ui/FlightHudWidget.tsx - -- [0013] Home 별자리 별(코어) 더 작게 + Flight 스타필드 속도 추가 감속 - - Summary: Home 별 코어 반지름을 추가 축소하고 코어 대비를 높여 작은 별 중심 표현을 강화, glint 길이/피크는 소폭 감쇠 - - Summary: Flight 스타필드 speed 티어를 한 단계 더 낮춰 워프감을 줄이고 조용한 전진/유영 느낌으로 재튜닝 - - Files: .gitignore, src/app/flight/page.tsx, src/app/globals.css, src/app/page.tsx, src/components/FlightBackground.tsx, src/components/LobbyBackground.tsx, src/lib/constants.ts - -- [0012] Lobby 배경 별(코어) 더 작고 더 진하게 튜닝 - - Summary: Home 별자리 코어 반지름을 15~35% 축소해 노드/버튼 느낌을 줄이고 작은 점 중심으로 정리 - - Summary: 코어 opacity 티어를 상향하고 glint/bloom 피크를 소폭 감쇠해 “작고 진한 별 + 은은한 글린트”로 조정 - - Files: .gitignore, src/app/flight/page.tsx, src/app/globals.css, src/app/page.tsx, src/components/FlightBackground.tsx, src/components/LobbyBackground.tsx, src/lib/constants.ts - -- [0011] Home 별 모양을 Flight 스타일로 통일 + glint 유지(십자/그라데이션/블룸, opacity only) - - Summary: Home 별자리 코어 반지름/밝기 티어를 flight 별 범위에 맞춰 재조정해 노드형 인상을 완화 - - Summary: 기존 십자 글린트(그라데이션/블룸)는 유지하고 코어 애니메이션을 변수 기반 opacity-only로 정렬 - - Files: .gitignore, src/app/flight/page.tsx, src/app/globals.css, src/app/page.tsx, src/components/FlightBackground.tsx, src/components/LobbyBackground.tsx, src/lib/constants.ts - -- [0010] Flight 스타필드 튜닝 — 중심 과집중 완화(넓은 스폰) + 속도 감속(유영 느낌) - - Summary: 소실점 기반 투영은 유지하되 스폰 반경을 넓은 링 중심 분포로 재조정해 중심 과집중을 완화 - - Summary: 속도 티어를 감속 범위로 낮추고 꼬리 티어를 4~10px 하한 기준으로 조정해 유영 느낌을 강화 - - Files: .gitignore, src/app/flight/page.tsx, src/app/globals.css, src/app/page.tsx, src/components/FlightBackground.tsx, src/components/LobbyBackground.tsx, src/lib/constants.ts - -- [0009] Flight 스타필드 가시성/전진감 개선 — “먼지 낙하” 제거 + 원근 전진(소실점) + 저밀도 유지 - - Summary: Flight 배경을 z-투영 기반 소실점 스타필드로 전환해 수직 낙하 인상을 제거하고 전진감을 강화 - - Summary: 별 가시성(밝기/반지름/꼬리 하한)을 상향하면서 저밀도 범위와 중심 UI 보호, reduced-motion 정지를 유지 - - Files: .gitignore, src/app/flight/page.tsx, src/app/globals.css, src/app/page.tsx, src/components/FlightBackground.tsx, src/components/LobbyBackground.tsx, src/lib/constants.ts - -- [0008] Flight 스타필드(이미지 없이) — “조용한 우주” 점 중심 + 약한 전진감 + 교차 0 (저밀도 튜닝) - - Summary: Flight 배경을 단일 방향 미세 전진감 기반으로 재구성해 교차/X자 인상을 제거하고 점 중심 표현으로 조정 - - Summary: 별 밀도를 데스크탑 18~45 / 모바일 12~30 범위로 제한하고 중앙 보호 베일 및 reduced-motion 정지 렌더를 적용 - - Files: .gitignore, src/app/flight/page.tsx, src/app/globals.css, src/app/page.tsx, src/components/FlightBackground.tsx, src/components/LobbyBackground.tsx, src/lib/constants.ts - -- [0007] Flight 스타필드 방향 수정(중심→4모서리 대각) + 중심부 자연화 + 별 개수 축소 - - Summary: 별 흐름을 화면 중심 영역에서 NE/NW/SE/SW 대각선으로 퍼져나가도록 재구성하고 수직 낙하 인상을 제거 - - Summary: 중심부 베일 그라데이션과 리사이클 스폰을 적용하고 스타 수를 68개로 축소해 과밀감을 완화 - - Files: .gitignore, src/app/globals.css, src/app/page.tsx, src/components/FlightBackground.tsx, src/components/LobbyBackground.tsx, src/lib/constants.ts - -- [0006] Lobby 별(노드) UI를 “빛나는 별”로 개선(그라데이션 스파이크 + 블룸 + 강약) — 이동 없음 - - Summary: 십자 스파이크를 중앙 강조/양끝 투명 그라데이션으로 정교화하고 별별 강약(피크/길이/크기)을 분산 - - Summary: 블룸 1겹과 작은 코어 글로우를 적용하고 반짝임을 opacity-only 리듬으로 조정 - - Files: .gitignore, src/app/globals.css, src/app/page.tsx, src/components/LobbyBackground.tsx, src/lib/constants.ts - -- [0005] Lobby 별 반짝임을 “십자 글린트 + 블룸(이미지 참고)”로 개선(이동/transform 0) - - Summary: 별 글린트를 대각선 없이 십자(+)만 남기고, 선 양끝 투명 그라데이션으로 부드럽게 감쇠되도록 조정 - - Summary: 코어/스파이크에 저강도 블룸 레이어를 추가하고 반짝임 리듬을 opacity-only 피크 형태로 재설계 - - Files: .gitignore, src/app/globals.css, src/app/page.tsx, src/components/LobbyBackground.tsx, src/lib/constants.ts - -- [0004] Lobby 별 반짝임을 “빛 번짐(십자/팔각 글린트)”으로 구현(이동 없음) - - Summary: 로비 별자리를 십자/팔각 글린트 기반 반짝임으로 변경하고 별자리 외 랜덤 별 생성 제거 - - Summary: 별 반짝임을 opacity-only로 분산 타이밍 적용하고 reduced-motion에서 정지/저강도 처리 - - Files: .gitignore, src/app/globals.css, src/app/page.tsx, src/components/LobbyBackground.tsx, src/lib/constants.ts - -- [0003] Lobby twinkle를 “반짝임만”으로 고정(이동 제거) + 별자리 3개 유지 - - Summary: 로비 배경의 별 반짝임(Twinkle)을 이동 없이 빛과 미세한 크기 변화만 있도록 수정 - - Summary: 배경 스크롤/드리프트/스타필드 등 모든 이동 애니메이션 제거 및 3개 별자리 고정 - - Files: src/app/globals.css - -- [0002] Lobby 별자리 3개 고정 + 별 반짝임 구현 + 불필요 별/문구 제거 - - Summary: 로비 하단 "3명 대기 중" 문구 제거 및 재발 방지 - - Summary: 배경 별자리를 오리온/마차부/북두칠성 3개로 고정하고 개별 별 반짝임 구현 - - Summary: 카드 내부 및 배경의 불필요한 랜덤 별 생성 로직 제거 - - Files: src/app/page.tsx, src/app/globals.css, src/components/LobbyBackground.tsx - -## 2026-02-12 - -- [0001] Lobby 카드 구성 단순화 + twinkle 강화 - - Summary: 로비 화면을 우주정거장(CTA) 및 오리온/쌍둥이자리 2열 구성으로 변경 - - Summary: 배경 및 카드 내 별 반짝임 효과(Twinkle) 강화 및 접근성(Reduced Motion) 적용 - - Files: src/lib/constants.ts, src/components/LobbyBackground.tsx, src/app/page.tsx diff --git a/.cli/planner/input.md b/.cli/planner/input.md deleted file mode 100644 index 29be653..0000000 --- a/.cli/planner/input.md +++ /dev/null @@ -1,5 +0,0 @@ -# input.md (자연어 초안) - -## 원하는 목표 - -- 꾹 눌렀을 때 나오는 테두리가 원이 아니다보니 어색한 면이 있다. 어떻게 하면 어색해지지 않을지 고민해서 적절한 대안을 찾아라. diff --git a/.gitignore b/.gitignore index 0367b47..8b8ad9b 100644 --- a/.gitignore +++ b/.gitignore @@ -40,3 +40,7 @@ yarn-error.log* *.tsbuildinfo next-env.d.ts .idea +.cli/tasks +.cli/_task_context.md +.cli/changelog.md +.cli/planner/input.md diff --git a/src/app/flight/page.tsx b/src/app/flight/page.tsx index 1e9d082..abcc6de 100644 --- a/src/app/flight/page.tsx +++ b/src/app/flight/page.tsx @@ -1,13 +1,16 @@ 'use client'; +import { useFlightSession } from '@/features/flight-session/model/useFlightSession'; import { FlightBackgroundWidget } from '@/widgets/flight-background'; import { FlightHudWidget } from '@/widgets/flight-hud'; export default function FlightPage() { + const session = useFlightSession(); + return (
- - + +
); } diff --git a/src/features/flight-starfield/ui/FlightStarfieldCanvas.tsx b/src/features/flight-starfield/ui/FlightStarfieldCanvas.tsx index 56747c5..a87bb76 100644 --- a/src/features/flight-starfield/ui/FlightStarfieldCanvas.tsx +++ b/src/features/flight-starfield/ui/FlightStarfieldCanvas.tsx @@ -16,11 +16,15 @@ import { getPrefersReducedMotionMediaQuery } from '@/shared/lib/motion/prefersRe export function FlightStarfieldCanvas({ vanishYOffset = -68, centerProtectRadius = 200, + isPaused = false, }: { vanishYOffset?: number; centerProtectRadius?: number; + isPaused?: boolean; }) { const canvasRef = useRef(null); + const starsRef = useRef([]); + const vanishXJitterRef = useRef(null); useEffect(() => { const canvas = canvasRef.current; @@ -35,7 +39,10 @@ export function FlightStarfieldCanvas({ const motionQuery = getPrefersReducedMotionMediaQuery(); let prefersReducedMotion = motionQuery.matches; - const vanishXJitter = createFlightVanishXJitter(); + if (vanishXJitterRef.current === null) { + vanishXJitterRef.current = createFlightVanishXJitter(); + } + const vanishXJitter = vanishXJitterRef.current ?? 0; const setCanvasSize = () => { width = window.innerWidth; @@ -58,7 +65,10 @@ export function FlightStarfieldCanvas({ ); setCanvasSize(); - let stars: FlightStar[] = createStars(); + if (starsRef.current.length === 0) { + starsRef.current = createStars(); + } + let stars = starsRef.current; const applyCenterProtection = (x: number, y: number, alpha: number) => { const centerX = width / 2; @@ -183,6 +193,7 @@ export function FlightStarfieldCanvas({ }) ) { stars[index] = createFlightStar({ width, height, isRespawn: true }); + starsRef.current = stars; return; } @@ -198,7 +209,18 @@ export function FlightStarfieldCanvas({ drawVignette(); }; + const stopAnimation = () => { + if (!animationFrameId) return; + cancelAnimationFrame(animationFrameId); + animationFrameId = 0; + }; + const render = () => { + if (prefersReducedMotion || isPaused) { + animationFrameId = 0; + return; + } + drawFrame(true); animationFrameId = requestAnimationFrame(render); }; @@ -211,8 +233,9 @@ export function FlightStarfieldCanvas({ const handleResize = () => { setCanvasSize(); stars = createStars(); + starsRef.current = stars; - if (prefersReducedMotion) { + if (prefersReducedMotion || isPaused) { renderStatic(); } }; @@ -221,18 +244,20 @@ export function FlightStarfieldCanvas({ prefersReducedMotion = event.matches; if (prefersReducedMotion) { - cancelAnimationFrame(animationFrameId); + stopAnimation(); renderStatic(); return; } - render(); + if (!isPaused && !animationFrameId) { + render(); + } }; window.addEventListener('resize', handleResize); motionQuery.addEventListener('change', handleMotionChange); - if (prefersReducedMotion) { + if (prefersReducedMotion || isPaused) { renderStatic(); } else { render(); @@ -241,9 +266,9 @@ export function FlightStarfieldCanvas({ return () => { window.removeEventListener('resize', handleResize); motionQuery.removeEventListener('change', handleMotionChange); - cancelAnimationFrame(animationFrameId); + stopAnimation(); }; - }, [vanishYOffset, centerProtectRadius]); + }, [vanishYOffset, centerProtectRadius, isPaused]); return ; } diff --git a/src/widgets/flight-background/ui/FlightBackgroundWidget.tsx b/src/widgets/flight-background/ui/FlightBackgroundWidget.tsx index 3bcb15c..f531c88 100644 --- a/src/widgets/flight-background/ui/FlightBackgroundWidget.tsx +++ b/src/widgets/flight-background/ui/FlightBackgroundWidget.tsx @@ -1,5 +1,11 @@ import { FlightStarfieldCanvas } from '@/features/flight-starfield'; -export function FlightBackgroundWidget() { - return ; +export function FlightBackgroundWidget({ isPaused }: { isPaused: boolean }) { + return ( + + ); } diff --git a/src/widgets/flight-hud/ui/FlightHudWidget.tsx b/src/widgets/flight-hud/ui/FlightHudWidget.tsx index 3809dbc..8dc3125 100644 --- a/src/widgets/flight-hud/ui/FlightHudWidget.tsx +++ b/src/widgets/flight-hud/ui/FlightHudWidget.tsx @@ -8,7 +8,6 @@ import { DialogHeader, DialogTitle, } from "@/components/ui/dialog"; -import { useFlightSession } from "@/features/flight-session/model/useFlightSession"; import { saveCurrentVoyage, saveToHistory } from "@/shared/lib/store"; import { Voyage, VoyageStatus } from "@/shared/types"; @@ -23,16 +22,24 @@ const statusOptions: { value: VoyageStatus; label: string; desc: string }[] = [ ]; const FINISH_HOLD_MS = 1000; -export function FlightHudWidget() { +type FlightHudWidgetProps = { + voyage: Voyage | null; + isPaused: boolean; + formattedTime: string; + isCountdownCompleted: boolean; + handlePauseToggle: () => void; + handleFinish: () => Voyage | null; +}; + +export function FlightHudWidget({ + voyage, + isPaused, + formattedTime, + isCountdownCompleted, + handlePauseToggle, + handleFinish, +}: FlightHudWidgetProps) { const router = useRouter(); - const { - voyage, - isPaused, - formattedTime, - isCountdownCompleted, - handlePauseToggle, - handleFinish, - } = useFlightSession(); const [isDebriefOpen, setIsDebriefOpen] = useState(false); const [finishedVoyage, setFinishedVoyage] = useState(null); const [status, setStatus] = useState(null);