create middleware block and update proxy file also make token stored in cookes and up date user page to can show user details also fixed delete user error and delete car error and broken corse inginx image block now we can uplode image to server and but it in my app

This commit is contained in:
m7amedez5511
2026-06-17 17:01:53 +03:00
parent 6ca2cc08d1
commit a23d21f222
15 changed files with 1017 additions and 137 deletions

View File

@@ -3,7 +3,7 @@
import { Spinner } from "../UI";
import type { User } from "../../types/user";
// ── role ───────────────────────────────────────────────────────────────
// ── role badge ───────────────────────────────────────────────────────────────
function RoleBadge({ name }: { name?: string }) {
const isAdmin = name === "مدير النظام";
return (
@@ -13,7 +13,7 @@ function RoleBadge({ name }: { name?: string }) {
);
}
// ── status ───────────────────────────────────────────────────────────────
// ── status badge ─────────────────────────────────────────────────────────────
function StatusBadge({ active }: { active: boolean }) {
return (
<span style={{ display: "inline-flex", alignItems: "center", gap: 5, borderRadius: "var(--radius-full)", border: active ? "1px solid #BBF7D0" : "1px solid #FECACA", background: active ? "#DCFCE7" : "#FEF2F2", padding: "0.2rem 0.625rem", fontSize: 11, fontWeight: 600, color: active ? "#166534" : "#991B1B" }}>
@@ -23,7 +23,7 @@ function StatusBadge({ active }: { active: boolean }) {
);
}
// icon buton ──────────────────────────────────────────────────────────────
// ── icon button ──────────────────────────────────────────────────────────────
function IconBtn({ onClick, title, color, bg, borderColor, children }: { onClick: () => void; title: string; color: string; bg: string; borderColor: string; children: React.ReactNode }) {
return (
<button type="button" title={title} aria-label={title} onClick={e => { e.stopPropagation(); onClick(); }}
@@ -33,7 +33,7 @@ function IconBtn({ onClick, title, color, bg, borderColor, children }: { onClick
);
}
// ── title style ───────────────────────────────────────────────────
// ── card / header styles ─────────────────────────────────────────────────────
const cardStyle: React.CSSProperties = {
borderRadius: "var(--radius-xl)", border: "1px solid var(--color-border)",
background: "var(--color-surface)", overflow: "hidden", boxShadow: "var(--shadow-card)",
@@ -45,7 +45,7 @@ const thStyle: React.CSSProperties = {
borderBottom: "1px solid var(--color-border)",
};
// ── Props ──────────────────────────────────────────────────────────────
// ── Props ────────────────────────────────────────────────────────────────────
interface UserTableProps {
users: User[];
loading: boolean;
@@ -54,16 +54,17 @@ interface UserTableProps {
pages: number;
onEdit: (user: User) => void;
onDelete: (user: User) => void;
onView: (user: User) => void;
onAddFirst: () => void;
onPageChange: (p: number) => void;
}
// ── main table ────────────────────────────────────────────────────────────
export function UserTable({ users, loading, search, page, pages, onEdit, onDelete, onAddFirst, onPageChange }: UserTableProps) {
// ── main table ───────────────────────────────────────────────────────────────
export function UserTable({ users, loading, search, page, pages, onEdit, onDelete, onView, onAddFirst, onPageChange }: UserTableProps) {
return (
<div style={cardStyle}>
{/* column headers */}
<div dir="rtl" style={{ display: "grid", gridTemplateColumns: "2fr 1.5fr 1.5fr 1fr 1fr 1fr 80px", ...thStyle }}>
{/* column headers */}
<div dir="rtl" style={{ display: "grid", gridTemplateColumns: "2fr 1.5fr 1.5fr 1fr 1fr 1fr 100px", ...thStyle }}>
<span>الاسم</span>
<span>اسم المستخدم</span>
<span>الفرع</span>
@@ -73,14 +74,14 @@ export function UserTable({ users, loading, search, page, pages, onEdit, onDelet
<span style={{ textAlign: "center" }}>إجراءات</span>
</div>
{/* loading state */}
{/* loading state */}
{loading ? (
<div style={{ display: "flex", alignItems: "center", justifyContent: "center", gap: 12, padding: "4rem 0", color: "var(--color-text-muted)" }}>
<Spinner size="sm" className="text-blue-600" />
<span style={{ fontSize: 13 }}>جارٍ التحميل</span>
</div>
) : users.length === 0 ? (
// empty state
/* empty state */
<div style={{ textAlign: "center", padding: "4rem 1rem" }}>
<p style={{ fontSize: 13, color: "var(--color-text-muted)" }}>
{search ? `لا توجد نتائج لـ "${search}"` : "لا يوجد مستخدمون لعرضهم."}
@@ -93,11 +94,11 @@ export function UserTable({ users, loading, search, page, pages, onEdit, onDelet
)}
</div>
) : (
// data rows
/* data rows */
<ul dir="rtl" style={{ listStyle: "none", margin: 0, padding: 0 }}>
{users.map((u, i) => (
<li key={u.id} style={{
display: "grid", gridTemplateColumns: "2fr 1.5fr 1.5fr 1fr 1fr 1fr 80px",
display: "grid", gridTemplateColumns: "2fr 1.5fr 1.5fr 1fr 1fr 1fr 100px",
alignItems: "center", gap: "0.5rem", padding: "0.875rem 1.5rem",
borderBottom: "1px solid var(--color-border)",
background: i % 2 !== 0 ? "var(--color-surface-muted)" : "transparent",
@@ -114,13 +115,22 @@ export function UserTable({ users, loading, search, page, pages, onEdit, onDelet
<span style={{ textAlign: "center", fontSize: 11, color: "var(--color-text-muted)" }}>
{new Date(u.createdAt).toLocaleDateString("ar-SA", { year: "numeric", month: "short", day: "numeric" })}
</span>
<div style={{ display: "flex", justifyContent: "center", gap: 6 }}>
<div style={{ display: "flex", justifyContent: "center", gap: 4 }}>
{/* view */}
<IconBtn title={`عرض ${u.name}`} color="#059669" bg="#ECFDF5" borderColor="#A7F3D0" onClick={() => onView(u)}>
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
<path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z" />
<circle cx="12" cy="12" r="3" />
</svg>
</IconBtn>
{/* edit */}
<IconBtn title={`تعديل ${u.name}`} color="#1D4ED8" bg="#EFF6FF" borderColor="#BFDBFE" onClick={() => onEdit(u)}>
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
<path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7" />
<path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z" />
</svg>
</IconBtn>
{/* delete */}
<IconBtn title={`حذف ${u.name}`} color="#DC2626" bg="#FEF2F2" borderColor="#FECACA" onClick={() => onDelete(u)}>
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
<polyline points="3 6 5 6 21 6" /><path d="M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6" />
@@ -133,7 +143,7 @@ export function UserTable({ users, loading, search, page, pages, onEdit, onDelet
</ul>
)}
{/* pagination */}
{/* pagination */}
{pages > 1 && (
<div dir="rtl" style={{ display: "flex", alignItems: "center", justifyContent: "space-between", borderTop: "1px solid var(--color-border)", padding: "0.875rem 1.5rem" }}>
<span style={{ fontSize: 12, color: "var(--color-text-muted)" }}>