import React, { useState, useEffect } from 'react'; import axios from 'axios'; import { useAuth } from '../AuthContext'; import { Save, Key, Shield, User, ArrowLeft, CreditCard, Upload, Image as ImageIcon } from 'lucide-react'; import { useNavigate } from 'react-router-dom'; import { Layout } from '../components/Layout'; import { ProductType } from '../types'; import { Tag } from 'lucide-react'; const SettingsPage: React.FC = () => { const { user, refreshUser } = useAuth(); const navigate = useNavigate(); const [apiKey, setApiKey] = useState(''); const [savedKeyMasked, setSavedKeyMasked] = useState(null); const [etsyShopName, setEtsyShopName] = useState(''); const [etsyShopLink, setEtsyShopLink] = useState(''); const [etsyShopLogo, setEtsyShopLogo] = useState(null); const [loading, setLoading] = useState(false); const [brandingLoading, setBrandingLoading] = useState(false); const [logoUploading, setLogoUploading] = useState(false); const [message, setMessage] = useState<{ type: 'success' | 'error', text: string } | null>(null); // SKU State const [skuConfig, setSkuConfig] = useState>({}); const [skuLoading, setSkuLoading] = useState(false); const PRODUCT_TYPES: ProductType[] = ["Wall Art", "Bookmark", "Sticker", "Planner", "Phone Wallpaper", "Social Media Kit", "Label"]; useEffect(() => { fetchApiKey(); fetchBranding(); // Check local storage for migration const localKey = localStorage.getItem('gemini_api_key'); if (localKey && !apiKey && !savedKeyMasked) { setApiKey(localKey); } }, []); const fetchApiKey = async () => { try { const token = localStorage.getItem('token'); const res = await axios.get('/api/user/apikey', { headers: { Authorization: `Bearer ${token}` } }); if (res.data.apiKey) { setSavedKeyMasked(res.data.apiKey); } } catch (err) { console.error("Failed to fetch key", err); } }; const fetchBranding = async () => { try { const token = localStorage.getItem('token'); const res = await axios.get('/api/user/branding', { headers: { Authorization: `Bearer ${token}` } }); setEtsyShopName(res.data.etsyShopName || ''); setEtsyShopLink(res.data.etsyShopLink || ''); setEtsyShopLogo(res.data.etsyShopLogo || null); } catch (err) { console.error("Failed to fetch branding", err); } }; useEffect(() => { if (user) { setEtsyShopName(user.etsyShopName || ''); setEtsyShopLink(user.etsyShopLink || ''); setEtsyShopLogo(user.etsyShopLogo || null); if (user.apiKey) setSavedKeyMasked(user.apiKey.replace(/.(?=.{4})/g, '*')); try { if (user.skuSettings) { setSkuConfig(JSON.parse(user.skuSettings)); } } catch (e) { } } }, [user]); const handleSaveSku = async () => { setSkuLoading(true); setMessage(null); try { const token = localStorage.getItem('token'); await axios.post('/api/user/sku', { skuSettings: JSON.stringify(skuConfig) }, { headers: { Authorization: `Bearer ${token}` } }); setMessage({ type: 'success', text: 'SKU Settings saved successfully.' }); await refreshUser(); } catch (error: any) { setMessage({ type: 'error', text: error.response?.data?.error || 'Failed to save SKU settings.' }); } finally { setSkuLoading(false); } }; const handleSaveKey = async () => { setLoading(true); setMessage(null); try { const token = localStorage.getItem('token'); await axios.post('/api/user/apikey', { apiKey }, { headers: { Authorization: `Bearer ${token}` } }); setMessage({ type: 'success', text: 'API Key saved securely to your profile.' }); setSavedKeyMasked(`${apiKey.substring(0, 4)}...${apiKey.substring(apiKey.length - 4)}`); setApiKey(''); // Clear input for security // Also update local storage for redundancy if needed, or clear it to enforce server side? // Let's keep it in sync for now as a fallback if we revert logic. localStorage.setItem('gemini_api_key', apiKey); } catch (err: any) { setMessage({ type: 'error', text: err.response?.data?.error || 'Failed to save key' }); } finally { setLoading(false); } }; const handleSaveBranding = async () => { setBrandingLoading(true); setMessage(null); try { const token = localStorage.getItem('token'); await axios.post('/api/user/branding', { etsyShopName, etsyShopLink }, { headers: { Authorization: `Bearer ${token}` } }); setMessage({ type: 'success', text: 'Store branding updated successfully.' }); await refreshUser(); // Update global context field } catch (err: any) { setMessage({ type: 'error', text: err.response?.data?.error || 'Failed to update branding' }); } finally { setBrandingLoading(false); } }; const handleGodMode = async () => { try { const token = localStorage.getItem('token'); const res = await axios.post('http://localhost:3001/api/admin/grant-me-god-mode', {}, { headers: { Authorization: `Bearer ${token}` } }); if (res.data.token) { localStorage.setItem('token', res.data.token); // Force update context if possible, or just reload } alert(res.data.message); window.location.reload(); } catch (err: any) { console.error(err); alert(err.response?.data?.error || "Failed to grant God Mode"); } }; return (

Account Settings

Manage your profile and API security.

{/* Profile Card */}

{user?.email}

{user?.role} {user?.plan} Plan

Available Credits

{user?.credits}

{/* API Key Management */}

Gemini API Key

Beta Mode Requirement: Your personal request key is now stored securely in your profile. This allows us to process your requests on our servers without you needing to re-enter it on every device.

setApiKey(e.target.value)} placeholder={savedKeyMasked ? `Current: ${savedKeyMasked}` : "Paste your Google Gemini API Key here"} className="w-full px-4 py-2 border border-stone-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:outline-none" /> {savedKeyMasked && !apiKey && ( Securely Saved )}

Get your key from Google AI Studio.

{message && (
{message.text}
)}
{/* Store Branding */}

Store Branding

setEtsyShopName(e.target.value)} placeholder="e.g. MyAmazingStudio" className="w-full px-4 py-2 border border-stone-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:outline-none" />
setEtsyShopLink(e.target.value)} placeholder="https://www.etsy.com/shop/..." className="w-full px-4 py-2 border border-stone-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:outline-none" />
{/* Logo Upload Section */}
{etsyShopLogo ? ( Shop Logo ) : ( )} {logoUploading && (
)}

Recommended: 500x500px, PNG or JPG.

{/* SKU MANAGEMENT */}

SKU Configuration

Set up prefixes and starting numbers for automatic SKU generation (e.g., WLR105).

{PRODUCT_TYPES.map((type) => { const config = skuConfig[type] || { prefix: '', next: 1 }; return ( ); })}
Product Type Prefix (3-4 Chars) Next Number
{type} { const val = e.target.value.toUpperCase().replace(/[^A-Z]/g, ''); setSkuConfig(prev => ({ ...prev, [type]: { ...prev[type], prefix: val, next: prev[type]?.next || 1 } })); }} className="w-24 px-2 py-1 border border-stone-300 rounded font-mono uppercase focus:ring-2 focus:ring-emerald-500 focus:outline-none" /> { const val = parseInt(e.target.value) || 1; setSkuConfig(prev => ({ ...prev, [type]: { ...prev[type], prefix: prev[type]?.prefix || '', next: val } })); }} className="w-24 px-2 py-1 border border-stone-300 rounded font-mono focus:ring-2 focus:ring-emerald-500 focus:outline-none" />

Emergency Admin Access

If you are unable to access admin features or are stuck with credit limits, use this button to force-upgrade your account to ADMIN status.

); }; export default SettingsPage;