6b7f0263e4
Replaces the hardcoded message limit with a model-driven paywall and removes registration before the first question: - Onboarding: the app opens directly into the chat. Dynamic conversation starters are served by GET /suggestions (services/api/suggestions.json), updatable with a deploy — no app release needed. Guests chat via POST /guest/chat, identified by an app-generated device id; sign-in moves to the paywall, where a purchase must attach to an account. - Free experience: the model runs in discovery mode — follow-up questions, pattern identification, visible understanding — building an analysis without delivering the full solution. - Intelligent paywall: the model returns structured output (reply + analysis_ready). Only when the problem is described, the information is sufficient and an action plan is ready does it write a calm transition and pause the conversation. Manufactured urgency, emotional pressure, fake readiness and mid-answer stops are explicitly forbidden. - Premium: on unlock the app resends the transcript and the backend immediately delivers the full analysis, strategies and exercises, then the dialogue continues without restriction. - The old FREE_MESSAGE_LIMIT becomes MESSAGE_CAP (default 200/30 days), kept purely as an abuse backstop — it is not the paywall. - WelcomeScreen removed; the app is now two views (Chat, Paywall). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0118DaxZR36RpnY524vRqx3z
46 lines
1.5 KiB
TypeScript
46 lines
1.5 KiB
TypeScript
import { useState } from 'react';
|
|
import { StatusBar } from 'expo-status-bar';
|
|
import type { ChatMessage } from './src/api/client';
|
|
import { ChatScreen } from './src/screens/ChatScreen';
|
|
import { PaywallScreen } from './src/screens/PaywallScreen';
|
|
|
|
/**
|
|
* Two views, no navigation library. The user lands directly in the chat —
|
|
* no registration before the first question. The backend decides the paywall
|
|
* moment (the analysis is ready); after unlock the conversation continues
|
|
* with the full analysis delivered immediately.
|
|
*/
|
|
export default function App() {
|
|
const [view, setView] = useState<'chat' | 'paywall'>('chat');
|
|
const [messages, setMessages] = useState<ChatMessage[]>([]);
|
|
const [paywalled, setPaywalled] = useState(false);
|
|
const [deliverAnalysis, setDeliverAnalysis] = useState(false);
|
|
|
|
return (
|
|
<>
|
|
<StatusBar style="dark" />
|
|
{view === 'chat' && (
|
|
<ChatScreen
|
|
messages={messages}
|
|
setMessages={setMessages}
|
|
paywalled={paywalled}
|
|
onPaywallTriggered={() => setPaywalled(true)}
|
|
onContinueWithPremium={() => setView('paywall')}
|
|
deliverAnalysis={deliverAnalysis}
|
|
onAnalysisDelivered={() => setDeliverAnalysis(false)}
|
|
/>
|
|
)}
|
|
{view === 'paywall' && (
|
|
<PaywallScreen
|
|
onSubscribed={() => {
|
|
setPaywalled(false);
|
|
setDeliverAnalysis(true);
|
|
setView('chat');
|
|
}}
|
|
onDismiss={() => setView('chat')}
|
|
/>
|
|
)}
|
|
</>
|
|
);
|
|
}
|