[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:
parent
c8dc68536e
commit
a517439c7d
@ -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,11 +70,13 @@ 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
|
||||
? needsReauth
|
||||
? '연결이 만료됐습니다. 다시 연결해야 게재할 수 있습니다.'
|
||||
: '연결되어 있습니다. 사이트를 발행한 뒤 소개글을 써서 올릴 수 있습니다.'
|
||||
: '미리 연결해 두면, 사이트를 발행한 뒤 소개글을 써서 이 계정으로 올립니다.'}
|
||||
{!ready
|
||||
? '연동 준비 중입니다. 열리면 여기서 계정을 연결합니다.'
|
||||
: account
|
||||
? needsReauth
|
||||
? '연결이 만료됐습니다. 다시 연결해야 게재할 수 있습니다.'
|
||||
: '연결되어 있습니다. 사이트를 발행한 뒤 소개글을 써서 올릴 수 있습니다.'
|
||||
: '미리 연결해 두면, 사이트를 발행한 뒤 소개글을 써서 이 계정으로 올립니다.'}
|
||||
</p>
|
||||
{account && (
|
||||
<p className="mt-1 text-xs">
|
||||
@ -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>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user