feat(post): 좋아요/저장/공유 모달 UX + 낙관 토글, admin 로그인 루프 fix#587
Merged
Conversation
- 모달 explore-preview에서 액션 prominence 부재 + race-prone 좋아요/저장 hook 정비 - usePostLike/useSavedPost: 단일 mutation + onMutate 낙관 + pendingIntent chain - ImageDetailModal: drawer aside sticky bottom footer 추가, ImageDetailContent L778 정적 블록 제거 - 비로그인 토스트(Sign in CTA), 공유 클립보드 토스트, 에러 토스트 표준화 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- 6 tasks, TDD 방식: 실패 테스트 → 구현 → 통과 → 커밋 - Task 1: usePostLike 낙관 토글 + 마지막 의도 chain - Task 2: useSavedPost 동일 패턴 - Task 3: SocialActions controlled API 전환 + 모달 정적 블록 제거 - Task 4: sharePostUrl util 추출 + 클립보드 토스트 - Task 5: ImageDetailModal sticky bottom footer - Task 6: 수동 QA + lint sweep - 추적 이벤트 / 마이크로 인터랙션은 follow-up으로 분리 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Single mutation with mutationFn:(next:boolean) → create or delete - toggle() writes optimistic cache, queues opposite intent during in-flight - onError snapshot rollback + sonner toast - onSuccess chains pendingIntent when it differs from last variables - onSettled invalidates detail key + likes feed key - ImageDetailContent.handleLike now reads usePostLike.toggle directly
INITIAL_SESSION 이벤트로 자동 /admin 이동 시 비-admin 세션 보유자가 proxy.ts → /admin/login 리다이렉트와 무한 루프에 빠지는 문제 수정. - /api/auth/session POST 응답에 isAdmin 추가 (서버에서 checkIsAdmin 호출) - /admin/login 페이지: SIGNED_IN 시 isAdmin 분기 — 비-admin 은 signOut + 세션 쿠키 삭제 후 에러 메시지 표시. INITIAL_SESSION 분기는 제거 (이미 proxy.ts 가 admin 인증된 사용자를 /admin 으로 바운스해 처리) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Document preOptimisticSnapshotRef race semantics + onSettled reconciliation - Document TanStack Query v5 mutation.mutate self-reference safety - Switch PostDetailLikeCache to Partial<PostDetailResponse> (avoid drift) - Add cache-state assertions to chain and unauth tests - Document why same-intent coalesce is not unit-tested (timing artifact) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…sePostLike) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Drop internal useState/useEffect; expose liked/saved/likeCount/saveCount as props - aria-pressed reflects toggle state for AT - ImageDetailContent: floating bar passes controlled props; modal-static block removed (modal will own its footer in Task 5) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Web Share API → silent (OS UI handles feedback) - Clipboard fallback → "Link copied" / "Couldn't copy link" - ImageDetailContent.handleShare now a thin call to the util Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Drawer aside now mounts its own SocialActions footer (always visible) - Pulls liked/saved/counts from cached image (controlled) - Wires usePostLike/useSavedPost toggles + sharePostUrl - Comment hidden in explore-preview (overlay disabled there) - safe-area inset honored for iOS Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
`.map().filter()` chain TS 추론 실패로 Vercel build에서 type check fail.
`HeroPostEntry["items"][number] & { label: string }` non-null array 반환을
보장하기 위해 .flatMap pattern으로 재작성 (null case = empty array return).
- mapSpotSolutionsToHeroItems: nested flatMap, no null branch
- mapMagazineItemsToHeroItems: flatMap with HeroItem type param
local build / tsc --noEmit 통과.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
이전 .flatMap<HeroItem>() 호출이 spots: any[]로 인해 "Untyped function calls may not accept type arguments" TS error 발생. 명령형 for-loop으로 재작성하여 type inference를 명확히 함. 동작은 동일. local build 통과 (next build + tsc). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
3 tasks
# Conflicts: # docs/superpowers/specs/2026-04-30-post-actions-modal-ux-design.md # packages/web/app/page.tsx # packages/web/lib/components/DecodedLogo.tsx # packages/web/lib/components/detail/ImageDetailModal.tsx
dev에 머지된 MagazineStatus 타입에 generating 추가되었으나 STATUS_DOT 객체에 누락되어 prod 빌드 typecheck 실패. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
usePostLike/useSavedPost를 단일 mutation + onMutate 낙관 + 마지막 의도 chain구조로 재작성해 race-prone 토글을 제거하고,
SocialActions를 controlled API로 전환.ImageDetailModal의 drawer aside에 sticky bottom footer를 추가해 explore-preview모달에서도 액션 prominence 확보.
sharePostUrl유틸 추출 + 클립보드 토스트 표준화.5037b58b):/api/auth/sessionPOST 응답에isAdmin추가,/admin/login에서 비-admin SIGNED_IN 시 signOut + 에러 표시.proxy.ts ↔ /admin/login redirect loop 해소.
86f7e31a):StatsCards/PostsGrid/LikesGrid/SavedGrid/SolutionsList/ProfileHeader를 신규 응답 스키마에맞춰 정리.
useProfileExtras,StyleDNAEditModal,InkEconomyCard미사용 제거.fe35a448):app/page.tsx에 spot solution /magazine item을 hero item으로 안전하게 매핑하는 헬퍼 추가, fallback 처리로
HeroCard 빈 슬롯 방지.
main-renewal/*컴포넌트 framing 일관성 정리.packages/web/scripts/dev-profile-seed.sql추가 (로컬 Supabase전용),
.gitignore에.superpowers/추가.주요 변경 파일
packages/web/lib/hooks/usePostLike.ts,useSavedPost.ts(+낙관 토글, +테스트)packages/web/lib/components/shared/SocialActions.tsx(controlled API, +테스트)packages/web/lib/components/detail/ImageDetailModal.tsx,ImageDetailContent.tsx(sticky footer, +테스트)packages/web/lib/utils/sharePostUrl.ts(+테스트)packages/web/app/admin/login/page.tsx,packages/web/app/api/auth/session/route.ts(admin 루프 fix)packages/web/app/profile/ProfileClient.tsx,packages/web/lib/components/profile/*(탭 정렬)packages/web/app/page.tsx,packages/web/lib/components/main-renewal/*(hero framing)packages/web/app/api/v1/users/me/solutions/route.ts(신규 proxy 라우트)packages/web/app/api/v1/posts/route.ts(Supabase fallback에user_id필터 추가)docs/superpowers/specs/2026-04-30-post-actions-modal-ux-design.mddocs/superpowers/plans/2026-04-30-post-actions-modal-ux-plan.mdTest plan
cd packages/web && bun test— 신규 단위 테스트 통과 확인lib/hooks/__tests__/usePostLike.test.tsxlib/hooks/__tests__/useSavedPost.test.tsxlib/components/shared/__tests__/SocialActions.test.tsxlib/components/detail/__tests__/ImageDetailModal.actions.test.tsxlib/utils/__tests__/sharePostUrl.test.ts/admin/login접속 시 비-admin 세션 → 에러 메시지, 루프 없음 / admin 세션 →/admin정상 진입/profile탭 6종 정상 렌더링 (Posts / Saved / Likes / Tries / Solutions /Badges) 및 빈 상태 처리
Breaking changes
없음. (
SocialActionsprops 시그니처는 변경되었지만, 사용처 모두 본 PR에서 함께 마이그레이션됨.)Linked issues
특별히 close 되는 이슈는 없음. 관련 spec/plan은 본 PR의
docs/superpowers/specs|plans/2026-04-30-post-actions-modal-ux-*.md.Lint / build
bun run lint: 본 브랜치 신규 변경 파일에서 error 0건 (warnings는 unusedimports /
<img>권고 등 기존 톤과 동일). 22개 lint error는 모두app/api/admin/entities/*,lib/components/admin/{editorial,raw-posts}/*,lib/api/admin/__tests__/posts.test.ts등 본 PR과 무관한 파일에서 발생하며,origin/dev에서도 동일하게 실패함 → 본 PR 머지 차단 사유 아님.주의 / Follow-up
app/page.tsx의 새 mapper 헬퍼에any캐스트가 일부 남아 있음. 후속 PR에서ApiSpot/ApiSolution타입으로 좁히는 것을 권장.🤖 Generated with Claude Code