This commit is contained in:
Atakan
2025-11-28 15:50:32 +03:00
parent 3e565663f7
commit 329b3df928
4 changed files with 80 additions and 29 deletions

View File

@@ -2,9 +2,9 @@
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<link rel="icon" type="image/png" href="/logo.png" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>atakan-portal</title>
<title>Atakan</title>
</head>
<body>
<div id="root"></div>

BIN
public/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View File

@@ -4,16 +4,10 @@ import { useNavigate } from 'react-router-dom';
import {
Terminal, Globe, Shield, Database,
Github, Twitter, Linkedin, Mail, Lock, X, ChevronRight, ExternalLink,
Coffee, Zap, Smartphone, Layers, Box, Server
Coffee, Zap, Smartphone, Layers, Box, Server, Loader2 // Loader2 eklendi
} from 'lucide-react';
// --- KULLANICI ADI VE ŞİFRE AYARLARI ---
const AUTH_CONFIG = {
username: "atakanzgn",
password: "atakanc123"
};
// --- YETENEKLER (Güncellendi) ---
// --- YETENEKLER ---
const skills = [
{ name: "Java", icon: <Coffee size={20} />, desc: "Core & Enterprise" },
{ name: "Spring Boot", icon: <Zap size={20} />, desc: "Microservices" },
@@ -50,16 +44,49 @@ export default function Home() {
const [isModalOpen, setIsModalOpen] = useState(false);
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
// Yeni State'ler
const [error, setError] = useState("");
const [isLoading, setIsLoading] = useState(false);
const navigate = useNavigate();
const handleLogin = (e) => {
const API_URL = "https://api.atakanzgn.com.tr/login";
const handleLogin = async (e) => {
e.preventDefault();
if (username === AUTH_CONFIG.username && password === AUTH_CONFIG.password) {
sessionStorage.setItem('isAuthenticated', 'true');
setError("");
setIsLoading(true);
try {
const response = await fetch(API_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
username: username,
password: password
}),
});
const data = await response.json();
if (response.ok) {
// Başarılı giriş: Token'ı sakla
// Backend'den { token: "..." } veya { accessToken: "..." } döndüğünü varsayıyoruz.
sessionStorage.setItem('authToken', data.token || data.accessToken);
sessionStorage.setItem('user', JSON.stringify(data.user)); // Opsiyonel: Kullanıcı bilgisini sakla
navigate('/portal');
} else {
setError("Hatalı kullanıcı adı veya şifre!");
// Backend'den gelen hata mesajını göster
setError(data.message || "Giriş başarısız. Bilgileri kontrol edin.");
}
} catch (err) {
console.error("Login hatası:", err);
setError("Sunucuya bağlanılamadı. Lütfen daha sonra tekrar deneyin.");
} finally {
setIsLoading(false);
}
};
@@ -99,7 +126,6 @@ export default function Home() {
{/* --- HERO BÖLÜMÜ --- */}
<section className="relative pt-40 pb-20 px-6 flex flex-col items-center justify-center text-center min-h-screen">
<div className="absolute inset-0 bg-[url('https://grainy-gradients.vercel.app/noise.svg')] opacity-20 brightness-100 pointer-events-none"></div>
{/* Renkleri Java/Backend temasına uygun (Turuncu/Kırmızı) güncelledim */}
<div className="absolute top-1/3 left-1/4 w-96 h-96 bg-orange-600/20 rounded-full blur-[100px] -z-10"></div>
<div className="absolute bottom-1/4 right-1/4 w-96 h-96 bg-red-600/20 rounded-full blur-[100px] -z-10"></div>
@@ -124,7 +150,7 @@ export default function Home() {
</motion.div>
</section>
{/* --- HAKKIMDA (Güncellendi) --- */}
{/* --- HAKKIMDA --- */}
<section id="about" className="py-20 px-6 bg-slate-900/50">
<div className="max-w-4xl mx-auto">
<h2 className="text-3xl font-bold text-white mb-8 flex items-center gap-3">
@@ -144,7 +170,7 @@ export default function Home() {
</div>
</section>
{/* --- YETENEKLER (Güncellendi) --- */}
{/* --- YETENEKLER --- */}
<section id="skills" className="py-20 px-6">
<div className="max-w-6xl mx-auto">
<h2 className="text-3xl font-bold text-white mb-12 text-center">Teknik Yetkinlikler</h2>
@@ -240,25 +266,35 @@ export default function Home() {
<label className="block text-xs font-medium text-slate-400 mb-1">Kullanıcı Adı</label>
<input
type="text"
className="w-full bg-slate-800 border border-slate-700 rounded-lg p-2.5 text-white focus:outline-none focus:border-orange-500 transition-colors"
className="w-full bg-slate-800 border border-slate-700 rounded-lg p-2.5 text-white focus:outline-none focus:border-orange-500 transition-colors disabled:opacity-50"
value={username}
onChange={(e) => setUsername(e.target.value)}
disabled={isLoading}
/>
</div>
<div>
<label className="block text-xs font-medium text-slate-400 mb-1">Şifre</label>
<input
type="password"
className="w-full bg-slate-800 border border-slate-700 rounded-lg p-2.5 text-white focus:outline-none focus:border-orange-500 transition-colors"
className="w-full bg-slate-800 border border-slate-700 rounded-lg p-2.5 text-white focus:outline-none focus:border-orange-500 transition-colors disabled:opacity-50"
value={password}
onChange={(e) => setPassword(e.target.value)}
disabled={isLoading}
/>
</div>
{error && <p className="text-red-400 text-xs">{error}</p>}
<button type="submit" className="w-full bg-orange-600 hover:bg-orange-700 text-white font-medium py-2.5 rounded-lg transition-colors flex justify-center items-center gap-2">
Giriş Yap <ChevronRight size={16} />
<button
type="submit"
disabled={isLoading}
className="w-full bg-orange-600 hover:bg-orange-700 disabled:bg-slate-700 disabled:cursor-not-allowed text-white font-medium py-2.5 rounded-lg transition-colors flex justify-center items-center gap-2"
>
{isLoading ? (
<><Loader2 className="animate-spin" size={16} /> Giriş Yapılıyor...</>
) : (
<><span className='mr-1'>Giriş Yap</span> <ChevronRight size={16} /></>
)}
</button>
</form>
</motion.div>

View File

@@ -1,4 +1,4 @@
import React, { useEffect } from 'react';
import React, { useEffect, useState } from 'react';
import { motion } from 'framer-motion';
import { GitBranch, Video, Mail, Cloud, Puzzle, ArrowRight, ArrowLeft, LogOut } from 'lucide-react';
import { Link, useNavigate } from 'react-router-dom';
@@ -23,17 +23,31 @@ const cardVariants = {
export default function Portal() {
const navigate = useNavigate();
// Kullanıcı adını state'ten veya storage'dan alalım
const [user, setUser] = useState({ name: "Atakan" });
// Sayfa yüklendiğinde güvenlik kontrolü yap
useEffect(() => {
const isAuth = sessionStorage.getItem('isAuthenticated');
if (isAuth !== 'true') {
navigate('/'); // Giriş yoksa ana sayfaya at
// Backend'den aldığımız token'ı kontrol ediyoruz
const token = sessionStorage.getItem('authToken');
const userData = sessionStorage.getItem('user');
if (!token) {
navigate('/'); // Token yoksa ana sayfaya at
}
if (userData) {
try {
setUser(JSON.parse(userData));
} catch (e) {
// JSON parse hatası olursa varsayılan kalır
}
}
}, [navigate]);
const handleLogout = () => {
sessionStorage.removeItem('isAuthenticated');
sessionStorage.removeItem('authToken');
sessionStorage.removeItem('user');
navigate('/');
};
@@ -54,7 +68,8 @@ export default function Portal() {
<motion.div initial={{ opacity: 0, y: -20 }} animate={{ opacity: 1, y: 0 }} className="text-center mb-12">
<h1 className="text-4xl md:text-5xl font-bold mb-2 text-white">Yönetim Portalı</h1>
<p className="text-slate-400">Hoş geldin, Atakan. Servisler aktif.</p>
{/* Kullanıcı adını dinamik gösterelim */}
<p className="text-slate-400">Hoş geldin, {user.username || user.name || "Admin"}. Servisler aktif.</p>
</motion.div>
<motion.div variants={containerVariants} initial="hidden" animate="visible" className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-5">