Jaouadart commited on
Commit
7ff46be
·
verified ·
1 Parent(s): e5a9c7f

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +243 -142
index.html CHANGED
@@ -3,11 +3,10 @@
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>إدارة مالية النادي - المزامنة السحابية</title>
7
  <script src="https://cdn.tailwindcss.com"></script>
 
8
  <script src="https://unpkg.com/lucide@latest"></script>
9
- <!-- إضافة Babel لتحويل JSX -->
10
- <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
11
  <style>
12
  @import url('https://fonts.googleapis.com/css2?family=Cairo:wght@400;600;800&display=swap');
13
  body { font-family: 'Cairo', sans-serif; font-size: 13px; }
@@ -21,204 +20,305 @@
21
  <body class="bg-slate-50 text-right text-slate-700">
22
  <div id="root"></div>
23
 
24
- <!-- Firebase SDKs -->
25
- <script type="module">
26
- import { initializeApp } from "https://www.gstatic.com/firebasejs/11.1.0/firebase-app.js";
27
- import { getAuth, signInAnonymously, onAuthStateChanged, signInWithCustomToken } from "https://www.gstatic.com/firebasejs/11.1.0/firebase-auth.js";
28
- import { getFirestore, collection, doc, onSnapshot, addDoc, deleteDoc, updateDoc } from "https://www.gstatic.com/firebasejs/11.1.0/firebase-firestore.js";
29
-
30
- // جعل Firebase متاحاً لسكربت Babel
31
- window.firebaseDocs = { collection, doc, onSnapshot, addDoc, deleteDoc, updateDoc, getAuth, signInAnonymously, onAuthStateChanged, signInWithCustomToken, getFirestore, initializeApp };
32
- </script>
33
-
34
  <script type="text/babel">
35
  const { useState, useEffect } = React;
36
- const { initializeApp, getAuth, signInAnonymously, onAuthStateChanged, signInWithCustomToken, getFirestore, collection, doc, onSnapshot, addDoc, deleteDoc, updateDoc } = window.firebaseDocs;
37
-
38
- // Firebase Configuration
39
- const firebaseConfig = JSON.parse(__firebase_config);
40
- const app = initializeApp(firebaseConfig);
41
- const auth = getAuth(app);
42
- const db = getFirestore(app);
43
- const appId = typeof __app_id !== 'undefined' ? __app_id : 'club-finance-prod';
44
 
