diff --git a/kittyurl-frontend/src/components/Generator.tsx b/kittyurl-frontend/src/components/Generator.tsx index 2cf64f2..9149ce1 100644 --- a/kittyurl-frontend/src/components/Generator.tsx +++ b/kittyurl-frontend/src/components/Generator.tsx @@ -2,7 +2,8 @@ import { PawPrint, Heart, Sparkles, Cat, Hash, Globe, BookOpen, Shield, Clock, - Settings2, AlertCircle, X, Save, RefreshCw, Copy, Check, ExternalLink, User as UserIcon + Settings2, AlertCircle, X, Save, RefreshCw, Copy, Check, ExternalLink, + User as UserIcon, Calendar, Hourglass } from 'lucide-react'; const API_BASE = import.meta.env.VITE_API_TARGET; @@ -10,6 +11,15 @@ const TOKEN_KEY = 'jwt_token'; type CaseType = 'upper' | 'lower' | 'mixed'; +// Mnożniki czasu w milisekundach +const TIME_MULTIPLIERS: Record = { + minutes: 60 * 1000, + hours: 60 * 60 * 1000, + days: 24 * 60 * 60 * 1000, + weeks: 7 * 24 * 60 * 60 * 1000, + months: 30 * 24 * 60 * 60 * 1000, // Przybliżenie +}; + interface GeneratorProps { url: string; setUrl: (url: string) => void; @@ -62,13 +72,17 @@ export const Generator: React.FC = ({ url, setUrl, onGenerate }) withSubdomain: false }); + // --- NOWE STANY DLA CZASU TRWANIA --- + const [expiryMode, setExpiryMode] = useState<'date' | 'duration'>('date'); + const [durationValue, setDurationValue] = useState(''); // Pusty string na start + const [durationUnit, setDurationUnit] = useState('minutes'); + const [loading, setLoading] = useState(false); const [generatingUri, setGeneratingUri] = useState(false); const [errorMsg, setErrorMsg] = useState(null); const [result, setResult] = useState(null); const [copied, setCopied] = useState(false); - // Obliczanie domeny bazowej i prefiksu do wyświetlenia w polu URI const baseDomain = API_BASE.replace('api.', '').replace(/^https?:\/\//, '').split('/')[0]; const displayPrefix = genSettings.withSubdomain && formData.subdomain ? `${formData.subdomain}.${baseDomain}` @@ -105,6 +119,30 @@ export const Generator: React.FC = ({ url, setUrl, onGenerate }) checkUser(); }, []); + // --- NOWY EFEKT: Przeliczanie czasu trwania na datę --- + // Uruchamia się automatycznie, gdy zmienisz liczbę, jednostkę lub tryb + useEffect(() => { + if (expiryMode === 'duration') { + const val = parseInt(durationValue); + if (!durationValue || isNaN(val) || val <= 0) { + // Jeśli pole jest puste lub 0, czyścimy datę wygaśnięcia + setFormData(prev => ({ ...prev, expiryDate: '' })); + return; + } + + const multiplier = TIME_MULTIPLIERS[durationUnit] || TIME_MULTIPLIERS.minutes; + const msToAdd = val * multiplier; + + const futureDate = new Date(Date.now() + msToAdd); + + // Formatowanie do datetime-local z uwzględnieniem strefy czasowej + const offset = futureDate.getTimezoneOffset() * 60000; + const localISOTime = new Date(futureDate.getTime() - offset).toISOString().slice(0, 16); + + setFormData(prev => ({ ...prev, expiryDate: localISOTime })); + } + }, [durationValue, durationUnit, expiryMode]); + const handleGenerateUri = async (type: 'random' | 'wordlist') => { setGeneratingUri(true); setErrorMsg(null); @@ -154,12 +192,10 @@ export const Generator: React.FC = ({ url, setUrl, onGenerate }) privacy: formData.privacy, }; - // Dodajemy subdomenę tylko jeśli jest włączona if (genSettings.withSubdomain && formData.subdomain) { payload.subdomain = formData.subdomain; } - // WYSYŁANIE DATY TYLKO JEŚLI JEST PODANA if (formData.expiryDate) { payload.expiryDate = new Date(formData.expiryDate).getTime(); } @@ -175,7 +211,6 @@ export const Generator: React.FC = ({ url, setUrl, onGenerate }) const data = await response.json(); if (!response.ok) throw new Error(data.error || `Error ${response.status}`); - // Budowanie końcowego linku do wyświetlenia (z subdomeną) let finalLink = data.url; if (!finalLink) { const protocol = API_BASE.startsWith('https') ? 'https://' : 'http://'; @@ -294,22 +329,18 @@ export const Generator: React.FC = ({ url, setUrl, onGenerate })
- {/* Dynamiczna domena przed / */}
{displayPrefix} /
- setFormData({ ...formData, uri: e.target.value })} /> - {formData.uri && (
@@ -321,18 +352,73 @@ export const Generator: React.FC = ({ url, setUrl, onGenerate }) {/* 3. Database Settings */}
- {/* Datetime input (Data + Godzina) */} -
- - setFormData({ ...formData, expiryDate: e.target.value })} - /> -

Optional: Leave empty for no expiry

+ + {/* ZMODYFIKOWANA SEKCJA: Expiry Date / Custom Duration */} +
+
+ + {/* Przełącznik trybu */} +
+ + +
+
+ + {expiryMode === 'date' ? ( + <> + setFormData({ ...formData, expiryDate: e.target.value })} + /> +

Pick specific date

+ + ) : ( + <> + {/* NOWE: Custom Duration Inputs dla Mobile */} +
+ setDurationValue(e.target.value)} + /> + +
+

+ {formData.expiryDate + ? `Expires: ${new Date(formData.expiryDate).toLocaleString()}` + : 'Enter duration (e.g. 45 min)'} +

+ + )}