rebreak-monorepo/apps/rebreak-native/hooks/useCuratedSuggest.ts
chahinebrini 0a0de3b75b feat(vip): Curated-Domain Suggest-UI
In der "Vordefinierte Top-Seiten"-Sektion der VIP-Liste ein
"Seite vorschlagen"-Link → SuggestCuratedSheet: Domain-Eingabe →
POST /api/curated-domains/suggest (Land via Geräte-Region). Response-
Handling: Erfolg / schon vorgeschlagen / approved / rejected / ungültig.

- useCuratedSuggest.ts (neu), SuggestCuratedSheet.tsx (neu)
- VipDomainList.tsx: Suggest-Link in der curated Sub-Sektion + Sheet-State

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-22 21:13:11 +02:00

54 lines
1.6 KiB
TypeScript

import { useState } from 'react';
import { apiFetch } from '../lib/api';
type SuggestResult =
| { ok: true }
| { ok: false; alreadyExists: true; status: 'suggested' | 'approved' | 'rejected' }
| { ok: false; alreadyExists?: false; errorCode?: 'INVALID_DOMAIN' | 'INVALID_COUNTRY' | string };
export type SuggestState = 'idle' | 'loading' | 'success' | 'already_suggested' | 'already_approved' | 'already_rejected' | 'invalid_domain' | 'error';
export function useCuratedSuggest() {
const [state, setState] = useState<SuggestState>('idle');
async function suggest(domain: string, country: string): Promise<SuggestState> {
setState('loading');
try {
const res = await apiFetch<{ ok: boolean; alreadyExists?: boolean; status?: string }>(
'/api/curated-domains/suggest',
{ method: 'POST', body: { domain, country } },
);
if (res.ok) {
setState('success');
return 'success';
}
if (res.alreadyExists) {
const next: SuggestState =
res.status === 'approved'
? 'already_approved'
: res.status === 'rejected'
? 'already_rejected'
: 'already_suggested';
setState(next);
return next;
}
setState('error');
return 'error';
} catch (e: any) {
const code: string = (e as any)?.code ?? '';
if (code === 'INVALID_DOMAIN') {
setState('invalid_domain');
return 'invalid_domain';
}
setState('error');
return 'error';
}
}
function reset() {
setState('idle');
}
return { state, suggest, reset };
}