45
  const App = () => {
46
- const [user, setUser] = useState(null);
 
 
 
 
 
 
47
  const [isAdmin, setIsAdmin] = useState(false);
48
  const [showLoginModal, setShowLoginModal] = useState(false);
49
  const [passwordInput, setPasswordInput] = useState('');
50
  const [loginError, setLoginError] = useState(false);
51
  const [activeTab, setActiveTab] = useState('dashboard');
52
 
53
- const [members, setMembers] = useState([]);
54
- const [trips, setTrips] = useState([]);
55
- const [activities, setActivities] = useState([]);
56
- const [tripOne, setTripOne] = useState([]);
 
 
 
 
 
 
 
 
 
 
 
 
57
 
58
- const [memberForm, setMemberForm] = useState({ name: '', amount: '' });
59
- const [tripForm, setTripForm] = useState({ destination: '', cost: '', income: '' });
60
- const [activityForm, setActivityForm] = useState({ title: '', expenses: '' });
 
 
 
 
 
61
  const [tripOneForm, setTripOneForm] = useState({ name: '', fee: '', paid: false });
62
 
63
  const CORRECT_PASSWORD = "CLUB@2976";
64
-
65
- useEffect(() => {
66
- const initAuth = async () => {
67
- if (typeof __initial_auth_token !== 'undefined' && __initial_auth_token) {
68
- await signInWithCustomToken(auth, __initial_auth_token);
69
- } else {
70
- await signInAnonymously(auth);
71
- }
72
- };
73
- initAuth();
74
- return onAuthStateChanged(auth, setUser);
75
- }, []);
76
-
77
- useEffect(() => {
78
- if (!user) return;
79
- const getPath = (name) => collection(db, 'artifacts', appId, 'public', 'data', name);
80
- const unsubers = [
81
- onSnapshot(getPath('members'), (s) => setMembers(s.docs.map(d => ({id: d.id, ...d.data()})))),
82
- onSnapshot(getPath('trips'), (s) => setTrips(s.docs.map(d => ({id: d.id, ...d.data()})))),
83
- onSnapshot(getPath('activities'), (s) => setActivities(s.docs.map(d => ({id: d.id, ...d.data()})))),
84
- onSnapshot(getPath('tripOne'), (s) => setTripOne(s.docs.map(d => ({id: d.id, ...d.data()})))),
85
- ];
86
- return () => unsubers.forEach(un => un());
87
- }, [user]);
88
-
89
- useEffect(() => { if(window.lucide) window.lucide.createIcons(); }, [activeTab, isAdmin, showLoginModal, members, tripOne]);
90
 
91
  const handleLogin = (e) => {
92
  e.preventDefault();
93
  if (passwordInput === CORRECT_PASSWORD) {
94
- setIsAdmin(true); setShowLoginModal(false); setLoginError(false); setPasswordInput('');
95
- } else { setLoginError(true); }
 
 
 
 
 
96
  };
97
 
98
- const cloudAdd = async (coll, data) => { if(isAdmin) await addDoc(collection(db, 'artifacts', appId, 'public', 'data', coll), data); };
99
- const cloudDel = async (coll, id) => { if(isAdmin) await deleteDoc(doc(db, 'artifacts', appId, 'public', 'data', coll, id)); };
100
- const cloudToggle = async (id, current) => { if(isAdmin) await updateDoc(doc(db, 'artifacts', appId, 'public', 'data', 'tripOne', id), { paid: !current }); };
101
-
102
- const totalMembers = members.reduce((a, c) => a + (Number(c.amount) || 0), 0);
103
- const totalTripOne = tripOne.reduce((a, c) => c.paid ? a + (Number(c.fee) || 0) : a, 0);
104
- const totalTripsNet = trips.reduce((a, c) => a + ((Number(c.income) || 0) - (Number(c.cost) || 0)), 0);
105
- const totalExpenses = activities.reduce((a, c) => a + (Number(c.expenses) || 0), 0);
106
- const grandTotal = totalMembers + totalTripOne + totalTripsNet - totalExpenses;
107
-
108
- const SidebarItem = ({ id, icon, label, color = "blue" }) => (
109
- <button onClick={() => setActiveTab(id)} className={`w-full flex items-center gap-3 px-4 py-2.5 rounded-xl transition-all text-xs font-bold mb-1 ${activeTab === id ? `bg-${color}-600 text-white shadow-lg` : `text-slate-500 hover:bg-slate-100`}`}>
110
- <i data-lucide={icon} className="w-4 h-4"></i>
111
- <span>{label}</span>
112
- </button>
113
- );
 
 
 
 
 
 
 
 
 
114
 
115
  return (
116
- <div className="min-h-screen bg-slate-50 flex flex-col md:flex-row-reverse">
 
117
  {showLoginModal && (
118
- <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/60 backdrop-blur-sm p-4 text-center">
119
- <div className="bg-white rounded-[2rem] p-8 shadow-2xl w-full max-w-xs animate-fade-in">
120
- <div className="bg-blue-600 w-14 h-14 rounded-2xl flex items-center justify-center text-white mx-auto mb-4"><i data-lucide="shield-check"></i></div>
121
- <h2 className="text-xl font-extrabold text-slate-800 mb-2">دخول المكلف</h2>
122
- <form onSubmit={handleLogin} className="space-y-4">
123
- <input type="password" placeholder="كلمة السر" value={passwordInput} onChange={(e) => setPasswordInput(e.target.value)} className="w-full p-4 bg-slate-50 rounded-2xl border-none text-center font-bold outline-blue-600 shadow-inner" autoFocus />
124
- <button type="submit" className="w-full bg-blue-600 text-white py-4 rounded-2xl font-extrabold shadow-xl hover:bg-blue-700">تأكيد الرمز</button>
 
 
 
 
 
 
 
125
  </form>
126
- {loginError && <p className="text-rose-500 text-[11px] mt-3 font-bold">الرمز غير صحيح</p>}
127
- <button onClick={() => setShowLoginModal(false)} className="mt-4 text-slate-400 text-[11px] font-bold">إغلاق</button>
128
  </div>
129
  </div>
130
  )}
131
 
132
- <aside className="w-full md:w-64 bg-white border-l border-slate-200 p-6 flex flex-col shrink-0">
133
- <div className="flex items-center gap-3 mb-10">
134
- <div className="bg-blue-600 p-2 rounded-xl text-white shadow-lg"><i data-lucide="wallet"></i></div>
135
- <span className="text-lg font-extrabold text-slate-800">مالية النادي</span>
 
 
 
136
  </div>
137
- <nav className="flex-1">
138
- <SidebarItem id="dashboard" icon="layout-dashboard" label="نظرة عامة" />
139
- <SidebarItem id="members" icon="users" label="المنخرطون" color="emerald" />
140
- <SidebarItem id="trip_one" icon="map-pin" label="الرحلة 1" color="blue" />
141
- <SidebarItem id="trips" icon="navigation" label="الرحلات الأخرى" color="purple" />
142
- <SidebarItem id="activities" icon="calendar" label="الأنشطة" color="rose" />
 
143
  </nav>
144
- <div className="mt-6 pt-6 border-t border-slate-100">
145
  {isAdmin ? (
146
- <button onClick={() => setIsAdmin(false)} className="w-full flex items-center justify-center gap-2 bg-rose-50 text-rose-600 p-3 rounded-xl font-bold text-[11px]"><i data-lucide="log-out" className="w-4 h-4"></i> خروج المكلف</button>
 
 
147
  ) : (
148
- <button onClick={() => setShowLoginModal(true)} className="w-full flex items-center justify-center gap-2 bg-blue-50 text-blue-600 p-3 rounded-xl font-bold text-[11px]"><i data-lucide="user-cog" className="w-4 h-4"></i> دخول المكلف</button>
 
 
149
  )}
 
 
 
150
  </div>
151
  </aside>
152
 
153
- <main className="flex-1 p-6 md:p-10 overflow-y-auto">
 
154
  {activeTab === 'dashboard' && (
155
- <div className="space-y-8 animate-fade-in">
156
- <header>
157
- <h2 className="text-2xl font-extrabold text-slate-800">لوحة التحكم</h2>
158
- <p className="text-slate-400 font-bold text-xs mt-1">تزامن فوري سحابي</p>
159
- </header>
160
- <div className="grid grid-cols-2 lg:grid-cols-4 gap-4">
161
- <div className="bg-emerald-50 p-5 rounded-[2rem] border border-white shadow-sm">
162
- <p className="text-[11px] font-extrabold mb-1 text-emerald-700 uppercase">انخراطات</p>
163
- <h3 className="text-xl font-extrabold text-emerald-700">{totalMembers} MAD</h3>
164
- </div>
165
- <div className="bg-blue-50 p-5 rounded-[2rem] border border-white shadow-sm">
166
- <p className="text-[11px] font-extrabold mb-1 text-blue-700 uppercase">الرحلة 1</p>
167
- <h3 className="text-xl font-extrabold text-blue-700">{totalTripOne} MAD</h3>
168
- </div>
169
- <div className="bg-purple-50 p-5 rounded-[2rem] border border-white shadow-sm">
170
- <p className="text-[11px] font-extrabold mb-1 text-purple-700 uppercase">أربا�� الرحلات</p>
171
- <h3 className="text-xl font-extrabold text-purple-700">{totalTripsNet} MAD</h3>
172
- </div>
173
- <div className="bg-rose-50 p-5 rounded-[2rem] border border-white shadow-sm">
174
- <p className="text-[11px] font-extrabold mb-1 text-rose-700 uppercase">المصاريف</p>
175
- <h3 className="text-xl font-extrabold text-rose-700">{totalExpenses} MAD</h3>
176
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
177
  </div>
178
- <div className="bg-slate-900 text-white p-10 rounded-[2.5rem] shadow-2xl text-right">
179
- <p className="text-blue-400 text-xs font-extrabold mb-2 uppercase">الرصيد الصافي المتوفر</p>
180
- <h2 className="text-5xl font-black tracking-tighter">{grandTotal} <span className="text-xl text-slate-500 font-bold ml-2">MAD</span></h2>
 
 
181
  </div>
182
  </div>
183
  )}
184
 
185
  {activeTab === 'members' && (
186
- <div className="space-y-6 animate-fade-in">
187
- <h2 className="text-xl font-extrabold text-slate-800">سجل المنخرطين</h2>
188
  {isAdmin && (
189
- <div className="bg-white p-5 rounded-[2rem] shadow-sm grid grid-cols-1 md:grid-cols-3 gap-3 border">
190
- <input type="text" placeholder="الاسم" value={memberForm.name} onChange={e=>setMemberForm({...memberForm, name: e.target.value})} className="p-3 bg-slate-50 rounded-xl outline-none text-xs font-bold" />
191
- <input type="number" placeholder="المبلغ" value={memberForm.amount} onChange={e=>setMemberForm({...memberForm, amount: e.target.value})} className="p-3 bg-slate-50 rounded-xl outline-none text-xs font-bold" />
192
- <button onClick={()=>{if(!memberForm.name)return; cloudAdd('members', memberForm); setMemberForm({name:'',amount:''})}} className="bg-emerald-600 text-white rounded-xl font-black text-xs hover:bg-emerald-700">إضافة</button>
 
193
  </div>
194
  )}
195
- <div className="bg-white rounded-[2rem] shadow-sm border overflow-hidden">
196
- <table className="w-full text-right"><thead className="bg-slate-50 text-[11px] text-slate-400 font-black"><tr><th className="px-6 py-4">الاسم</th><th className="px-6 py-4 text-center">المبلغ</th>{isAdmin && <th className="px-6 py-4 text-center">حذف</th>}</tr></thead><tbody className="divide-y text-xs font-bold">{members.map(m => (<tr key={m.id}><td className="px-6 py-4">{m.name}</td><td className="px-6 py-4 text-emerald-600 text-center">{m.amount} MAD</td>{isAdmin && <td className="px-6 py-4 text-center"><button onClick={()=>cloudDel('members', m.id)} className="text-rose-300 hover:text-rose-500"><i data-lucide="trash-2" className="w-4 h-4"></i></button></td>}</tr>))}</tbody></table>
 
 
 
 
 
 
 
 
 
 
 
 
 
197
  </div>
198
  </div>
199
  )}
200
 
201
  {activeTab === 'trip_one' && (
202
- <div className="space-y-6 animate-fade-in">
203
- <h2 className="text-xl font-extrabold text-blue-800">لائحة الرحلة الأولى</h2>
204
  {isAdmin && (
205
- <div className="bg-white p-5 rounded-[2rem] shadow-sm grid grid-cols-1 md:grid-cols-4 gap-3 border">
206
- <input type="text" placeholder="الاسم" value={tripOneForm.name} onChange={e=>setTripOneForm({...tripOneForm, name: e.target.value})} className="p-3 bg-blue-50/50 rounded-xl outline-none text-xs font-bold" />
207
- <input type="number" placeholder="المبلغ" value={tripOneForm.fee} onChange={e=>setTripOneForm({...tripOneForm, fee: e.target.value})} className="p-3 bg-blue-50/50 rounded-xl outline-none text-xs font-bold" />
208
- <div className="flex items-center gap-2 px-2"><input type="checkbox" checked={tripOneForm.paid} onChange={e=>setTripOneForm({...tripOneForm, paid: e.target.checked})} /> <span className="text-[11px] font-bold">تم الدفع</span></div>
209
- <button onClick={()=>{if(!tripOneForm.name)return; cloudAdd('tripOne', tripOneForm); setTripOneForm({name:'',fee:'',paid:false})}} className="bg-blue-700 text-white rounded-xl font-black text-xs">تسجيل</button>
 
 
 
210
  </div>
211
  )}
212
- <div className="bg-white rounded-[2rem] shadow-sm border overflow-hidden">
213
- <table className="w-full text-right"><thead className="bg-blue-700 text-white text-[11px] font-black"><tr><th className="px-6 py-4">المشارك</th><th className="px-6 py-4 text-center">الواجب</th><th className="px-6 py-4 text-center">الحالة</th>{isAdmin && <th className="px-6 py-4 text-center">حذف</th>}</tr></thead><tbody className="divide-y text-xs font-bold">{tripOne.map(t => (<tr key={t.id}><td className="px-6 py-4">{t.name}</td><td className="px-6 py-4 text-center">{t.fee} MAD</td><td className="px-6 py-4 text-center"><span onClick={() => isAdmin && cloudToggle(t.id, t.paid)} className={`px-3 py-1 rounded-full text-[10px] font-black border ${isAdmin ? 'cursor-pointer' : ''} ${t.paid ? 'bg-emerald-50 text-emerald-600 border-emerald-100' : 'bg-amber-50 text-amber-600 border-amber-100'}`}>{t.paid ? 'تم الاستخلاص' : 'في الانتظار'}</span></td>{isAdmin && <td className="px-6 py-4 text-center"><button onClick={()=>cloudDel('tripOne', t.id)} className="text-slate-300"><i data-lucide="trash-2" className="w-4 h-4"></i></button></td>}</tr>))}</tbody></table>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
214
  </div>
215
  </div>
216
  )}
217
-
218
- {/* باقي الأقسام تتبع نفس المنطق */}
219
- {activeTab === 'trips' && <div className="p-10 text-center text-slate-400 font-bold italic">قسم الرحلات - يرجى إضافة البيانات سحابياً</div>}
220
- {activeTab === 'activities' && <div className="p-10 text-center text-slate-400 font-bold italic">قسم الأنشطة - يرجى إضافة البيانات سحابياً</div>}
221
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
222
  </main>
223
  </div>
224
  );
@@ -230,5 +330,6 @@
230
 
231
  <script src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
232
  <script src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
 
233
  </body>
234
  </html>
 
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>إدارة مالية النادي - الواجهة الذكية</title>
7
  <script src="https://cdn.tailwindcss.com"></script>
8
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js"></script>
9
  <script src="https://unpkg.com/lucide@latest"></script>
 
 
10
  <style>
11
  @import url('https://fonts.googleapis.com/css2?family=Cairo:wght@400;600;800&display=swap');
12
  body { font-family: 'Cairo', sans-serif; font-size: 13px; }
 
20
  <body class="bg-slate-50 text-right text-slate-700">
21
  <div id="root"></div>
22
 
 
 
 
 
 
 
 
 
 
 
23
  <script type="text/babel">
24
  const { useState, useEffect } = React;
 
 
 
 
 
 
 
 
25
 
26
  const App = () => {
27
+ const STORAGE_KEYS = {
28
+ MEMBERS: 'club_members_data',
29
+ TRIPS: 'club_trips_data',
30
+ ACTIVITIES: 'club_activities_data',
31
+ TRIP_ONE: 'club_trip_one_data'
32
+ };
33
+
34
  const [isAdmin, setIsAdmin] = useState(false);
35
  const [showLoginModal, setShowLoginModal] = useState(false);
36
  const [passwordInput, setPasswordInput] = useState('');
37
  const [loginError, setLoginError] = useState(false);
38
  const [activeTab, setActiveTab] = useState('dashboard');
39
 
40
+ const [members, setMembers] = useState(() => {
41
+ const saved = localStorage.getItem(STORAGE_KEYS.MEMBERS);
42
+ return saved ? JSON.parse(saved) : [];
43
+ });
44
+ const [trips, setTrips] = useState(() => {
45
+ const saved = localStorage.getItem(STORAGE_KEYS.TRIPS);
46
+ return saved ? JSON.parse(saved) : [];
47
+ });
48
+ const [activities, setActivities] = useState(() => {
49
+ const saved = localStorage.getItem(STORAGE_KEYS.ACTIVITIES);
50
+ return saved ? JSON.parse(saved) : [];
51
+ });
52
+ const [tripOneRegistrations, setTripOneRegistrations] = useState(() => {
53
+ const saved = localStorage.getItem(STORAGE_KEYS.TRIP_ONE);
54
+ return saved ? JSON.parse(saved) : [];
55
+ });
56
 
57
+ useEffect(() => localStorage.setItem(STORAGE_KEYS.MEMBERS, JSON.stringify(members)), [members]);
58
+ useEffect(() => localStorage.setItem(STORAGE_KEYS.TRIPS, JSON.stringify(trips)), [trips]);
59
+ useEffect(() => localStorage.setItem(STORAGE_KEYS.ACTIVITIES, JSON.stringify(activities)), [activities]);
60
+ useEffect(() => localStorage.setItem(STORAGE_KEYS.TRIP_ONE, JSON.stringify(tripOneRegistrations)), [tripOneRegistrations]);
61
+
62
+ const [memberForm, setMemberForm] = useState({ name: '', amount: '', date: '' });
63
+ const [tripForm, setTripForm] = useState({ destination: '', cost: '', income: '', date: '' });
64
+ const [activityForm, setActivityForm] = useState({ title: '', expenses: '', date: '' });
65
  const [tripOneForm, setTripOneForm] = useState({ name: '', fee: '', paid: false });
66
 
67
  const CORRECT_PASSWORD = "CLUB@2976";
68
+ const WHATSAPP_LINK = "https://wa.me/message/P3DXRV6NTZ63L1";
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
69
 
70
  const handleLogin = (e) => {
71
  e.preventDefault();
72
  if (passwordInput === CORRECT_PASSWORD) {
73
+ setIsAdmin(true);
74
+ setShowLoginModal(false);
75
+ setLoginError(false);
76
+ setPasswordInput('');
77
+ } else {
78
+ setLoginError(true);
79
+ }
80
  };
81
 
82
+ const totalMemberIncome = members.reduce((acc, curr) => acc + (parseFloat(curr.amount) || 0), 0);
83
+ const tripOneIncome = tripOneRegistrations.reduce((acc, curr) => curr.paid ? acc + (parseFloat(curr.fee) || 0) : acc, 0);
84
+ const totalTripBalance = trips.reduce((acc, curr) => acc + ((parseFloat(curr.income) || 0) - (parseFloat(curr.cost) || 0)), 0);
85
+ const totalActivityExpenses = activities.reduce((acc, curr) => acc + (parseFloat(curr.expenses) || 0), 0);
86
+ const netBalance = totalMemberIncome + tripOneIncome + totalTripBalance - totalActivityExpenses;
87
+
88
+ useEffect(() => { lucide.createIcons(); }, [activeTab, isAdmin, showLoginModal]);
89
+
90
+ const SidebarItem = ({ id, iconName, label, color = "blue", isExternal = false, href = "" }) => {
91
+ const baseClass = `w-full flex items-center space-x-reverse space-x-2 px-3 py-2 rounded-lg transition-all text-xs font-semibold`;
92
+ if (isExternal) {
93
+ return (
94
+ <a href={href} target="_blank" rel="noopener noreferrer" className={`${baseClass} text-emerald-600 hover:bg-emerald-50`}>
95
+ <i data-lucide={iconName} className="w-4 h-4"></i>
96
+ <span>{label}</span>
97
+ </a>
98
+ );
99
+ }
100
+ return (
101
+ <button onClick={() => setActiveTab(id)} className={`${baseClass} ${activeTab === id ? `bg-${color}-600 text-white shadow-md` : `text-slate-500 hover:bg-slate-100`}`}>
102
+ <i data-lucide={iconName} className="w-4 h-4"></i>
103
+ <span>{label}</span>
104
+ </button>
105
+ );
106
+ };
107
 
108
  return (
109
+ <div className="min-h-screen bg-slate-50 flex flex-col md:flex-row-reverse" dir="rtl">
110
+ {/* Login Modal */}
111
  {showLoginModal && (
112
+ <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/50 backdrop-blur-sm p-4">
113
+ <div className="bg-white rounded-3xl p-8 shadow-2xl animate-fade-in text-center max-w-xs w-full relative">
114
+ <button onClick={() => {setShowLoginModal(false); setLoginError(false);}} className="absolute top-4 left-4 text-slate-400 hover:text-slate-600">
115
+ <i data-lucide="x" className="w-5 h-5"></i>
116
+ </button>
117
+ <div className="bg-blue-600 w-12 h-12 rounded-xl flex items-center justify-center text-white mx-auto mb-4">
118
+ <i data-lucide="shield-check" className="w-6 h-6"></i>
119
+ </div>
120
+ <h2 className="text-lg font-extrabold text-slate-800 mb-1">دخول المكلف</h2>
121
+ <p className="text-[10px] text-slate-400 mb-4 font-bold">يرجى إدخال رمز الوصول للإدارة</p>
122
+ <form onSubmit={handleLogin} className="space-y-3">
123
+ <input type="password" placeholder="كلمة السر" value={passwordInput} onChange={(e) => setPasswordInput(e.target.value)}
124
+ className="w-full p-3 bg-slate-50 rounded-xl border border-slate-100 outline-none text-center font-bold text-sm" autoFocus />
125
+ <button type="submit" className="w-full bg-blue-600 text-white py-3 rounded-xl font-bold text-sm shadow-lg hover:bg-blue-700">تأكيد الدخول</button>
126
  </form>
127
+ {loginError && <p className="text-rose-500 text-[10px] mt-2 font-bold">الرمز غير صحيح!</p>}
 
128
  </div>
129
  </div>
130
  )}
131
 
132
+ {/* Sidebar */}
133
+ <aside className="w-full md:w-56 bg-white border-l border-slate-200 p-4 flex flex-col gap-1 shrink-0 z-10">
134
+ <div className="flex items-center gap-2 mb-6 px-2">
135
+ <div className="bg-blue-600 p-1.5 rounded-lg text-white shadow-sm">
136
+ <i data-lucide="wallet" className="w-4 h-4"></i>
137
+ </div>
138
+ <h1 className="text-base font-extrabold text-slate-800">المالية الذكية</h1>
139
  </div>
140
+ <nav className="space-y-1">
141
+ <SidebarItem id="dashboard" iconName="layout-dashboard" label="لوحة التحكم" />
142
+ <SidebarItem id="members" iconName="users" label="المنخرطون" />
143
+ <SidebarItem id="trip_one" iconName="map" label="الرحلة 1" />
144
+ <SidebarItem id="trips" iconName="navigation" label="رحلات أخرى" color="purple" />
145
+ <SidebarItem id="activities" iconName="calendar" label="الأنشطة" color="rose" />
146
+ <SidebarItem isExternal={true} href={WHATSAPP_LINK} iconName="message-circle" label="تواصل معنا" />
147
  </nav>
148
+ <div className="mt-auto pt-4 border-t border-slate-100 space-y-2">
149
  {isAdmin ? (
150
+ <button onClick={() => setIsAdmin(false)} className="w-full text-rose-500 text-[11px] font-bold flex items-center gap-2 hover:bg-rose-50 p-2 rounded-lg">
151
+ <i data-lucide="log-out" className="w-3.5 h-3.5"></i> خروج من الإدارة
152
+ </button>
153
  ) : (
154
+ <button onClick={() => setShowLoginModal(true)} className="w-full text-blue-600 text-[11px] font-bold flex items-center gap-2 hover:bg-blue-50 p-2 rounded-lg">
155
+ <i data-lucide="user-check" className="w-3.5 h-3.5"></i> دخول المكلف
156
+ </button>
157
  )}
158
+ <div className={`text-[9px] text-center font-bold px-2 py-1 rounded ${isAdmin ? 'bg-emerald-50 text-emerald-600' : 'bg-slate-100 text-slate-500'}`}>
159
+ {isAdmin ? 'وضع التعديل نشط' : 'وضع العرض فقط'}
160
+ </div>
161
  </div>
162
  </aside>
163
 
164
+ {/* Main Content */}
165
+ <main className="flex-1 p-4 md:p-6 overflow-y-auto animate-fade-in">
166
  {activeTab === 'dashboard' && (
167
+ <div className="space-y-6">
168
+ <header className="flex justify-between items-center">
169
+ <div>
170
+ <h2 className="text-xl font-extrabold text-slate-800 leading-tight">ملخص النادي</h2>
171
+ <p className="text-[11px] text-slate-400 font-bold uppercase tracking-wider">البيانات المالية المحدثة</p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
172
  </div>
173
+ </header>
174
+
175
+ <div className="grid grid-cols-2 lg:grid-cols-4 gap-3">
176
+ {[
177
+ { label: "انخراطات", val: totalMemberIncome, bg: "bg-emerald-50", text: "text-emerald-700" },
178
+ { label: "الرحلة 1", val: tripOneIncome, bg: "bg-blue-50", text: "text-blue-700" },
179
+ { label: "أرباح الرحلات", val: totalTripBalance, bg: "bg-purple-50", text: "text-purple-700" },
180
+ { label: "المصاريف", val: totalActivityExpenses, bg: "bg-rose-50", text: "text-rose-700" }
181
+ ].map((card, i) => (
182
+ <div key={i} className={`p-3 rounded-2xl ${card.bg} border border-white shadow-sm`}>
183
+ <p className={`text-[10px] font-bold mb-0.5 ${card.text}`}>{card.label}</p>
184
+ <h3 className={`text-lg font-extrabold ${card.text}`}>{card.val} <span className="text-[10px]">MAD</span></h3>
185
+ </div>
186
+ ))}
187
  </div>
188
+
189
+ <div className="bg-slate-900 text-white p-6 rounded-3xl shadow-xl relative overflow-hidden">
190
+ <div className="absolute top-0 right-0 w-32 h-32 bg-blue-500/10 rounded-full blur-2xl"></div>
191
+ <p className="text-slate-400 text-xs font-bold mb-1">صافي الرصيد المتوفر</p>
192
+ <h2 className="text-4xl font-extrabold tracking-tight">{netBalance} <span className="text-sm text-slate-500 font-bold">درهم مغربي</span></h2>
193
  </div>
194
  </div>
195
  )}
196
 
197
  {activeTab === 'members' && (
198
+ <div className="space-y-4">
199
+ <h2 className="text-lg font-extrabold text-slate-800">سجل المنخرطين</h2>
200
  {isAdmin && (
201
+ <div className="bg-white p-4 rounded-2xl shadow-sm grid grid-cols-1 md:grid-cols-4 gap-2 border">
202
+ <input type="text" placeholder="الاسم" value={memberForm.name} onChange={(e)=>setMemberForm({...memberForm, name: e.target.value})} className="p-2 bg-slate-50 rounded-lg outline-none border border-slate-100 text-xs font-semibold" />
203
+ <input type="number" placeholder="المبلغ" value={memberForm.amount} onChange={(e)=>setMemberForm({...memberForm, amount: e.target.value})} className="p-2 bg-slate-50 rounded-lg outline-none border border-slate-100 text-xs font-semibold" />
204
+ <input type="date" value={memberForm.date} onChange={(e)=>setMemberForm({...memberForm, date: e.target.value})} className="p-2 bg-slate-50 rounded-lg outline-none border border-slate-100 text-xs font-semibold" />
205
+ <button onClick={()=>{if(!memberForm.name) return; setMembers([...members, {...memberForm, id: Date.now()}]); setMemberForm({name:'',amount:'',date:''})}} className="bg-blue-600 text-white p-2 rounded-lg font-bold text-xs">إضافة</button>
206
  </div>
207
  )}
208
+ <div className="bg-white rounded-2xl shadow-sm border overflow-hidden">
209
+ <table className="w-full text-right">
210
+ <thead className="bg-slate-50 border-b text-[11px] text-slate-400 uppercase font-extrabold">
211
+ <tr><th className="px-4 py-3">الاسم</th><th className="px-4 py-3 text-center">المبلغ</th>{isAdmin && <th className="px-4 py-3 text-center w-16">إجراء</th>}</tr>
212
+ </thead>
213
+ <tbody className="divide-y divide-slate-50 text-xs font-semibold">
214
+ {members.map(m => (
215
+ <tr key={m.id} className="hover:bg-slate-50">
216
+ <td className="px-4 py-2 text-slate-700">{m.name}</td>
217
+ <td className="px-4 py-2 text-emerald-600 text-center font-bold">{m.amount} MAD</td>
218
+ {isAdmin && <td className="px-4 py-2 text-center"><button onClick={()=>setMembers(members.filter(x=>x.id!==m.id))} className="text-rose-300 hover:text-rose-500 p-1"><i data-lucide="trash-2" className="w-3.5 h-3.5"></i></button></td>}
219
+ </tr>
220
+ ))}
221
+ </tbody>
222
+ </table>
223
  </div>
224
  </div>
225
  )}
226
 
227
  {activeTab === 'trip_one' && (
228
+ <div className="space-y-4">
229
+ <h2 className="text-lg font-extrabold text-blue-800 text-center md:text-right">لائحة المشاركين في الرحلة 1</h2>
230
  {isAdmin && (
231
+ <div className="bg-white p-4 rounded-2xl shadow-sm grid grid-cols-1 md:grid-cols-4 gap-2 border border-blue-50">
232
+ <input type="text" placeholder="الاسم الكامل" value={tripOneForm.name} onChange={(e)=>setTripOneForm({...tripOneForm, name: e.target.value})} className="p-2 bg-blue-50/50 rounded-lg outline-none text-xs font-semibold" />
233
+ <input type="number" placeholder="المبلغ" value={tripOneForm.fee} onChange={(e)=>setTripOneForm({...tripOneForm, fee: e.target.value})} className="p-2 bg-blue-50/50 rounded-lg outline-none text-xs font-semibold" />
234
+ <div className="flex items-center gap-2 px-1">
235
+ <input type="checkbox" checked={tripOneForm.paid} onChange={(e)=>setTripOneForm({...tripOneForm, paid: e.target.checked})} className="w-4 h-4 accent-blue-600" />
236
+ <span className="text-[11px] font-bold">مدفوع</span>
237
+ </div>
238
+ <button onClick={()=>{if(!tripOneForm.name) return; setTripOneRegistrations([...tripOneRegistrations, {...tripOneForm, id: Date.now()}]); setTripOneForm({name:'',fee:'',paid:false})}} className="bg-blue-700 text-white p-2 rounded-lg font-bold text-xs shadow-sm">تسجيل مشارك</button>
239
  </div>
240
  )}
241
+ <div className="bg-white rounded-2xl shadow-sm border overflow-hidden">
242
+ <table className="w-full text-right">
243
+ <thead className="bg-blue-700 text-white text-[11px] font-bold">
244
+ <tr><th className="px-4 py-2.5">المشارك</th><th className="px-4 py-2.5 text-center">الواجب</th><th className="px-4 py-2.5 text-center">الحالة</th>{isAdmin && <th className="px-4 py-2.5 text-center w-16">إجراء</th>}</tr>
245
+ </thead>
246
+ <tbody className="text-xs font-semibold divide-y divide-blue-50">
247
+ {tripOneRegistrations.map(reg => (
248
+ <tr key={reg.id} className="hover:bg-blue-50/30">
249
+ <td className="px-4 py-2">{reg.name}</td>
250
+ <td className="px-4 py-2 text-center font-bold">{reg.fee} MAD</td>
251
+ <td className="px-4 py-2 text-center">
252
+ <span onClick={() => isAdmin && setTripOneRegistrations(tripOneRegistrations.map(r => r.id === reg.id ? {...r, paid: !r.paid} : r))}
253
+ className={`px-2 py-0.5 rounded-full text-[9px] font-extrabold border ${isAdmin ? 'cursor-pointer' : ''} ${reg.paid ? 'bg-emerald-50 text-emerald-600 border-emerald-100' : 'bg-amber-50 text-amber-600 border-amber-100'}`}>
254
+ {reg.paid ? 'تم الدفع' : 'في الانتظار'}
255
+ </span>
256
+ </td>
257
+ {isAdmin && <td className="px-4 py-2 text-center"><button onClick={()=>setTripOneRegistrations(tripOneRegistrations.filter(x=>x.id!==reg.id))} className="text-blue-200 hover:text-rose-500"><i data-lucide="trash-2" className="w-3.5 h-3.5"></i></button></td>}
258
+ </tr>
259
+ ))}
260
+ </tbody>
261
+ </table>
262
  </div>
263
  </div>
264
  )}
 
 
 
 
265
 
266
+ {activeTab === 'trips' && (
267
+ <div className="space-y-4">
268
+ <h2 className="text-lg font-extrabold text-purple-800">بيانات الرحلات</h2>
269
+ {isAdmin && (
270
+ <div className="bg-white p-4 rounded-2xl shadow-sm grid grid-cols-1 md:grid-cols-4 gap-2 border border-purple-50">
271
+ <input type="text" placeholder="الوجهة" value={tripForm.destination} onChange={(e)=>setTripForm({...tripForm, destination: e.target.value})} className="p-2 bg-purple-50/50 rounded-lg outline-none text-xs font-semibold" />
272
+ <input type="number" placeholder="المصاريف" value={tripForm.cost} onChange={(e)=>setTripForm({...tripForm, cost: e.target.value})} className="p-2 bg-purple-50/50 rounded-lg outline-none text-xs font-semibold" />
273
+ <input type="number" placeholder="المداخيل" value={tripForm.income} onChange={(e)=>setTripForm({...tripForm, income: e.target.value})} className="p-2 bg-purple-50/50 rounded-lg outline-none text-xs font-semibold" />
274
+ <button onClick={()=>{if(!tripForm.destination) return; setTrips([...trips, {...tripForm, id: Date.now()}]); setTripForm({destination:'',cost:'',income:'',date:''})}} className="bg-purple-600 text-white p-2 rounded-lg font-bold text-xs shadow-sm">حفظ الرحلة</button>
275
+ </div>
276
+ )}
277
+ <div className="bg-white rounded-2xl shadow-sm border overflow-hidden">
278
+ <table className="w-full text-right text-xs">
279
+ <thead className="bg-purple-50 text-purple-900 border-b text-[11px] font-bold">
280
+ <tr><th className="px-4 py-3">الوجهة</th><th className="px-4 py-3 text-center">مصاريف</th><th className="px-4 py-3 text-center">مداخيل</th><th className="px-4 py-3 text-center">الصافي</th>{isAdmin && <th className="px-4 py-3 text-center">حذف</th>}</tr>
281
+ </thead>
282
+ <tbody className="divide-y divide-purple-50 font-semibold">
283
+ {trips.map(t => (
284
+ <tr key={t.id} className="hover:bg-purple-50/30">
285
+ <td className="px-4 py-2">{t.destination}</td>
286
+ <td className="px-4 py-2 text-rose-500 text-center">{t.cost}</td>
287
+ <td className="px-4 py-2 text-emerald-600 text-center">{t.income}</td>
288
+ <td className="px-4 py-2 text-center font-extrabold text-slate-800">{(t.income - t.cost)} MAD</td>
289
+ {isAdmin && <td className="px-4 py-2 text-center"><button onClick={()=>setTrips(trips.filter(x=>x.id!==t.id))} className="text-purple-200 hover:text-rose-500"><i data-lucide="trash-2" className="w-3.5 h-3.5"></i></button></td>}
290
+ </tr>
291
+ ))}
292
+ </tbody>
293
+ </table>
294
+ </div>
295
+ </div>
296
+ )}
297
+
298
+ {activeTab === 'activities' && (
299
+ <div className="space-y-4">
300
+ <h2 className="text-lg font-extrabold text-rose-800">سجل الأنشطة</h2>
301
+ {isAdmin && (
302
+ <div className="bg-white p-4 rounded-2xl shadow-sm grid grid-cols-1 md:grid-cols-3 gap-2 border border-rose-50">
303
+ <input type="text" placeholder="اسم النشاط" value={activityForm.title} onChange={(e)=>setActivityForm({...activityForm, title: e.target.value})} className="p-2 bg-rose-50/50 rounded-lg outline-none text-xs font-semibold" />
304
+ <input type="number" placeholder="الميزانية المستهلكة" value={activityForm.expenses} onChange={(e)=>setActivityForm({...activityForm, expenses: e.target.value})} className="p-2 bg-rose-50/50 rounded-lg outline-none text-xs font-semibold" />
305
+ <button onClick={()=>{if(!activityForm.title) return; setActivities([...activities, {...activityForm, id: Date.now()}]); setActivityForm({title:'',expenses:'',date:''})}} className="bg-rose-600 text-white p-2 rounded-lg font-bold text-xs shadow-sm">إضافة نشاط</button>
306
+ </div>
307
+ )}
308
+ <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-2">
309
+ {activities.map(a => (
310
+ <div key={a.id} className="p-3 bg-white border border-rose-50 rounded-xl flex justify-between items-center shadow-sm">
311
+ <div>
312
+ <h4 className="font-extrabold text-xs text-slate-800 leading-tight">{a.title}</h4>
313
+ <p className="text-rose-600 font-bold text-[11px]">{a.expenses} MAD</p>
314
+ </div>
315
+ {isAdmin && <button onClick={()=>setActivities(activities.filter(x=>x.id!==a.id))} className="text-slate-200 hover:text-rose-500"><i data-lucide="trash-2" className="w-3.5 h-3.5"></i></button>}
316
+ </div>
317
+ ))}
318
+ {activities.length === 0 && <p className="text-slate-400 text-center col-span-full py-10 text-[11px] font-bold italic">لا توجد أنشطة مسجلة بعد</p>}
319
+ </div>
320
+ </div>
321
+ )}
322
  </main>
323
  </div>
324
  );
 
330
 
331
  <script src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
332
  <script src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
333
+ <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
334
  </body>
335
  </html>