🚀 مُصادَق: تحديث برمجي جديد 2026-05-03 15:51

This commit is contained in:
Hamza-Ayed
2026-05-03 15:51:53 +03:00
parent e182faad1d
commit 81a3e5188e
12 changed files with 415 additions and 6060 deletions

View File

@@ -15,9 +15,13 @@
.card { background: var(--bg-surface); border: 1px solid var(--border-default); border-radius: 14px; }
.nav-link { border-right: 3px solid transparent; color: var(--text-secondary); }
.nav-active { border-right-color: var(--emerald); background: rgba(16,185,129,.12); color: var(--text-primary); }
#loading-bar { position: fixed; top: 0; left: 0; right: 0; height: 3px; background: var(--emerald); transform: scaleX(0); transform-origin: left; transition: transform .3s ease; z-index: 100; }
.toast { position: fixed; bottom: 24px; left: 50%; transform: translateX(-50%); background: var(--bg-elevated); border: 1px solid var(--border-default); padding: 12px 20px; border-radius: 10px; z-index: 1000; box-shadow: 0 10px 30px rgba(0,0,0,.5); }
</style>
</head>
<body data-theme="dark">
<div id="loading-bar"></div>
<div id="toast-container"></div>
<div class="min-h-screen flex">
<aside class="w-64 p-4 border-l" style="background:var(--bg-surface);border-color:var(--border-default)">
<div class="font-bold text-2xl mb-6">مُصادَق</div>
@@ -39,8 +43,49 @@
<div id="modal-overlay" class="hidden fixed inset-0 bg-black/60 p-6 items-center justify-center"></div>
<script>
const state={user:null,currentPage:null,currentParams:{},companies:[],theme:localStorage.getItem("theme")||"dark"};
const API={token:()=>localStorage.getItem("access_token"),async request(method,path,body=null,isFormData=false){const headers={"Authorization":"Bearer "+(API.token()||"")};if(!isFormData&&body)headers["Content-Type"]="application/json";const opts={method,headers};if(body)opts.body=isFormData?body:JSON.stringify(body);let res=await fetch("/api/v1"+path,opts);if(res.status===404)res=await fetch("index.php?route=/api/v1"+path,opts);if(res.status===401){logout();throw new Error("unauthorized");}const data=await res.json();if(!data.success)throw new Error(data.error?.message_ar||"Request failed");return data;},get:(p)=>API.request("GET",p),post:(p,b)=>API.request("POST",p,b),put:(p,b)=>API.request("PUT",p,b),delete:(p)=>API.request("DELETE",p),upload:(p,f)=>API.request("POST",p,f,true)};
const toast={show(msg){alert(msg);}};
const API={
token:()=>localStorage.getItem("access_token"),
async request(method,path,body=null,isFormData=false){
const loading = document.getElementById("loading-bar");
loading.style.transform = "scaleX(0.3)";
const headers={"Authorization":"Bearer "+(API.token()||"")};
if(!isFormData&&body)headers["Content-Type"]="application/json";
const csrfCookie=document.cookie.split("; ").find(r=>r.startsWith("csrf_token="))?.split("=")[1];
if(csrfCookie&&["POST","PUT","DELETE","PATCH"].includes(method.toUpperCase()))headers["X-CSRF-TOKEN"]=csrfCookie;
const opts={method,headers};
if(body)opts.body=isFormData?body:JSON.stringify(body);
try {
let res=await fetch("/api/v1"+path,opts);
if(res.status===404)res=await fetch("index.php?route=/api/v1"+path,opts);
loading.style.transform = "scaleX(1)";
setTimeout(()=>loading.style.transform="scaleX(0)", 400);
if(res.status===401){logout();throw new Error("unauthorized");}
const data=await res.json();
if(!data.success) {
toast.show(data.message || "حدث خطأ غير متوقع", "error");
throw new Error(data.message || "Request failed");
}
return data;
} catch(e) {
loading.style.transform = "scaleX(0)";
throw e;
}
},
get:(p)=>API.request("GET",p),
post:(p,b)=>API.request("POST",p,b),
put:(p,b)=>API.request("PUT",p,b),
delete:(p)=>API.request("DELETE",p),
upload:(p,f)=>API.request("POST",p,f,true)
};
const toast={
show(msg, type="info"){
const el = document.createElement("div");
el.className = "toast " + (type === "error" ? "border-red-500 text-red-400" : "border-emerald-500 text-emerald-400");
el.textContent = msg;
document.getElementById("toast-container").appendChild(el);
setTimeout(() => el.remove(), 4000);
}
};
const modal={open(html){const el=document.getElementById("modal-overlay");el.innerHTML='<div class="card p-6 w-full max-w-2xl">'+html+"</div>";el.classList.remove("hidden");el.classList.add("flex");},close(){const el=document.getElementById("modal-overlay");el.classList.add("hidden");el.classList.remove("flex");}};
const theme={init(){document.body.setAttribute("data-theme",state.theme);},toggle(){state.theme=state.theme==="dark"?"light":"dark";localStorage.setItem("theme",state.theme);theme.init();}};
function logout(){localStorage.removeItem("access_token");location.reload();}