dodanie hasla i poprawki
This commit is contained in:
185
App.tsx
185
App.tsx
@@ -7,10 +7,31 @@ import StepEventType from './components/StepEventType';
|
||||
import StepToneGoal from './components/StepToneGoal';
|
||||
import StepDetails from './components/StepDetails';
|
||||
import StepResult from './components/StepResult';
|
||||
import { ChevronLeft, ExternalLink, Sparkles, User } from 'lucide-react';
|
||||
import { ChevronLeft, ExternalLink, Sparkles, User, Lock, ArrowRight, AlertCircle, Bug } from 'lucide-react';
|
||||
import { generateStoryContent } from './services/geminiService';
|
||||
|
||||
const STORAGE_KEY = 'gpx-storyteller-state-v6'; // Incremented version for structure change
|
||||
const AUTH_KEY = 'promptstory-auth-token';
|
||||
|
||||
// --- PASSWORD CONFIGURATION ---
|
||||
|
||||
// 1. Try fetching from Vite standard (import.meta.env)
|
||||
// @ts-ignore
|
||||
const VITE_ENV_PASS = import.meta.env && import.meta.env.VITE_APP_PASSWORD ? import.meta.env.VITE_APP_PASSWORD : '';
|
||||
|
||||
// 2. Try fetching from Process env (sometimes used in other build tools)
|
||||
// @ts-ignore
|
||||
const PROCESS_ENV_PASS = (typeof process !== 'undefined' && process.env && process.env.VITE_APP_PASSWORD) ? process.env.VITE_APP_PASSWORD : '';
|
||||
|
||||
// 3. Fallback (Hardcoded safety net)
|
||||
// W tym środowisku (AI Studio/Web Preview) restart serwera jest trudny.
|
||||
// Ustawiamy hasło "na sztywno" jako zapas, żeby działało od razu.
|
||||
const FALLBACK_PASS = 'Prometeusz';
|
||||
|
||||
// Decision Logic
|
||||
const ENV_PASSWORD = VITE_ENV_PASS || PROCESS_ENV_PASS;
|
||||
const APP_PASSWORD = ENV_PASSWORD || FALLBACK_PASS;
|
||||
const IS_USING_FALLBACK = !ENV_PASSWORD;
|
||||
|
||||
const INITIAL_STATE: WizardState = {
|
||||
step: Step.CONTEXT,
|
||||
@@ -38,7 +59,131 @@ const INITIAL_STATE: WizardState = {
|
||||
}
|
||||
};
|
||||
|
||||
// --- LOGIN SCREEN COMPONENT ---
|
||||
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 VITE_ENV:", VITE_ENV_PASS ? "****" : "(empty)");
|
||||
console.log("2. Detected PROCESS_ENV:", PROCESS_ENV_PASS ? "****" : "(empty)");
|
||||
console.log("3. Final Password Source:", IS_USING_FALLBACK ? "FALLBACK (Hardcoded)" : ".ENV FILE");
|
||||
console.log("4. Active Password Length:", APP_PASSWORD.length);
|
||||
console.groupEnd();
|
||||
}, []);
|
||||
|
||||
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('');
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-50 flex flex-col items-center justify-center p-4">
|
||||
<div className="bg-white p-8 rounded-xl shadow-lg border border-gray-100 max-w-md w-full text-center space-y-6 animate-fade-in relative">
|
||||
|
||||
{/* Debug Toggle (Hidden in corner) */}
|
||||
<button
|
||||
onClick={() => setShowDebug(!showDebug)}
|
||||
className="absolute top-2 right-2 text-gray-200 hover:text-gray-400 p-2"
|
||||
title="Pokaż informacje debugowania"
|
||||
>
|
||||
<Bug size={16} />
|
||||
</button>
|
||||
|
||||
<div className="flex justify-center mb-2">
|
||||
<div className="bg-[#EA4420]/10 p-4 rounded-full text-[#EA4420]">
|
||||
<Lock size={32} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h2 className="text-2xl font-bold text-gray-900">Dostęp Chroniony</h2>
|
||||
<p className="text-gray-500 mt-2">Wprowadź hasło, aby uzyskać dostęp do kreatora PromptStory.</p>
|
||||
</div>
|
||||
|
||||
<form onSubmit={handleSubmit} className="space-y-4">
|
||||
<div className="relative">
|
||||
<input
|
||||
type="password"
|
||||
value={input}
|
||||
onChange={(e) => {
|
||||
setInput(e.target.value);
|
||||
setError(false);
|
||||
}}
|
||||
placeholder="Hasło..."
|
||||
className={`w-full p-4 border rounded-lg outline-none transition-all font-medium text-center tracking-widest ${
|
||||
error
|
||||
? 'border-red-300 bg-red-50 focus:border-red-500'
|
||||
: 'border-gray-200 focus:border-[#EA4420] focus:ring-1 focus:ring-[#EA4420]'
|
||||
}`}
|
||||
autoFocus
|
||||
/>
|
||||
</div>
|
||||
|
||||
{error && (
|
||||
<div className="flex items-center justify-center gap-2 text-red-500 text-sm font-medium animate-pulse">
|
||||
<AlertCircle size={16} />
|
||||
<span>Nieprawidłowe hasło</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
className="w-full bg-[#EA4420] text-white py-4 rounded-lg font-bold hover:bg-[#d63b1a] transition-colors flex items-center justify-center gap-2"
|
||||
>
|
||||
<span>Odblokuj</span>
|
||||
<ArrowRight size={20} />
|
||||
</button>
|
||||
</form>
|
||||
|
||||
{/* DEBUG PANEL */}
|
||||
{showDebug && (
|
||||
<div className="bg-gray-800 text-left text-green-400 p-4 rounded-md text-xs font-mono mt-4 overflow-hidden">
|
||||
<p className="font-bold border-b border-gray-600 mb-2 pb-1 text-white">DEBUG STATUS:</p>
|
||||
|
||||
<div className="grid grid-cols-2 gap-x-4 gap-y-1 mt-2">
|
||||
<span className="text-gray-400">SOURCE:</span>
|
||||
<span className={IS_USING_FALLBACK ? "text-yellow-400 font-bold" : "text-green-400 font-bold"}>
|
||||
{IS_USING_FALLBACK ? "FALLBACK (Code)" : ".ENV FILE"}
|
||||
</span>
|
||||
|
||||
<span className="text-gray-400">ACTIVE PASS:</span>
|
||||
<span>{APP_PASSWORD.substring(0, 4)}... (len: {APP_PASSWORD.length})</span>
|
||||
</div>
|
||||
|
||||
{IS_USING_FALLBACK && (
|
||||
<div className="mt-3 text-yellow-500 border-t border-gray-600 pt-2">
|
||||
<p>System używa hasła awaryjnego zdefiniowanego w kodzie, ponieważ nie może odświeżyć pliku .env bez restartu.</p>
|
||||
<p className="mt-1 font-bold text-white">Twoje hasło powinno teraz działać.</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<p className="text-xs text-gray-300 pt-4">
|
||||
PromptStory v1.0 • Private Instance
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const App: React.FC = () => {
|
||||
// Auth State
|
||||
const [isAuthenticated, setIsAuthenticated] = useState(false);
|
||||
const [isAuthChecking, setIsAuthChecking] = useState(true);
|
||||
|
||||
// App State
|
||||
const [data, setData] = useState<WizardState>(INITIAL_STATE);
|
||||
const [generatedContent, setGeneratedContent] = useState<GeneratedContent | null>(null);
|
||||
const [isGenerating, setIsGenerating] = useState(false);
|
||||
@@ -49,7 +194,29 @@ const App: React.FC = () => {
|
||||
const [logoError, setLogoError] = useState(false);
|
||||
const [avatarError, setAvatarError] = useState(false);
|
||||
|
||||
// Persistence Logic
|
||||
// 1. Check Auth on Mount
|
||||
useEffect(() => {
|
||||
const storedAuth = localStorage.getItem(AUTH_KEY);
|
||||
if (storedAuth === 'true') {
|
||||
setIsAuthenticated(true);
|
||||
}
|
||||
setIsAuthChecking(false);
|
||||
}, []);
|
||||
|
||||
const handleLogin = (success: boolean) => {
|
||||
if (success) {
|
||||
localStorage.setItem(AUTH_KEY, 'true');
|
||||
setIsAuthenticated(true);
|
||||
}
|
||||
};
|
||||
|
||||
const handleLogout = () => {
|
||||
localStorage.removeItem(AUTH_KEY);
|
||||
setIsAuthenticated(false);
|
||||
resetApp();
|
||||
};
|
||||
|
||||
// 2. Load Data Persistence Logic
|
||||
useEffect(() => {
|
||||
const saved = localStorage.getItem(STORAGE_KEY);
|
||||
if (saved) {
|
||||
@@ -154,7 +321,13 @@ const App: React.FC = () => {
|
||||
window.location.reload();
|
||||
};
|
||||
|
||||
if (!isLoaded) return null;
|
||||
// --- RENDER LOGIC ---
|
||||
|
||||
if (isAuthChecking || !isLoaded) return null; // Loading state
|
||||
|
||||
if (!isAuthenticated) {
|
||||
return <LoginScreen onLogin={handleLogin} />;
|
||||
}
|
||||
|
||||
// Step Labels for Progress Bar (Order Changed)
|
||||
const stepsLabels = ['Kontekst', 'Typ', 'Platforma', 'Vibe & Cel', 'Szczegóły'];
|
||||
@@ -179,9 +352,15 @@ const App: React.FC = () => {
|
||||
)}
|
||||
<h1 className="text-xl font-bold tracking-tight text-gray-900">PromptStory</h1>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-4">
|
||||
<button onClick={resetApp} className="text-xs font-medium text-gray-400 hover:text-[#EA4420] transition-colors uppercase tracking-wide">
|
||||
Resetuj
|
||||
</button>
|
||||
<button onClick={handleLogout} className="text-xs font-medium text-gray-400 hover:text-red-500 transition-colors uppercase tracking-wide">
|
||||
Wyloguj
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user