Files
kitebeachakyaka/app/admin/users/UsersClient.tsx
T

202 lines
7.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use client";
import { useState, useActionState, useEffect } from "react";
import { createUser, updateUser, deleteUser, UserActionState } from "@/app/actions/users";
import { User, UserPlus, Edit2, Trash2, X, Save, ShieldAlert } from "lucide-react";
type UserType = {
id: number;
username: string;
createdAt: Date;
updatedAt: Date;
};
export default function UsersClient({ initialUsers }: { initialUsers: UserType[] }) {
const [users, setUsers] = useState<UserType[]>(initialUsers);
const [isEditing, setIsEditing] = useState(false);
const [editingUser, setEditingUser] = useState<UserType | null>(null);
// Update state when initialUsers change
useEffect(() => {
setUsers(initialUsers);
}, [initialUsers]);
const [createState, createAction, isCreating] = useActionState<UserActionState, FormData>(
createUser,
null
);
const [updateState, updateAction, isUpdating] = useActionState<UserActionState, FormData>(
updateUser,
null
);
const handleDelete = async (id: number) => {
if (confirm("Bu kullanıcıyı silmek istediğinize emin misiniz?")) {
const result = await deleteUser(id);
if (result?.success) {
setUsers(users.filter(u => u.id !== id));
} else {
alert(result?.message || "Bir hata oluştu.");
}
}
};
const handleEditClick = (user: UserType) => {
setEditingUser(user);
setIsEditing(true);
};
const handleAddNew = () => {
setEditingUser(null);
setIsEditing(true);
};
const handleCancel = () => {
setIsEditing(false);
setEditingUser(null);
};
// Check state to close modal on success
useEffect(() => {
if (createState?.success || updateState?.success) {
setIsEditing(false);
setEditingUser(null);
}
}, [createState, updateState]);
return (
<div className="space-y-6">
{/* List Section */}
{!isEditing && (
<div className="bg-white rounded-2xl p-6 shadow-[0_8px_30px_rgb(0,0,0,0.04)] border border-primary/10 relative overflow-hidden group">
<div className="flex justify-between items-center mb-6">
<h2 className="text-xl font-bold text-dark flex items-center gap-2">
<User className="w-5 h-5 text-accent" /> Yönetici Hesapları
</h2>
<button
onClick={handleAddNew}
className="flex items-center gap-2 px-4 py-2 bg-accent hover:bg-accent/90 text-white rounded-xl transition-all font-medium text-sm shadow-md"
>
<UserPlus className="w-4 h-4" /> Yeni Kullanıcı
</button>
</div>
{(createState?.message || updateState?.message) && (
<div className={`p-4 mb-6 rounded-xl text-sm ${createState?.success || updateState?.success ? 'bg-green-50 text-green-700' : 'bg-red-50 text-red-700'}`}>
{createState?.message || updateState?.message}
</div>
)}
<div className="space-y-4">
{users.map((user) => (
<div key={user.id} className="flex items-center justify-between p-4 rounded-xl border border-primary/5 hover:border-primary/20 transition-all bg-gray-50/50">
<div className="flex flex-col">
<span className="font-semibold text-dark">{user.username}</span>
<span className="text-xs text-gray-500">
Oluşturulma: {new Date(user.createdAt).toLocaleDateString('tr-TR')}
</span>
</div>
<div className="flex items-center gap-2">
<button
onClick={() => handleEditClick(user)}
className="p-2 text-blue-600 hover:bg-blue-50 rounded-lg transition-colors"
title="Düzenle"
>
<Edit2 className="w-4 h-4" />
</button>
<button
onClick={() => handleDelete(user.id)}
className="p-2 text-red-600 hover:bg-red-50 rounded-lg transition-colors"
title="Sil"
disabled={users.length <= 1}
>
<Trash2 className="w-4 h-4" />
</button>
</div>
</div>
))}
{users.length === 0 && (
<p className="text-center text-gray-500 py-4">Kullanıcı bulunamadı.</p>
)}
</div>
</div>
)}
{/* Form Section */}
{isEditing && (
<div className="bg-white rounded-2xl p-6 shadow-[0_8px_30px_rgb(0,0,0,0.04)] border border-primary/10 relative overflow-hidden">
<div className="flex justify-between items-center mb-6 border-b border-primary/10 pb-4">
<h2 className="text-xl font-bold text-dark flex items-center gap-2">
{editingUser ? <Edit2 className="w-5 h-5 text-accent" /> : <UserPlus className="w-5 h-5 text-accent" />}
{editingUser ? "Kullanıcıyı Düzenle" : "Yeni Kullanıcı Ekle"}
</h2>
<button
onClick={handleCancel}
className="p-2 text-gray-400 hover:text-gray-600 hover:bg-gray-100 rounded-lg transition-colors"
>
<X className="w-5 h-5" />
</button>
</div>
<form action={editingUser ? updateAction : createAction} className="space-y-4">
{editingUser && <input type="hidden" name="id" value={editingUser.id} />}
<div className="space-y-2">
<label className="block text-sm font-medium text-dark">Kullanıcı Adı</label>
<input
type="text"
name="username"
defaultValue={editingUser?.username || ""}
required
className="w-full px-4 py-2 bg-gray-50 border border-primary/10 rounded-xl focus:outline-none focus:ring-2 focus:ring-accent/50 text-dark"
placeholder="Örn: admin"
/>
</div>
<div className="space-y-2">
<label className="block text-sm font-medium text-dark">Şifre</label>
<input
type="password"
name="password"
required={!editingUser}
className="w-full px-4 py-2 bg-gray-50 border border-primary/10 rounded-xl focus:outline-none focus:ring-2 focus:ring-accent/50 text-dark"
placeholder={editingUser ? "Değiştirmek için yeni şifre girin (İsteğe bağlı)" : "Güçlü bir şifre girin"}
/>
{editingUser && (
<p className="text-xs text-gray-500 mt-1 flex items-center gap-1">
<ShieldAlert className="w-3 h-3" /> Şifreyi değiştirmek istemiyorsanız boş bırakın.
</p>
)}
</div>
{(createState?.message || updateState?.message) && (
<div className={`p-4 rounded-xl text-sm ${createState?.success || updateState?.success ? 'bg-green-50 text-green-700' : 'bg-red-50 text-red-700'}`}>
{createState?.message || updateState?.message}
</div>
)}
<div className="flex gap-3 pt-4 border-t border-primary/10">
<button
type="button"
onClick={handleCancel}
className="px-6 py-2 border border-primary/20 text-dark hover:bg-gray-50 rounded-xl transition-colors"
>
İptal
</button>
<button
type="submit"
disabled={isCreating || isUpdating}
className="flex-1 flex items-center justify-center gap-2 px-6 py-2 bg-accent hover:bg-accent/90 text-white rounded-xl transition-all font-medium disabled:opacity-50"
>
<Save className="w-4 h-4" />
{isCreating || isUpdating ? "Kaydediliyor..." : "Kaydet"}
</button>
</div>
</form>
</div>
)}
</div>
);
}