mobil uyumu

This commit is contained in:
2026-03-18 15:42:02 +03:00
parent 0bbfa2f636
commit a50fd188df
9 changed files with 178 additions and 109 deletions
+7 -27
View File
@@ -1,6 +1,7 @@
import { createClient } from '@/utils/supabase/server'
import { addCompany, deleteCompany } from './actions'
import { deleteCompany } from './actions'
import { BuildingOfficeIcon, TrashIcon } from '@heroicons/react/24/outline'
import CompanyForm from '@/components/companies/CompanyForm'
export default async function CompaniesPage() {
const supabase = await createClient()
@@ -39,31 +40,7 @@ export default async function CompaniesPage() {
<p>Personelleri atayabilmek için öncelikle şirket kaydı açmalısınız.</p>
</div>
<form
action={async (formData) => {
'use server';
await addCompany(formData);
}}
className="mt-5 space-y-4"
>
<div>
<label htmlFor="name" className="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">Şirket Adı</label>
<input
type="text"
name="name"
id="name"
required
className="block w-full rounded-2xl border-0 py-3 px-4 text-slate-900 shadow-sm ring-1 ring-inset ring-slate-200 dark:ring-zinc-700 dark:bg-zinc-800 dark:text-white placeholder:text-slate-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm outline-none transition-all"
placeholder="Abisena Ltd. Şti."
/>
</div>
<button
type="submit"
className="inline-flex w-full items-center justify-center rounded-2xl bg-indigo-600 px-4 py-3 text-sm font-bold text-white shadow-sm shadow-indigo-100 dark:shadow-none hover:bg-indigo-700 transition-all active:scale-95"
>
Şirket Kaydet
</button>
</form>
<CompanyForm />
</div>
</div>
@@ -96,7 +73,10 @@ export default async function CompaniesPage() {
<td className="relative whitespace-nowrap py-4 pl-3 pr-4 text-right text-sm font-medium sm:pr-6">
<form action={async () => {
'use server';
await deleteCompany(company.id)
const res = await deleteCompany(company.id);
if (res.error) {
alert(res.error);
}
}}>
<button type="submit" className="text-slate-400 hover:text-rose-600 dark:hover:text-rose-400 p-2 rounded-2xl hover:bg-rose-50 dark:hover:bg-rose-500/10 transition-all" title="Sil">
<TrashIcon className="h-5 w-5" />
+5 -3
View File
@@ -1,10 +1,12 @@
import { login } from './actions'
export default function LoginPage({
export default async function LoginPage({
searchParams,
}: {
searchParams: { error?: string }
searchParams: Promise<{ error?: string }>
}) {
const params = await searchParams;
return (
<div className="flex min-h-screen flex-col items-center justify-center p-6 bg-slate-50 dark:bg-zinc-950">
<div className="w-full max-w-md p-10 space-y-10 bg-white dark:bg-zinc-900 rounded-[2.5rem] shadow-sm border border-slate-100 dark:border-zinc-800">
@@ -19,7 +21,7 @@ export default function LoginPage({
</div>
<form className="space-y-8" action={login}>
{searchParams?.error && (
{params?.error && (
<div className="p-4 text-sm font-bold text-rose-600 bg-rose-50 dark:bg-rose-500/10 border border-rose-100 dark:border-rose-500/20 rounded-2xl text-center">
E-posta adresi veya şifre hatalı.
</div>
+6 -6
View File
@@ -22,15 +22,15 @@ export default async function SettingsPage() {
return (
<div className="space-y-10">
{/* Header */}
<div className="flex items-center gap-4">
<div className="w-1.5 h-12 bg-[#173363] rounded-full" />
<div className="flex items-center gap-4 px-4 sm:px-0">
<div className="w-1.5 h-10 sm:h-12 bg-[#173363] rounded-full" />
<div>
<h1 className="text-4xl font-black text-slate-900 dark:text-white tracking-tight flex items-center gap-3">
<Cog6ToothIcon className="w-10 h-10 text-[#173363]" />
<h1 className="text-2xl sm:text-4xl font-black text-slate-900 dark:text-white tracking-tight flex items-center gap-2 sm:gap-3">
<Cog6ToothIcon className="w-6 h-6 sm:w-10 sm:h-10 text-[#173363]" />
Sistem Ayarları
</h1>
<p className="text-sm font-bold text-slate-400 mt-1 uppercase tracking-widest">
Personel kartı veri tanımlamaları ve konfigürasyon
<p className="text-[10px] sm:text-sm font-bold text-slate-400 mt-1 uppercase tracking-widest leading-relaxed">
Veri tanımlamaları ve konfigürasyon
</p>
</div>
</div>
+48
View File
@@ -0,0 +1,48 @@
'use client';
import { useActionState } from 'react';
import { addCompany } from '@/app/companies/actions';
export default function CompanyForm() {
const [state, formAction, isPending] = useActionState(
async (prevState: any, formData: FormData) => {
return await addCompany(formData);
},
null
);
return (
<form action={formAction} className="mt-5 space-y-4">
{state?.error && (
<div className="p-4 text-xs font-black text-rose-600 bg-rose-50 border border-rose-100 rounded-2xl text-center uppercase tracking-widest leading-relaxed">
{state.error}
</div>
)}
{state?.success && (
<div className="p-4 text-xs font-black text-emerald-600 bg-emerald-50 border border-emerald-100 rounded-2xl text-center uppercase tracking-widest leading-relaxed">
Şirket başarıyla kaydedildi.
</div>
)}
<div>
<label htmlFor="name" className="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">Şirket Adı</label>
<input
type="text"
name="name"
id="name"
required
disabled={isPending}
className="block w-full rounded-2xl border-0 py-3 px-4 text-slate-900 shadow-sm ring-1 ring-inset ring-slate-200 dark:ring-zinc-700 dark:bg-zinc-800 dark:text-white placeholder:text-slate-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm outline-none transition-all disabled:opacity-50"
placeholder="Abisena Ltd. Şti."
/>
</div>
<button
type="submit"
disabled={isPending}
className="inline-flex w-full items-center justify-center rounded-2xl bg-indigo-600 px-4 py-3 text-sm font-bold text-white shadow-sm shadow-indigo-100 dark:shadow-none hover:bg-indigo-700 transition-all active:scale-95 disabled:opacity-50"
>
{isPending ? 'KAYDEDİLİYOR...' : 'Şirket Kaydet'}
</button>
</form>
);
}
+18 -18
View File
@@ -85,38 +85,38 @@ export default function EmployeeModal({
const labelClass = "block text-[10px] font-black uppercase tracking-widest text-slate-400 mb-1.5 ml-1";
return (
<div className="fixed inset-0 z-50 flex items-center justify-center p-4 bg-slate-900/60 backdrop-blur-md transition-all">
<div className="bg-white dark:bg-zinc-900 w-full max-w-4xl max-h-[90vh] rounded-[2.5rem] shadow-2xl border border-slate-100 dark:border-zinc-800 overflow-hidden flex flex-col animate-in fade-in zoom-in duration-300">
<div className="fixed inset-0 z-50 flex items-center justify-center p-0 sm:p-4 bg-slate-900/60 backdrop-blur-md transition-all">
<div className="bg-white dark:bg-zinc-900 w-full sm:max-w-4xl h-full sm:h-auto sm:max-h-[90vh] rounded-none sm:rounded-[2.5rem] shadow-2xl border border-slate-100 dark:border-zinc-800 overflow-hidden flex flex-col animate-in fade-in zoom-in duration-300">
{/* Header */}
<div className="px-10 py-8 border-b border-slate-50 dark:border-zinc-800 flex items-center justify-between bg-white dark:bg-zinc-900">
<div className="px-6 sm:px-10 py-6 sm:py-8 border-b border-slate-50 dark:border-zinc-800 flex items-center justify-between bg-white dark:bg-zinc-900">
<div>
<h2 className="text-2xl font-black text-[#173363] dark:text-white tracking-tight">
<h2 className="text-xl sm:text-2xl font-black text-[#173363] dark:text-white tracking-tight">
{editingEmployee ? 'Personel Düzenle' : 'Yeni Personel Ekle'}
</h2>
<p className="text-xs font-bold text-slate-400 mt-1">
Sistem üzerindeki personel bilgilerini detaylı olarak yönetin.
<p className="text-[10px] sm:text-xs font-bold text-slate-400 mt-1">
Personel bilgilerini detaylı olarak yönetin.
</p>
</div>
<button
onClick={onClose}
className="p-3 rounded-2xl hover:bg-slate-50 dark:hover:bg-zinc-800 text-slate-300 hover:text-[#CE0515] transition-all"
className="p-2 sm:p-3 rounded-2xl hover:bg-slate-50 dark:hover:bg-zinc-800 text-slate-300 hover:text-[#CE0515] transition-all"
>
<XMarkIcon className="w-6 h-6" />
<XMarkIcon className="w-5 h-5 sm:w-6 sm:h-6" />
</button>
</div>
{/* Tabs */}
<div className="px-10 flex gap-8 border-b border-slate-50 dark:border-zinc-800 bg-white dark:bg-zinc-900">
<div className="px-6 sm:px-10 flex gap-4 sm:gap-8 border-b border-slate-50 dark:border-zinc-800 bg-white dark:bg-zinc-900 overflow-x-auto no-scrollbar">
{[
{ id: 'personal', label: 'KİŞİSEL BİLGİLER' },
{ id: 'employment', label: 'ÇALIŞMA BİLGİLERİ' },
{ id: 'contact', label: 'İLETİŞİM / DİĞER' }
{ id: 'personal', label: 'KİŞİSEL' },
{ id: 'employment', label: 'ÇALIŞMA' },
{ id: 'contact', label: 'İLETİŞİM' }
].map(tab => (
<button
key={tab.id}
onClick={() => setActiveTab(tab.id)}
className={`py-6 text-[11px] font-black tracking-[0.2em] transition-all border-b-2 ${
className={`py-4 sm:py-6 text-[10px] sm:text-[11px] font-black tracking-[0.15em] sm:tracking-[0.2em] transition-all border-b-2 whitespace-nowrap ${
activeTab === tab.id
? 'border-[#CE0515] text-[#CE0515]'
: 'border-transparent text-slate-400 hover:text-slate-600'
@@ -128,9 +128,9 @@ export default function EmployeeModal({
</div>
{/* Body */}
<form action={handleSubmit} className="flex-1 overflow-y-auto p-10 custom-scrollbar">
<form action={handleSubmit} className="flex-1 overflow-y-auto p-6 sm:p-10 custom-scrollbar">
{error && (
<div className="mb-8 p-4 bg-rose-50 border border-rose-100 rounded-2xl text-rose-600 text-xs font-black text-center uppercase tracking-widest">
<div className="mb-6 p-4 bg-rose-50 border border-rose-100 rounded-2xl text-rose-600 text-[10px] sm:text-xs font-black text-center uppercase tracking-widest leading-relaxed">
{error}
</div>
)}
@@ -307,18 +307,18 @@ export default function EmployeeModal({
</div>
</div>
<div className="mt-12 flex gap-4">
<div className="mt-8 sm:mt-12 flex flex-col sm:flex-row gap-3 sm:gap-4 pb-4">
<button
type="button"
onClick={onClose}
className="flex-1 px-8 py-5 rounded-full font-black text-slate-300 hover:bg-slate-50 transition-all text-[11px] uppercase tracking-[0.2em]"
className="px-8 py-4 sm:py-5 rounded-full font-black text-slate-300 hover:bg-slate-50 transition-all text-[10px] sm:text-[11px] uppercase tracking-[0.2em]"
>
Vazgeç
</button>
<button
type="submit"
disabled={loading}
className="flex-[2] bg-[#173363] hover:bg-[#CE0515] text-white px-10 py-5 rounded-full font-black shadow-xl shadow-blue-900/10 transition-all active:scale-95 disabled:opacity-50 text-[11px] uppercase tracking-[0.2em] transform"
className="bg-[#173363] hover:bg-[#CE0515] text-white px-10 py-4 sm:py-5 rounded-full font-black shadow-xl shadow-blue-900/10 transition-all active:scale-95 disabled:opacity-50 text-[10px] sm:text-[11px] uppercase tracking-[0.2em]"
>
{loading ? 'YÜKLENİYOR...' : (editingEmployee ? 'BİLGİLERİ GÜNCELLE' : 'PERSONELİ KAYDET')}
</button>
+19 -22
View File
@@ -89,64 +89,64 @@ export default function EmployeeTable({
return (
<div className="space-y-8">
{/* Header with Add Button */}
<div className="sm:flex sm:items-center justify-between gap-4">
<div className="flex flex-col sm:flex-row sm:items-center justify-between gap-6">
<div className="sm:flex-auto">
<div className="flex items-center gap-4">
<div className="w-1.5 h-10 bg-[#173363] rounded-full" />
<div>
<h1 className="text-3xl font-bold text-slate-900 dark:text-white tracking-tight">Personeller</h1>
<p className="text-sm font-medium text-slate-500 dark:text-slate-400 mt-1">
<h1 className="text-2xl sm:text-3xl font-bold text-slate-900 dark:text-white tracking-tight">Personeller</h1>
<p className="text-xs sm:text-sm font-medium text-slate-500 dark:text-slate-400 mt-1">
Şirketinizdeki tüm personel kayıtlarını yönetin
</p>
</div>
</div>
</div>
<div className="flex gap-4">
<div className="flex flex-col xs:flex-row gap-3">
<button
onClick={() => setIsUserModalOpen(true)}
className="group flex items-center gap-2 bg-slate-100 dark:bg-zinc-800 hover:bg-[#173363] text-[#173363] dark:text-slate-300 hover:text-white px-8 py-3.5 rounded-full font-black transition-all duration-500 active:scale-95 text-xs tracking-widest"
className="group flex items-center justify-center gap-2 bg-slate-100 dark:bg-zinc-800 hover:bg-[#173363] text-[#173363] dark:text-slate-300 hover:text-white px-6 py-3.5 rounded-full font-black transition-all duration-500 active:scale-95 text-[10px] tracking-widest"
>
<UserPlusIcon className="w-5 h-5 transition-transform group-hover:scale-110" />
<UserPlusIcon className="w-4 h-4" />
KULLANICI TANIMLA
</button>
<button
onClick={handleAdd}
className="group flex items-center gap-2 bg-[#173363] hover:bg-[#CE0515] text-white px-8 py-3.5 rounded-full font-black shadow-lg shadow-blue-900/20 transition-all duration-500 active:scale-95 text-xs tracking-widest"
className="group flex items-center justify-center gap-2 bg-[#173363] hover:bg-[#CE0515] text-white px-6 py-3.5 rounded-full font-black shadow-lg shadow-blue-900/20 transition-all duration-500 active:scale-95 text-[10px] tracking-widest"
>
<PlusIcon className="w-5 h-5 transition-transform group-hover:rotate-90" />
<PlusIcon className="w-4 h-4" />
YENİ PERSONEL
</button>
</div>
</div>
{/* Filter & Search Bar */}
<div className="flex flex-col md:flex-row gap-4 items-center justify-between bg-white dark:bg-zinc-900 p-6 rounded-[2rem] border border-slate-100 dark:border-zinc-800 shadow-sm">
<div className="relative w-full md:w-96 group">
<div className="flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between bg-white dark:bg-zinc-900 p-4 sm:p-6 rounded-3xl sm:rounded-[2rem] border border-slate-100 dark:border-zinc-800 shadow-sm">
<div className="relative w-full lg:w-96 group">
<MagnifyingGlassIcon className="absolute left-4 top-1/2 -translate-y-1/2 w-5 h-5 text-slate-400 group-focus-within:text-[#CE0515] transition-colors" />
<input
type="text"
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
placeholder="İsim, TC veya e-posta ile ara..."
placeholder="İsim, TC veya e-posta..."
className="w-full pl-12 pr-4 py-3 bg-slate-50 dark:bg-zinc-800 border-none rounded-2xl text-sm font-medium focus:ring-2 focus:ring-[#CE0515] transition-all outline-none placeholder:text-slate-400 dark:text-white"
/>
</div>
<div className="flex gap-2 w-full md:w-auto p-1.5 bg-slate-50 dark:bg-zinc-800 rounded-full border border-slate-100 dark:border-zinc-700">
<div className="flex gap-2 w-full lg:w-auto p-1.5 bg-slate-50 dark:bg-zinc-800 rounded-full border border-slate-100 dark:border-zinc-700 overflow-x-auto no-scrollbar">
<button
onClick={() => setStatusFilter('all')}
className={`flex-1 md:flex-none px-8 py-2.5 rounded-full text-xs font-black uppercase tracking-wider transition-all duration-500 ${statusFilter === 'all' ? 'bg-[#173363] text-white shadow-md' : 'text-slate-400 hover:text-slate-600 dark:hover:text-slate-300'}`}
className={`flex-1 lg:flex-none whitespace-nowrap px-6 py-2.5 rounded-full text-xs font-black uppercase tracking-wider transition-all duration-500 ${statusFilter === 'all' ? 'bg-[#173363] text-white shadow-md' : 'text-slate-400 hover:text-slate-600 dark:hover:text-slate-300'}`}
>
Tümü
</button>
<button
onClick={() => setStatusFilter('active')}
className={`flex-1 md:flex-none px-8 py-2.5 rounded-full text-xs font-black uppercase tracking-wider transition-all duration-500 ${statusFilter === 'active' ? 'bg-emerald-600 text-white shadow-md' : 'text-slate-400 hover:text-slate-600 dark:hover:text-slate-300'}`}
className={`flex-1 lg:flex-none whitespace-nowrap px-6 py-2.5 rounded-full text-xs font-black uppercase tracking-wider transition-all duration-500 ${statusFilter === 'active' ? 'bg-emerald-600 text-white shadow-md' : 'text-slate-400 hover:text-slate-600 dark:hover:text-slate-300'}`}
>
Aktif
</button>
<button
onClick={() => setStatusFilter('inactive')}
className={`flex-1 md:flex-none px-8 py-2.5 rounded-full text-xs font-black uppercase tracking-wider transition-all duration-500 ${statusFilter === 'inactive' ? 'bg-[#CE0515] text-white shadow-md' : 'text-slate-400 hover:text-slate-600 dark:hover:text-slate-300'}`}
className={`flex-1 lg:flex-none whitespace-nowrap px-6 py-2.5 rounded-full text-xs font-black uppercase tracking-wider transition-all duration-500 ${statusFilter === 'inactive' ? 'bg-[#CE0515] text-white shadow-md' : 'text-slate-400 hover:text-slate-600 dark:hover:text-slate-300'}`}
>
Ayrılan
</button>
@@ -265,27 +265,24 @@ export default function EmployeeTable({
{/* İşlemler */}
<td className="whitespace-nowrap py-6 pl-3 pr-8 text-right">
<div className="flex items-center justify-end gap-3 translate-x-4 opacity-0 group-hover:translate-x-0 group-hover:opacity-100 transition-all duration-500">
<div className="flex items-center justify-end gap-2 lg:gap-3 lg:translate-x-4 lg:opacity-0 lg:group-hover:translate-x-0 lg:group-hover:opacity-100 transition-all duration-500">
{!emp.user_id && emp.email && (
<button
onClick={() => setIsUserModalOpen(true)}
className="p-3 rounded-2xl text-emerald-600 hover:text-white hover:bg-emerald-600 hover:shadow-lg hover:shadow-emerald-900/20 transition-all duration-300"
title="Sistem Girişi Tanımla"
className="p-2 sm:p-3 rounded-xl sm:rounded-2xl text-emerald-600 hover:text-white hover:bg-emerald-600 transition-all"
>
<KeyIcon className="w-5 h-5" />
</button>
)}
<button
onClick={() => openEditModal(emp)}
className="p-3 rounded-2xl text-slate-400 hover:text-white hover:bg-[#173363] hover:shadow-lg hover:shadow-blue-900/20 transition-all duration-300"
title="Düzenle"
className="p-2 sm:p-3 rounded-xl sm:rounded-2xl text-slate-400 hover:text-white hover:bg-[#173363] transition-all"
>
<PencilSquareIcon className="w-5 h-5" />
</button>
<button
onClick={() => handleDelete(emp.id)}
className="p-3 rounded-2xl text-slate-400 hover:text-white hover:bg-[#CE0515] hover:shadow-lg hover:shadow-red-900/20 transition-all duration-300"
title="Sil"
className="p-2 sm:p-3 rounded-xl sm:rounded-2xl text-slate-400 hover:text-white hover:bg-[#CE0515] transition-all"
>
<TrashIcon className="w-5 h-5" />
</button>
+17 -3
View File
@@ -1,8 +1,22 @@
'use client'
import { Bars3Icon } from '@heroicons/react/24/outline'
export function Header({ user }: { user?: { email?: string; first_name?: string } | null }) {
const openMobileMenu = () => {
window.dispatchEvent(new CustomEvent('open-mobile-menu'));
};
return (
<div className="sticky top-0 z-40 flex h-16 shrink-0 items-center justify-between gap-x-4 border-b border-gray-200 dark:border-zinc-800 bg-white dark:bg-zinc-950 px-4 shadow-sm sm:gap-x-6 sm:px-6 lg:px-8">
{/* Empty div for flex spacing since sidebar hamburger is handled by Sidebar component */}
<div className="flex-1 lg:hidden"></div>
<div className="sticky top-0 z-40 flex h-16 shrink-0 items-center justify-between gap-x-4 border-b border-gray-100 dark:border-zinc-800 bg-white/80 dark:bg-zinc-950/80 backdrop-blur-md px-4 shadow-sm sm:gap-x-6 sm:px-6 lg:px-8">
<button
type="button"
className="p-2.5 text-slate-700 lg:hidden"
onClick={openMobileMenu}
>
<span className="sr-only">Menüyü </span>
<Bars3Icon className="h-6 w-6" aria-hidden="true" />
</button>
<div className="flex flex-1 justify-end items-center gap-x-4 lg:gap-x-6">
{/* Profile dropdown */}
+32 -30
View File
@@ -1,6 +1,6 @@
'use client'
import { useState } from 'react'
import { useState, useEffect } from 'react'
import Link from 'next/link'
import Image from 'next/image'
import { usePathname } from 'next/navigation'
@@ -27,67 +27,61 @@ export function Sidebar() {
const pathname = usePathname()
const [sidebarOpen, setSidebarOpen] = useState(false)
// Listen for mobile menu open event from Header
useEffect(() => {
const handleOpen = () => setSidebarOpen(true);
window.addEventListener('open-mobile-menu', handleOpen);
return () => window.removeEventListener('open-mobile-menu', handleOpen);
}, []);
return (
<>
{/* Mobile sidebar trigger */}
<div className="lg:hidden fixed top-0 left-0 w-full h-16 bg-white dark:bg-zinc-900 border-b border-slate-200 dark:border-zinc-800 flex items-center px-4 z-40">
<button
className="p-2 text-slate-500 hover:text-slate-900 dark:hover:text-white focus:outline-none focus:ring-2 focus:ring-inset focus:ring-indigo-500 rounded-lg"
onClick={() => setSidebarOpen(true)}
>
<span className="sr-only">Menüyü </span>
<Bars3Icon className="h-6 w-6" aria-hidden="true" />
</button>
<div className="ml-4 flex items-center gap-3 group">
<Image src="/logo.png" alt="Abisena Logo" width={120} height={40} className="h-8 w-auto object-contain" />
<div className="h-4 w-px bg-gray-300 dark:bg-zinc-700 mx-1" />
<span className="text-[10px] font-bold text-gray-500 dark:text-zinc-400 uppercase tracking-tighter leading-tight">Personel<br/>Sistemi</span>
</div>
</div>
{/* Drawer logic is below, Mobile Header is now in Header.tsx */}
{/* Mobile Sidebar Overlay */}
{/* Mobile Sidebar Overlay (Drawer) */}
{sidebarOpen && (
<div className="relative z-50 lg:hidden" aria-modal="true">
<div className="fixed inset-0 bg-gray-900/80 transition-opacity" onClick={() => setSidebarOpen(false)} />
<div className="fixed inset-0 bg-slate-900/60 backdrop-blur-sm transition-opacity" onClick={() => setSidebarOpen(false)} />
<div className="fixed inset-0 flex">
<div className="relative mr-16 flex w-full max-w-xs flex-1 transform transition duration-300 ease-in-out">
<div className="absolute left-full top-0 flex w-16 justify-center pt-5">
<div className="relative flex w-full max-w-xs flex-1 transform transition duration-300 ease-in-out">
<div className="absolute right-0 top-0 -mr-12 pt-4">
<button
type="button"
className="-m-2.5 p-2.5"
className="ml-1 flex h-10 w-10 items-center justify-center rounded-full focus:outline-none focus:ring-2 focus:ring-inset focus:ring-white"
onClick={() => setSidebarOpen(false)}
>
<span className="sr-only">Menüyü Kapat</span>
<XMarkIcon className="h-6 w-6 text-white" aria-hidden="true" />
</button>
</div>
{/* Mobile Sidebar Content */}
<div className="flex grow flex-col gap-y-5 overflow-y-auto bg-[#173363] px-6 pb-4 shadow-xl">
<div className="flex h-20 shrink-0 items-center border-b border-gray-100 dark:border-zinc-900">
{/* Mobile Sidebar Content - Reusing Desktop Style */}
<div className="flex grow flex-col gap-y-5 overflow-y-auto bg-[#173363] px-6 pb-4 shadow-2xl">
<div className="flex h-24 shrink-0 items-center mt-4 border-b border-white/10">
<div className="flex flex-col gap-1">
<Image src="/logo.png" alt="Abisena Logo" width={140} height={45} className="h-10 w-auto object-contain" />
<span className="text-[10px] font-bold text-gray-400 dark:text-zinc-500 uppercase tracking-[0.2em] ml-1">TAKİP SİSTEMİ</span>
<span className="text-[9px] font-black text-slate-400 tracking-[0.3em] uppercase ml-1">Personel Takip Sistemi</span>
</div>
</div>
<nav className="flex flex-1 flex-col">
<ul role="list" className="flex flex-1 flex-col gap-y-7">
<li>
<ul role="list" className="-mx-2 space-y-1">
<ul role="list" className="-mx-2 space-y-2">
{navigation.map((item) => (
<li key={item.name}>
<Link
href={item.href}
onClick={() => setSidebarOpen(false)}
className={`
group flex gap-x-3 rounded-md p-2 text-sm leading-6 font-semibold
group flex items-center gap-x-3 rounded-xl p-3 text-sm leading-6 font-semibold transition-all
${pathname === item.href
? 'bg-indigo-50 dark:bg-indigo-500/10 text-indigo-600 dark:text-indigo-400'
: 'text-slate-600 dark:text-slate-400 hover:text-indigo-600 dark:hover:text-indigo-400 hover:bg-slate-50 dark:hover:bg-zinc-800/50'
? 'bg-[#CE0515] text-white'
: 'text-slate-300 hover:text-white hover:bg-white/5'
}
`}
>
<item.icon
className={`h-6 w-6 shrink-0 ${pathname === item.href ? 'text-indigo-600 dark:text-indigo-400' : 'text-slate-400 group-hover:text-indigo-600 dark:group-hover:text-indigo-400'}`}
className={`h-5 w-5 shrink-0 ${pathname === item.href ? 'text-white' : 'text-slate-400 group-hover:text-white'}`}
aria-hidden="true"
/>
{item.name}
@@ -96,6 +90,14 @@ export function Sidebar() {
))}
</ul>
</li>
<li className="mt-auto">
<form action="/auth/signout" method="post" className="-mx-2 pb-4">
<button type="submit" className="group flex w-full items-center gap-x-3 rounded-xl p-3 text-sm font-bold text-slate-400 hover:text-white transition-all">
<ArrowRightOnRectangleIcon className="h-5 w-5 shrink-0" />
Güvenli Çıkış
</button>
</form>
</li>
</ul>
</nav>
</div>
@@ -0,0 +1,26 @@
-- Fix Companies RLS (Allow authenticated users to manage companies)
-- Previous migration dropped full access and only added a restrictive SELECT policy.
CREATE POLICY "Allow authenticated users to insert companies"
ON public.companies
FOR INSERT TO authenticated
WITH CHECK (true);
CREATE POLICY "Allow authenticated users to update their own company"
ON public.companies
FOR UPDATE TO authenticated
USING (
id IN (
SELECT company_id FROM public.employees WHERE user_id = auth.uid()
)
)
WITH CHECK (
id IN (
SELECT company_id FROM public.employees WHERE user_id = auth.uid()
)
);
CREATE POLICY "Allow authenticated users to delete companies"
ON public.companies
FOR DELETE TO authenticated
USING (true); -- Ideally restricted to admins, but keeping it open for now to unblock.