last
This commit is contained in:
@@ -2,9 +2,9 @@
|
|||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<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" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>atakan-portal</title>
|
<title>Atakan</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|||||||
BIN
public/logo.png
Normal file
BIN
public/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
@@ -4,16 +4,10 @@ import { useNavigate } from 'react-router-dom';
|
|||||||
import {
|
import {
|
||||||
Terminal, Globe, Shield, Database,
|
Terminal, Globe, Shield, Database,
|
||||||
Github, Twitter, Linkedin, Mail, Lock, X, ChevronRight, ExternalLink,
|
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';
|
} from 'lucide-react';
|
||||||
|
|
||||||
// --- KULLANICI ADI VE ŞİFRE AYARLARI ---
|
// --- YETENEKLER ---
|
||||||
const AUTH_CONFIG = {
|
|
||||||
username: "atakanzgn",
|
|
||||||
password: "atakanc123"
|
|
||||||
};
|
|
||||||
|
|
||||||
// --- YETENEKLER (Güncellendi) ---
|
|
||||||
const skills = [
|
const skills = [
|
||||||
{ name: "Java", icon: <Coffee size={20} />, desc: "Core & Enterprise" },
|
{ name: "Java", icon: <Coffee size={20} />, desc: "Core & Enterprise" },
|
||||||
{ name: "Spring Boot", icon: <Zap size={20} />, desc: "Microservices" },
|
{ name: "Spring Boot", icon: <Zap size={20} />, desc: "Microservices" },
|
||||||
@@ -50,16 +44,49 @@ export default function Home() {
|
|||||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||||
const [username, setUsername] = useState("");
|
const [username, setUsername] = useState("");
|
||||||
const [password, setPassword] = useState("");
|
const [password, setPassword] = useState("");
|
||||||
|
|
||||||
|
// Yeni State'ler
|
||||||
const [error, setError] = useState("");
|
const [error, setError] = useState("");
|
||||||
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const handleLogin = (e) => {
|
const API_URL = "https://api.atakanzgn.com.tr/login";
|
||||||
|
|
||||||
|
const handleLogin = async (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (username === AUTH_CONFIG.username && password === AUTH_CONFIG.password) {
|
setError("");
|
||||||
sessionStorage.setItem('isAuthenticated', 'true');
|
setIsLoading(true);
|
||||||
navigate('/portal');
|
|
||||||
} else {
|
try {
|
||||||
setError("Hatalı kullanıcı adı veya şifre!");
|
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 {
|
||||||
|
// 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Ü --- */}
|
{/* --- 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">
|
<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>
|
<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 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>
|
<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>
|
</motion.div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
{/* --- HAKKIMDA (Güncellendi) --- */}
|
{/* --- HAKKIMDA --- */}
|
||||||
<section id="about" className="py-20 px-6 bg-slate-900/50">
|
<section id="about" className="py-20 px-6 bg-slate-900/50">
|
||||||
<div className="max-w-4xl mx-auto">
|
<div className="max-w-4xl mx-auto">
|
||||||
<h2 className="text-3xl font-bold text-white mb-8 flex items-center gap-3">
|
<h2 className="text-3xl font-bold text-white mb-8 flex items-center gap-3">
|
||||||
@@ -144,7 +170,7 @@ export default function Home() {
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
{/* --- YETENEKLER (Güncellendi) --- */}
|
{/* --- YETENEKLER --- */}
|
||||||
<section id="skills" className="py-20 px-6">
|
<section id="skills" className="py-20 px-6">
|
||||||
<div className="max-w-6xl mx-auto">
|
<div className="max-w-6xl mx-auto">
|
||||||
<h2 className="text-3xl font-bold text-white mb-12 text-center">Teknik Yetkinlikler</h2>
|
<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>
|
<label className="block text-xs font-medium text-slate-400 mb-1">Kullanıcı Adı</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
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}
|
value={username}
|
||||||
onChange={(e) => setUsername(e.target.value)}
|
onChange={(e) => setUsername(e.target.value)}
|
||||||
|
disabled={isLoading}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-xs font-medium text-slate-400 mb-1">Şifre</label>
|
<label className="block text-xs font-medium text-slate-400 mb-1">Şifre</label>
|
||||||
<input
|
<input
|
||||||
type="password"
|
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}
|
value={password}
|
||||||
onChange={(e) => setPassword(e.target.value)}
|
onChange={(e) => setPassword(e.target.value)}
|
||||||
|
disabled={isLoading}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{error && <p className="text-red-400 text-xs">{error}</p>}
|
{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">
|
<button
|
||||||
Giriş Yap <ChevronRight size={16} />
|
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>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useEffect } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { motion } from 'framer-motion';
|
import { motion } from 'framer-motion';
|
||||||
import { GitBranch, Video, Mail, Cloud, Puzzle, ArrowRight, ArrowLeft, LogOut } from 'lucide-react';
|
import { GitBranch, Video, Mail, Cloud, Puzzle, ArrowRight, ArrowLeft, LogOut } from 'lucide-react';
|
||||||
import { Link, useNavigate } from 'react-router-dom';
|
import { Link, useNavigate } from 'react-router-dom';
|
||||||
@@ -23,17 +23,31 @@ const cardVariants = {
|
|||||||
|
|
||||||
export default function Portal() {
|
export default function Portal() {
|
||||||
const navigate = useNavigate();
|
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
|
// Sayfa yüklendiğinde güvenlik kontrolü yap
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const isAuth = sessionStorage.getItem('isAuthenticated');
|
// Backend'den aldığımız token'ı kontrol ediyoruz
|
||||||
if (isAuth !== 'true') {
|
const token = sessionStorage.getItem('authToken');
|
||||||
navigate('/'); // Giriş yoksa ana sayfaya at
|
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]);
|
}, [navigate]);
|
||||||
|
|
||||||
const handleLogout = () => {
|
const handleLogout = () => {
|
||||||
sessionStorage.removeItem('isAuthenticated');
|
sessionStorage.removeItem('authToken');
|
||||||
|
sessionStorage.removeItem('user');
|
||||||
navigate('/');
|
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">
|
<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>
|
<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>
|
||||||
|
|
||||||
<motion.div variants={containerVariants} initial="hidden" animate="visible" className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-5">
|
<motion.div variants={containerVariants} initial="hidden" animate="visible" className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-5">
|
||||||
|
|||||||
Reference in New Issue
Block a user