diff --git a/.DS_Store b/.DS_Store index 18829a8..b9b5395 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/App.tsx b/App.tsx index f8d54cd..69130e8 100644 --- a/App.tsx +++ b/App.tsx @@ -11,17 +11,12 @@ import { ChevronLeft, ExternalLink, Sparkles, User, Lock, ArrowRight, AlertCircl import { generateStoryContent } from './services/geminiService'; import { getEnvVar } from './utils/envUtils'; -const STORAGE_KEY = 'gpx-storyteller-state-v6'; // Incremented version for structure change +const STORAGE_KEY = 'gpx-storyteller-state-v6'; const AUTH_KEY = 'promptstory-auth-token'; // --- PASSWORD CONFIGURATION --- -const ENV_PASSWORD = getEnvVar('VITE_APP_PASSWORD'); -// Fallback Hardcoded Password (Safety net) -const FALLBACK_PASS = 'Preorder$Disinfect6$Childlike$Unnamed'; - -// Decision Logic -const APP_PASSWORD = ENV_PASSWORD || FALLBACK_PASS; -const IS_USING_FALLBACK = !ENV_PASSWORD; +// STRICT MODE: No fallbacks. The environment variable must be set in Coolify/Vercel/Netlify. +const APP_PASSWORD = getEnvVar('VITE_APP_PASSWORD'); const INITIAL_STATE: WizardState = { step: Step.CONTEXT, @@ -53,42 +48,44 @@ const INITIAL_STATE: WizardState = { const LoginScreen: React.FC<{ onLogin: (success: boolean) => void }> = ({ onLogin }) => { const [input, setInput] = useState(''); const [error, setError] = useState(false); - const [showDebug, setShowDebug] = useState(false); - - // DEBUGGING: Log to console on mount - useEffect(() => { - console.group("--- DEBUG PASSWORD SYSTEM ---"); - console.log("1. Detected ENV Variable:", ENV_PASSWORD ? "****" : "(empty)"); - console.log("2. Final Password Source:", IS_USING_FALLBACK ? "FALLBACK (Code)" : ".ENV FILE"); - console.log("3. Active Password Length:", APP_PASSWORD.length); - console.groupEnd(); - }, []); + + // Check if password is misconfigured (empty) + const isConfigMissing = !APP_PASSWORD; const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); - // Trim input to avoid accidental spaces from copy-paste if (input.trim() === APP_PASSWORD) { onLogin(true); } else { - console.log(`Failed Login. Input: "${input}" vs Expected: "${APP_PASSWORD}"`); setError(true); setInput(''); } }; + if (isConfigMissing) { + return ( +
+
+ +

Błąd Konfiguracji

+

+ Aplikacja nie wykryła hasła w zmiennych środowiskowych. +

+
+

Brakuje zmiennej: VITE_APP_PASSWORD

+

Jeśli używasz Coolify/Vercel:

+

1. Dodaj zmienną w panelu.

+

2. Przebuduj projekt (Re-deploy).

+
+
+
+ ); + } + return (
- {/* Debug Toggle (Hidden in corner) */} - -
@@ -97,7 +94,7 @@ const LoginScreen: React.FC<{ onLogin: (success: boolean) => void }> = ({ onLogi

Dostęp Chroniony

-

Wprowadź hasło, aby uzyskać dostęp do kreatora PromptStory.

+

Wprowadź hasło, aby uzyskać dostęp.

@@ -134,32 +131,9 @@ const LoginScreen: React.FC<{ onLogin: (success: boolean) => void }> = ({ onLogi - - {/* DEBUG PANEL */} - {showDebug && ( -
-

DEBUG STATUS:

- -
- SOURCE: - - {IS_USING_FALLBACK ? "FALLBACK (Code)" : ".ENV FILE"} - - - ACTIVE PASS: - {APP_PASSWORD.substring(0, 4)}... (len: {APP_PASSWORD.length}) -
- - {IS_USING_FALLBACK && ( -
-

System używa hasła awaryjnego zdefiniowanego w kodzie.

-
- )} -
- )} - +

- PromptStory v1.0 • Private Instance + PromptStory v1.2 • Secure Production Build

@@ -210,19 +184,11 @@ const App: React.FC = () => { if (saved) { try { const parsed = JSON.parse(saved); - // Reset files because File objects cannot be serialized to local storage - parsed.files = []; + parsed.files = []; // Reset files - // Ensure new fields exist if loading from old state if (!parsed.stats) parsed.stats = { distance: '', duration: '', elevation: '' }; if (!parsed.waypoints) parsed.waypoints = []; - - // Ensure tripData exists - if (!parsed.tripData) { - parsed.tripData = { ...INITIAL_STATE.tripData }; - } - - // Defaults for new fields if migrating + if (!parsed.tripData) parsed.tripData = { ...INITIAL_STATE.tripData }; if (!parsed.tone) parsed.tone = null; if (!parsed.goal) parsed.goal = null; if (!parsed.storyStyle) parsed.storyStyle = null; @@ -237,13 +203,11 @@ const App: React.FC = () => { useEffect(() => { if (isLoaded) { - // Exclude files from persistence to avoid quota issues and serialization errors const stateToSave = { ...data, files: [] }; localStorage.setItem(STORAGE_KEY, JSON.stringify(stateToSave)); } }, [data, isLoaded]); - // UPDATED: Now supports functional updates to prevent stale state issues const updateData = (updates: Partial | ((prev: WizardState) => Partial)) => { setData(prev => { const newValues = typeof updates === 'function' ? updates(prev) : updates; @@ -266,19 +230,23 @@ const App: React.FC = () => { const handleGenerate = async () => { setIsGenerating(true); setErrorMessage(null); + + // STRICT MODE: Use VITE_API_KEY + const apiKey = getEnvVar('VITE_API_KEY'); + + if (!apiKey) { + setErrorMessage("BŁĄD KRYTYCZNY: Brak klucza API (VITE_API_KEY). Skonfiguruj zmienne w panelu Coolify."); + setIsGenerating(false); + return; + } + try { - // SAFE ENV ACCESS - const apiKey = getEnvVar('API_KEY'); - const content = await generateStoryContent( - data, - apiKey || '' - ); - + const content = await generateStoryContent(data, apiKey); setGeneratedContent(content); updateData({ step: Step.RESULT }); } catch (error: any) { console.error("Generowanie nie powiodło się:", error); - setErrorMessage("Błąd generowania. Sprawdź poprawność klucza API w pliku .env oraz połączenie z siecią. " + (error.message || '')); + setErrorMessage("Błąd generowania: " + (error.message || 'Sprawdź konsolę')); } finally { setIsGenerating(false); } @@ -287,15 +255,11 @@ const App: React.FC = () => { const handleRegenerate = async (slideCount: number, feedback: string) => { setIsGenerating(true); setErrorMessage(null); + + const apiKey = getEnvVar('VITE_API_KEY'); + try { - // SAFE ENV ACCESS - const apiKey = getEnvVar('API_KEY'); - const content = await generateStoryContent( - data, - apiKey || '', - { slideCount, feedback } - ); - + const content = await generateStoryContent(data, apiKey || '', { slideCount, feedback }); setGeneratedContent(content); } catch (error: any) { console.error("Regenerowanie nie powiodło się:", error); @@ -309,24 +273,19 @@ const App: React.FC = () => { setData({ ...INITIAL_STATE }); setGeneratedContent(null); localStorage.removeItem(STORAGE_KEY); - // Force reload to clear any hung states window.location.reload(); }; - // --- RENDER LOGIC --- - - if (isAuthChecking || !isLoaded) return null; // Loading state + if (isAuthChecking || !isLoaded) return null; if (!isAuthenticated) { return ; } - // Step Labels for Progress Bar (Order Changed) const stepsLabels = ['Kontekst', 'Typ', 'Platforma', 'Vibe & Cel', 'Szczegóły']; return (
- {/* Header */}
@@ -357,8 +316,6 @@ const App: React.FC = () => {
- - {/* Progress Bar */} {data.step !== Step.RESULT && (
@@ -377,21 +334,11 @@ const App: React.FC = () => {
)} - {/* Dynamic Content Container */}
- {/* STEP 1: CONTEXT */} {data.step === Step.CONTEXT && } - - {/* STEP 2: EVENT TYPE (Moved UP) */} {data.step === Step.EVENT_TYPE && } - - {/* STEP 3: PLATFORM (Moved DOWN) */} {data.step === Step.PLATFORM && } - - {/* STEP 4: TONE & GOAL (NEW) */} {data.step === Step.TONE_GOAL && } - - {/* STEP 5: DETAILS */} {data.step === Step.DETAILS && ( { isGenerating={isGenerating} /> )} - - {/* STEP 6: RESULT */} {data.step === Step.RESULT && generatedContent && ( { /> )} - {/* Error Message */} {errorMessage && (
{errorMessage} @@ -419,7 +363,6 @@ const App: React.FC = () => { )}
- {/* Navigation Controls (Back Only) */} {data.step > Step.CONTEXT && data.step < Step.RESULT && (
@@ -436,11 +379,9 @@ const App: React.FC = () => { )}
- {/* Footer / Author Info */}