main
UI Deploy (Next-Auth Support) 🎨 / build-and-deploy (push) Has been cancelled

This commit is contained in:
Harun CAN
2026-04-30 13:46:23 +02:00
parent 5144ee4d9a
commit 1b980f637b
3 changed files with 439 additions and 128 deletions
@@ -1,7 +1,7 @@
'use client';
import { useParams, useRouter } from 'next/navigation';
import { motion } from 'framer-motion';
import { motion, AnimatePresence } from 'framer-motion';
import {
ArrowLeft,
Play,
@@ -16,6 +16,7 @@ import {
Trash2,
MoreVertical,
X,
Languages,
} from 'lucide-react';
import Link from 'next/link';
import { useState, useEffect } from 'react';
@@ -34,8 +35,10 @@ import { useRenderProgress } from '@/hooks/use-render-progress';
import { SceneCard } from '@/components/project/scene-card';
import { RenderProgress } from '@/components/project/render-progress';
import { VideoPlayer } from '@/components/project/video-player';
import { projectsApi } from '@/lib/api/api-service';
import { projectsApi, apiClient } from '@/lib/api/api-service';
import { CINEMATIC_REFERENCES } from '@/constants/cinematic-references';
import { languages } from '@/components/projects/ProjectConfiguration';
import { toast } from 'sonner';
// X (Twitter) ikonunu burada da tanımlıyoruz
const XIcon = ({ size = 16 }: { size?: number }) => (
@@ -126,6 +129,27 @@ export default function ProjectDetailPage() {
const [showMenu, setShowMenu] = useState(false);
const [regeneratingSceneId, setRegeneratingSceneId] = useState<string | null>(null);
const [mounted, setMounted] = useState(false);
const [showTranslateModal, setShowTranslateModal] = useState(false);
const [targetLanguage, setTargetLanguage] = useState<string>("");
const [isTranslating, setIsTranslating] = useState(false);
const confirmTranslate = async () => {
if (!id || !targetLanguage) return;
try {
setIsTranslating(true);
const res = await apiClient.post(`/projects/${id}/translate`, { targetLanguage });
toast.success("Proje başarıyla çevrildi!");
setShowTranslateModal(false);
setTargetLanguage("");
// refetch() to maybe update some states, or router.push to the new project
router.push(`/dashboard/projects/${res.data.id}`);
} catch (err: any) {
toast.error(err?.response?.data?.message || "Çeviri sırasında bir hata oluştu.");
} finally {
setIsTranslating(false);
}
};
useEffect(() => {
setMounted(true);
@@ -328,6 +352,12 @@ export default function ProjectDetailPage() {
>
<RefreshCw size={14} /> Yenile
</button>
<button
onClick={() => { setShowMenu(false); setShowTranslateModal(true); }}
className="w-full flex items-center gap-2 px-3 py-2 text-sm text-[var(--color-text-secondary)] hover:bg-[var(--color-bg-elevated)] rounded-lg transition-colors"
>
<Languages size={14} /> Çevir
</button>
<button
onClick={() => { handleDelete(); setShowMenu(false); }}
className="w-full flex items-center gap-2 px-3 py-2 text-sm text-red-400 hover:bg-red-500/10 rounded-lg transition-colors"
@@ -672,6 +702,93 @@ export default function ProjectDetailPage() {
</div>
</motion.div>
)}
{/* ─── Çeviri Modal ─── */}
<AnimatePresence>
{showTranslateModal && (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
transition={{ duration: 0.15 }}
className="fixed inset-0 z-50 flex items-center justify-center bg-black/60 backdrop-blur-sm"
onClick={() => !isTranslating && setShowTranslateModal(false)}
>
<motion.div
initial={{ opacity: 0, scale: 0.95, y: 10 }}
animate={{ opacity: 1, scale: 1, y: 0 }}
exit={{ opacity: 0, scale: 0.95, y: 10 }}
transition={{ duration: 0.2, ease: [0.16, 1, 0.3, 1] }}
className="relative bg-[var(--color-bg-elevated)] border border-[var(--color-border-default)] rounded-2xl p-6 max-w-sm w-full mx-4 shadow-2xl"
onClick={(e) => e.stopPropagation()}
>
{/* Kapatma butonu */}
<button
onClick={() => setShowTranslateModal(false)}
disabled={isTranslating}
className="absolute top-3 right-3 p-1 rounded-lg text-[var(--color-text-ghost)] hover:text-[var(--color-text-secondary)] hover:bg-[var(--color-bg-surface)] transition-colors disabled:opacity-50"
>
<X size={16} />
</button>
{/* Icon */}
<div className="flex items-center justify-center w-12 h-12 rounded-full bg-blue-500/10 mb-4">
<Languages size={22} className="text-blue-400" />
</div>
{/* İçerik */}
<h3 className="text-base font-semibold text-[var(--color-text-primary)] mb-1.5">
Projeyi Çevir
</h3>
<p className="text-sm text-[var(--color-text-muted)] mb-3">
"{project?.title}" projesini başka bir dile çevirin. (1 kredi)
</p>
<select
value={targetLanguage}
onChange={(e) => setTargetLanguage(e.target.value)}
disabled={isTranslating}
className="w-full bg-[var(--color-bg-surface)] border border-[var(--color-border-default)] rounded-xl px-4 py-2.5 text-sm text-[var(--color-text-primary)] mb-5 outline-none focus:border-blue-500"
>
<option value="">Dil Seçin...</option>
{languages.map((lang) => (
<option key={lang.code} value={lang.code}>
{lang.flag} {lang.label}
</option>
))}
</select>
{/* Butonlar */}
<div className="flex items-center gap-3">
<button
onClick={() => setShowTranslateModal(false)}
disabled={isTranslating}
className="flex-1 px-4 py-2.5 rounded-xl border border-[var(--color-border-default)] text-sm font-medium text-[var(--color-text-secondary)] hover:bg-[var(--color-bg-surface)] transition-colors disabled:opacity-50"
>
İptal
</button>
<button
onClick={confirmTranslate}
disabled={isTranslating || !targetLanguage}
className="flex-1 flex items-center justify-center gap-2 px-4 py-2.5 rounded-xl bg-blue-500 hover:bg-blue-600 text-white text-sm font-medium transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
>
{isTranslating ? (
<>
<Loader2 size={14} className="animate-spin" />
Çevriliyor...
</>
) : (
<>
<Languages size={14} />
Çevir (1 🪙)
</>
)}
</button>
</div>
</motion.div>
</motion.div>
)}
</AnimatePresence>
</motion.div>
);
}