Skip to content

feat(post): 좋아요/저장/공유 모달 UX + 낙관 토글, admin 로그인 루프 fix#587

Merged
thxforall merged 16 commits into
devfrom
feature/tryon-profile-mypage
May 28, 2026
Merged

feat(post): 좋아요/저장/공유 모달 UX + 낙관 토글, admin 로그인 루프 fix#587
thxforall merged 16 commits into
devfrom
feature/tryon-profile-mypage

Conversation

@thxforall
Copy link
Copy Markdown
Contributor

Summary

  • Post 좋아요/저장/공유 모달 UX 정비 (5 commits, spec/plan 동봉):
    usePostLike / useSavedPost를 단일 mutation + onMutate 낙관 + 마지막 의도 chain
    구조로 재작성해 race-prone 토글을 제거하고, SocialActions를 controlled API로 전환.
    ImageDetailModal의 drawer aside에 sticky bottom footer를 추가해 explore-preview
    모달에서도 액션 prominence 확보. sharePostUrl 유틸 추출 + 클립보드 토스트 표준화.
  • admin 로그인 무한 루프 수정 (5037b58b): /api/auth/session POST 응답에
    isAdmin 추가, /admin/login에서 비-admin SIGNED_IN 시 signOut + 에러 표시.
    proxy.ts ↔ /admin/login redirect loop 해소.
  • 프로필 탭을 profile API와 정렬 (86f7e31a): StatsCards / PostsGrid /
    LikesGrid / SavedGrid / SolutionsList / ProfileHeader를 신규 응답 스키마에
    맞춰 정리. useProfileExtras, StyleDNAEditModal, InkEconomyCard 미사용 제거.
  • 메인 페이지 hero framing 보존 (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.md
  • docs/superpowers/plans/2026-04-30-post-actions-modal-ux-plan.md

Test plan

  • cd packages/web && bun test — 신규 단위 테스트 통과 확인
    • lib/hooks/__tests__/usePostLike.test.tsx
    • lib/hooks/__tests__/useSavedPost.test.tsx
    • lib/components/shared/__tests__/SocialActions.test.tsx
    • lib/components/detail/__tests__/ImageDetailModal.actions.test.tsx
    • lib/utils/__tests__/sharePostUrl.test.ts
  • 로컬에서 explore → post 모달 → 좋아요/저장 연타 → 새로고침 후 상태 일관성
  • 비로그인 상태에서 좋아요 클릭 → Sign in 토스트 노출
  • Web Share API 미지원 브라우저에서 공유 클릭 → 클립보드 복사 + 토스트
  • iOS safe-area inset 확인 (modal 하단 footer)
  • /admin/login 접속 시 비-admin 세션 → 에러 메시지, 루프 없음 / admin 세션 →
    /admin 정상 진입
  • /profile 탭 6종 정상 렌더링 (Posts / Saved / Likes / Tries / Solutions /
    Badges) 및 빈 상태 처리
  • 메인 페이지 hero carousel — magazine item / spot solution 모두 framing 보존

Breaking changes

없음. (SocialActions props 시그니처는 변경되었지만, 사용처 모두 본 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는 unused
    imports / <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으로 admin lint 정리 PR 권장.

주의 / Follow-up

  • app/page.tsx의 새 mapper 헬퍼에 any 캐스트가 일부 남아 있음. 후속 PR에서
    ApiSpot / ApiSolution 타입으로 좁히는 것을 권장.
  • 추적 이벤트 / 마이크로 인터랙션은 spec 6번에 정의된 follow-up으로 분리됨.

🤖 Generated with Claude Code

thxforall and others added 11 commits May 4, 2026 18:07
- 모달 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>
@vercel
Copy link
Copy Markdown

vercel Bot commented May 28, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
decoded-app Error Error May 29, 2026 6:13am

`.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>
thxforall and others added 2 commits May 28, 2026 14:56
이전 .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>
# 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
@thxforall thxforall added the bump:patch Bug fixes / internal refactor label May 28, 2026
dev에 머지된 MagazineStatus 타입에 generating 추가되었으나
STATUS_DOT 객체에 누락되어 prod 빌드 typecheck 실패.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@thxforall thxforall merged commit e90f116 into dev May 28, 2026
6 checks passed
@github-project-automation github-project-automation Bot moved this from Todo to Done in decoded-monorepo May 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bump:patch Bug fixes / internal refactor

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant