-
Notifications
You must be signed in to change notification settings - Fork 1
Feat(client): 직무 아티클 주기적 업데이트 공지 로딩 추가 #289
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,26 @@ | ||||||||||||||||||||||||||||||||
| import JobPinsBottomSpinner from './JobPinsBottomSpinner'; | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| interface JobPinsBottomNoticeProps { | ||||||||||||||||||||||||||||||||
| visible: boolean; | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| const JobPinsBottomNotice = ({ visible }: JobPinsBottomNoticeProps) => { | ||||||||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||||||||
| <div | ||||||||||||||||||||||||||||||||
| className={`w-full overflow-hidden transition-all duration-300 ease-out ${ | ||||||||||||||||||||||||||||||||
| visible | ||||||||||||||||||||||||||||||||
| ? 'max-h-[10rem] translate-y-0 py-[1.2rem] opacity-100' | ||||||||||||||||||||||||||||||||
| : 'max-h-0 translate-y-2 py-0 opacity-0' | ||||||||||||||||||||||||||||||||
| }`} | ||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||
|
Comment on lines
+9
to
+15
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 숨김 상태를 접근성 트리에도 반영해 주세요. Line 10-14는 시각적 접힘만 처리해서, 숨김 상태 문구가 보조기기에 노출될 수 있습니다. 래퍼에 제안 diff <div
+ aria-hidden={!visible}
className={`w-full overflow-hidden transition-all duration-300 ease-out ${
visible
? 'max-h-[10rem] translate-y-0 py-[1.2rem] opacity-100'
: 'max-h-0 translate-y-2 py-0 opacity-0'
}`}
>📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||
| <div className="flex w-full flex-col items-center gap-[0.8rem]"> | ||||||||||||||||||||||||||||||||
| <p className="body2-m text-font-gray-3 text-center"> | ||||||||||||||||||||||||||||||||
| 관심 직무 핀은 계속 업데이트 돼요! | ||||||||||||||||||||||||||||||||
| </p> | ||||||||||||||||||||||||||||||||
| <JobPinsBottomSpinner /> | ||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| export default JobPinsBottomNotice; | ||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| import { useId } from 'react'; | ||
|
|
||
| const JobPinsBottomSpinner = () => { | ||
| const gradientId = useId(); | ||
|
|
||
| return ( | ||
| <svg | ||
| xmlns="http://www.w3.org/2000/svg" | ||
| width="30" | ||
| height="30" | ||
| viewBox="0 0 30 30" | ||
| fill="none" | ||
| className="animate-spin-smooth h-[3rem] w-[3rem]" | ||
| > | ||
| <circle cx="15" cy="15" r="13" stroke="#E5E7EB" strokeWidth="4" /> | ||
| <circle | ||
| cx="15" | ||
| cy="15" | ||
| r="13" | ||
| stroke={`url(#${gradientId})`} | ||
| strokeWidth="4" | ||
| strokeDasharray="46 120" | ||
| strokeLinecap="round" | ||
| /> | ||
| <defs> | ||
| <radialGradient | ||
| id={gradientId} | ||
| cx="0" | ||
| cy="0" | ||
| r="1" | ||
| gradientUnits="userSpaceOnUse" | ||
| gradientTransform="translate(13 9.75) rotate(122.975) scale(20.3637)" | ||
| > | ||
| <stop stopColor="var(--color-gradient-start, #cff080)" /> | ||
| <stop offset="1" stopColor="var(--color-gradient-end, #33d08f)" /> | ||
| </radialGradient> | ||
| </defs> | ||
| </svg> | ||
| ); | ||
| }; | ||
|
|
||
| export default JobPinsBottomSpinner; |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,59 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { useCallback, useEffect, useRef, useState } from 'react'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export const useJobPinsBottomNotice = () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const scrollContainerRef = useRef<HTMLDivElement>(null); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const hideTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const [isBottomNoticeVisible, setIsBottomNoticeVisible] = useState(false); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const showBottomNoticeTemporarily = useCallback(() => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (isBottomNoticeVisible) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setIsBottomNoticeVisible(true); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (hideTimerRef.current) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| clearTimeout(hideTimerRef.current); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| hideTimerRef.current = setTimeout(() => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setIsBottomNoticeVisible(false); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| hideTimerRef.current = null; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, 2000); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, [isBottomNoticeVisible]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+8
to
+22
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 공지 재노출 타이머가 갱신되지 않습니다. Line 9의 조기 제안 diff const showBottomNoticeTemporarily = useCallback(() => {
- if (isBottomNoticeVisible) {
- return;
- }
-
setIsBottomNoticeVisible(true);
if (hideTimerRef.current) {
clearTimeout(hideTimerRef.current);
}
hideTimerRef.current = setTimeout(() => {
setIsBottomNoticeVisible(false);
hideTimerRef.current = null;
}, 2000);
- }, [isBottomNoticeVisible]);
+ }, []);📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| useEffect(() => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (hideTimerRef.current) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| clearTimeout(hideTimerRef.current); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, []); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const handleBottomWheel = useCallback( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| (e: React.WheelEvent<HTMLDivElement>) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (e.deltaY <= 0) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const container = scrollContainerRef.current; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!container) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const isAtBottom = | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| container.scrollTop + container.clientHeight >= | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| container.scrollHeight - 1; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (isAtBottom) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| showBottomNoticeTemporarily(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| [showBottomNoticeTemporarily] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| scrollContainerRef, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| isBottomNoticeVisible, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| handleBottomWheel, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
Repository: Pinback-Team/pinback-client
Length of output: 3697
🏁 Script executed:
Repository: Pinback-Team/pinback-client
Length of output: 676
🏁 Script executed:
Repository: Pinback-Team/pinback-client
Length of output: 148
🏁 Script executed:
Repository: Pinback-Team/pinback-client
Length of output: 1509
🏁 Script executed:
Repository: Pinback-Team/pinback-client
Length of output: 1005
🏁 Script executed:
Repository: Pinback-Team/pinback-client
Length of output: 1948
🏁 Script executed:
Repository: Pinback-Team/pinback-client
Length of output: 105
공지 높이 애니메이션으로 인한 센티넬 재교차 가능성이 있습니다.
Line 66-67에서
JobPinsBottomNotice가 300ms 전환 애니메이션으로 높이가 변하면(max-h: 0 ↔ 10rem), 센티넬이 재진입할 수 있습니다. 현재useInfiniteScroll은hasNextPage가드만 사용하며, 옵저버 콜백 내부에isFetching체크가 없어 진행 중인 페치 중 레이아웃 변동 시 중복 호출 위험이 있습니다.개선안:
useInfiniteScroll콜백에서 다음과 같이 추가 가드를 적용하세요.또는 TanStack Query의
isFetchingNextPage상태를 props로 받아 콜백 내에서 체크하면 더욱 견고합니다.🤖 Prompt for AI Agents