[fix] solution/frontend: 연동 카드를 준비 전에도 보여준다 — 숨기면 기능이 없는 것처럼 보인다

앱 자격증명(THREADS_*)이 없으면 카드를 통째로 숨겼다. 근거는 "누를 수 없는 버튼을 세우지
않는다" 였는데, **이 기능을 만든 사람조차 "연동 버튼이 아예 안 보인다" 고 했다**(2026-09-14).
만든 사람이 못 찾으면 사장님은 더더욱 못 찾는다 — 숨기는 것과 "아직 준비 중" 은 다른 말이고,
화면은 그 둘을 구별해 말해야 한다.

- 자리는 늘 보이고 **버튼만 비활성**이다. "연동 준비 중입니다. 열리면 여기서 계정을 연결합니다."
- 통째로 접는 경우는 하나만 남겼다 — 상태를 아직 못 읽었을 때(로그인 직후 한순간).
  그건 '준비 안 됨' 이 아니라 '모름' 이라 다르게 다뤄야 한다

검증: frontend tsc·eslint 통과. 번들에 새 문구가 실린 것과 `connection_enabled=false` 에서
비활성 상태로 그려지는 것을 확인

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
hbyang 2026-09-14 16:29:31 +09:00
parent c8dc68536e
commit a517439c7d

View File

@ -12,10 +12,12 @@ import {socialApi, type SocialState} from './api';
* , .
* , [ ] .
*
* ** .**
* `THREADS_APP_ID` 409 (`SOCIAL_CONNECTION_DISABLED`).
* , .
* `connection_enabled` (docs/SOCIAL.md '연동 준비').
* ** .** , .
* `connection_enabled=false` , ** **
* "연동 버튼이 안 보인다" (2026-09-14). .
* "아직 준비 중" , .
* 409 (`SOCIAL_CONNECTION_DISABLED`) ** **
* , (docs/SOCIAL.md '연동 준비').
*/
export function SocialConnectionCard() {
const [state, setState] = useState<SocialState | null>(null);
@ -35,8 +37,10 @@ export function SocialConnectionCard() {
void load();
}, [load]);
if (!state?.connection_enabled) return null;
// 상태를 아직 못 읽었을 때만 접는다(로그인 직후 한순간). '준비 안 됨' 과는 다르다.
if (!state) return null;
const ready = state.connection_enabled;
const account = state.account;
const needsReauth = account?.status === 'needs_reauth';
@ -66,7 +70,9 @@ export function SocialConnectionCard() {
<div className="min-w-0">
<h2 className="text-sm font-bold">SNS · Threads</h2>
<p className="mt-1 text-xs text-muted-foreground">
{account
{!ready
? '연동 준비 중입니다. 열리면 여기서 계정을 연결합니다.'
: account
? needsReauth
? '연결이 만료됐습니다. 다시 연결해야 게재할 수 있습니다.'
: '연결되어 있습니다. 사이트를 발행한 뒤 소개글을 써서 올릴 수 있습니다.'
@ -87,7 +93,12 @@ export function SocialConnectionCard() {
</div>
<div className="flex shrink-0 flex-wrap gap-2">
<Button size="sm" variant={account && !needsReauth ? 'outline' : 'primary'} disabled={busy} onClick={connect}>
<Button
size="sm"
variant={account && !needsReauth ? 'outline' : 'primary'}
disabled={busy || !ready}
onClick={connect}
>
{busy ? <Loader2 className="size-4 animate-spin" /> : <Link2 className="size-4" />}
<span>{account ? '다시 연결' : 'Threads 계정 연결'}</span>
</Button>
@ -106,7 +117,7 @@ export function SocialConnectionCard() {
</div>
{/* 게재가 아직 안 열린 상태를 숨기지 않는다 — 연결만 해 두고 기다리는 것도 사장님의 선택이다. */}
{!state.posting_enabled && (
{ready && !state.posting_enabled && (
<p className="mt-3 text-xs text-muted-foreground">
. .
</p>