الحمل والعناية بالطفل

ابحث هنا عن اسم لعبتك ً

import React, { useState, useEffect } from 'react'; import { initializeApp } from 'firebase/app'; import { getAuth, signInAnonymously, signInWithCustomToken, onAuthStateChanged } from 'firebase/auth'; import { getFirestore, doc, getDoc, addDoc, setDoc, updateDoc, deleteDoc, onSnapshot, collection, query, where, getDocs } from 'firebase/firestore'; // Main App component const App = () => { const [employees, setEmployees] = useState([]); const [newEmployeeName, setNewEmployeeName] = useState(''); const [currentMonth, setCurrentMonth] = useState(new Date().getMonth()); const [currentYear, setCurrentYear] = useState(new Date().getFullYear()); const [showAttendanceModal, setShowAttendanceModal] = useState(false); const [selectedEmployeeForAttendance, setSelectedEmployeeForAttendance] = useState(null); const [showDetailsModal, setShowDetailsModal] = useState(false); const [selectedEmployeeForDetails, setSelectedEmployeeForDetails] = useState(null); // Firestore states const [db, setDb] = useState(null); const [auth, setAuth] = useState(null); const [userId, setUserId] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); // Initialize Firebase and set up authentication listener useEffect(() => { try { const appId = typeof __app_id !== 'undefined' ? __app_id : 'default-app-id'; const firebaseConfig = typeof __firebase_config !== 'undefined' ? JSON.parse(__firebase_config) : {}; const app = initializeApp(firebaseConfig); const firestore = getFirestore(app); const firebaseAuth = getAuth(app); setDb(firestore); setAuth(firebaseAuth); const unsubscribe = onAuthStateChanged(firebaseAuth, async (user) => { if (user) { setUserId(user.uid); } else { // Sign in anonymously if no token or user try { if (typeof __initial_auth_token !== 'undefined' && __initial_auth_token) { await signInWithCustomToken(firebaseAuth, __initial_auth_token); } else { await signInAnonymously(firebaseAuth); } } catch (authError) { console.error("Firebase Auth Error:", authError); setError("فشل المصادقة مع Firebase: " + authError.message); setLoading(false); } } }); return () => unsubscribe(); // Cleanup auth listener } catch (e) { console.error("Firebase Initialization Error:", e); setError("خطأ في تهيئة Firebase: " + e.message); setLoading(false); } }, []); // Fetch employees data from Firestore when db or userId changes useEffect(() => { if (!db || !userId) { if (!db && !auth && !loading) { // Only set loading to true if not already initializing setLoading(true); } return; } const employeesCollectionRef = collection(db, `artifacts/${__app_id}/users/${userId}/employees`); const unsubscribe = onSnapshot(employeesCollectionRef, (snapshot) => { const employeesData = snapshot.docs.map(doc => ({ id: doc.id, // Firestore document ID is used as employee ID ...doc.data(), })); setEmployees(employeesData); setLoading(false); setError(null); // Clear any previous errors }, (err) => { console.error("Failed to fetch employees:", err); setError("فشل في تحميل بيانات الموظفين: " + err.message); setLoading(false); }); return () => unsubscribe(); // Cleanup Firestore listener }, [db, userId, __app_id]); // Depend on db, userId, and __app_id // Function to handle changes in input fields in the main table (monthlySalary, bonus, deduction) const handleTableInputChange = async (id, field, value) => { if (!db || !userId) { console.error("Firestore not initialized or user not logged in."); setError("قاعدة البيانات غير جاهزة أو المستخدم غير مسجل الدخول."); return; } const employeeDocRef = doc(db, `artifacts/${__app_id}/users/${userId}/employees`, id); try { await updateDoc(employeeDocRef, { [field]: parseFloat(value) || 0 // Parse numeric values }); } catch (e) { console.error(`Error updating employee ${field}:`, e); setError(`فشل تحديث حقل ${field} للموظف: ` + e.message); } }; // Function to handle changes in employee details modal inputs const handleDetailsModalInputChange = async (field, value) => { if (!db || !userId || !selectedEmployeeForDetails) { console.error("Firestore not initialized, user not logged in, or no employee selected."); setError("قاعدة البيانات غير جاهزة أو لا يوجد موظف محدد."); return; } let processedValue = value; if (['monthlySalary', 'allowedLeaveDays'].includes(field)) { processedValue = parseFloat(value) || 0; } else if (field === 'peopleOfDetermination') { processedValue = value; // Checkbox value is boolean } const employeeDocRef = doc(db, `artifacts/${__app_id}/users/${userId}/employees`, selectedEmployeeForDetails.id); try { await updateDoc(employeeDocRef, { [field]: processedValue }); // Update the local state of the modal's selected employee for immediate UI feedback setSelectedEmployeeForDetails(prevSelected => ({ ...prevSelected, [field]: processedValue, })); } catch (e) { console.error(`Error updating employee details ${field}:`, e); setError(`فشل تحديث تفاصيل الموظف ${field}: ` + e.message); } }; // Function to add a new employee to the list const addEmployee = async () => { if (!db || !userId) { console.error("Firestore not initialized or user not logged in."); setError("قاعدة البيانات غير جاهزة أو المستخدم غير مسجل الدخول."); return; } if (newEmployeeName.trim() === '') { console.error('الرجاء إدخال اسم الموظف الجديد.'); return; } try { const docRef = await addDoc(collection(db, `artifacts/${__app_id}/users/${userId}/employees`), { name: newEmployeeName.trim(), monthlySalary: 5000, allowedLeaveDays: 4, absentDates: [], bonus: 0, deduction: 0, nationalId: '', nationality: '', maritalStatus: 'أعزب', peopleOfDetermination: false, jobTitle: '', }); setNewEmployeeName(''); } catch (e) { console.error("Error adding document: ", e); setError("فشل إضافة موظف جديد: " + e.message); } }; // Function to delete an employee from the list const deleteEmployee = async (idToDelete) => { if (!db || !userId) { console.error("Firestore not initialized or user not logged in."); setError("قاعدة البيانات غير جاهزة أو المستخدم غير مسجل الدخول."); return; } try { await deleteDoc(doc(db, `artifacts/${__app_id}/users/${userId}/employees`, idToDelete)); } catch (e) { console.error("Error deleting document: ", e); setError("فشل حذف الموظف: " + e.message); } }; // Function to open the attendance calendar modal for a specific employee const openAttendanceCalendarModal = (employee) => { setSelectedEmployeeForAttendance(employee); setShowAttendanceModal(true); }; // Function to close the attendance calendar modal const closeAttendanceCalendarModal = () => { setShowAttendanceModal(false); setSelectedEmployeeForAttendance(null); }; // Function to open the employee details modal const openEmployeeDetailsModal = (employee) => { setSelectedEmployeeForDetails(employee); setShowDetailsModal(true); }; // Function to close the employee details modal const closeEmployeeDetailsModal = () => { setShowDetailsModal(false); setSelectedEmployeeForDetails(null); }; // Function to toggle an absent date for the selected employee in calendar modal const toggleAbsentDate = async (date) => { if (!db || !userId || !selectedEmployeeForAttendance) { console.error("Firestore not initialized, user not logged in, or no employee selected."); setError("قاعدة البيانات غير جاهزة أو لا يوجد موظف محدد."); return; } const dateString = `${currentYear}-${(currentMonth + 1).toString().padStart(2, '0')}-${date.toString().padStart(2, '0')}`; const isCurrentlyAbsent = selectedEmployeeForAttendance.absentDates.includes(dateString); const newAbsentDates = isCurrentlyAbsent ? selectedEmployeeForAttendance.absentDates.filter(d => d !== dateString) : [...selectedEmployeeForAttendance.absentDates, dateString]; const employeeDocRef = doc(db, `artifacts/${__app_id}/users/${userId}/employees`, selectedEmployeeForAttendance.id); try { await updateDoc(employeeDocRef, { absentDates: newAbsentDates }); // Update the local state of the modal's selected employee for immediate UI feedback setSelectedEmployeeForAttendance(prevSelected => ({ ...prevSelected, absentDates: newAbsentDates, })); } catch (e) { console.error("Error toggling absent date: ", e); setError("فشل تحديث أيام الغياب: " + e.message); } }; // Function to navigate calendar month const changeMonth = (delta) => { let newMonth = currentMonth + delta; let newYear = currentYear; if (newMonth > 11) { newMonth = 0; newYear++; } else if (newMonth < 0) { newMonth = 11; newYear--; } setCurrentMonth(newMonth); setCurrentYear(newYear); }; // Utility to get the number of days in a given month and year const getDaysInMonth = (year, month) => { return new Date(year, month + 1, 0).getDate(); }; // Utility to get the first day of the week for a given month and year (0=Sunday, 1=Monday...) const getFirstDayOfMonth = (year, month) => { return new Date(year, month, 1).getDay(); }; // Function to calculate salary details for a single employee const calculateEmployeeSalary = (employee) => { const { monthlySalary, allowedLeaveDays, bonus, deduction } = employee; // Get total days in the currently selected month const totalDaysInCurrentMonth = getDaysInMonth(currentYear, currentMonth); // Filter absent dates relevant to the current month and year const absentDaysInCurrentMonth = (employee.absentDates || []).filter(dateString => { const [year, month, day] = dateString.split('-').map(Number); return year === currentYear && (month - 1) === currentMonth; // month is 1-indexed in string }).length; // Calculate absent days const absentDays = absentDaysInCurrentMonth; // Calculate present days (total days in month - absent days) const daysPresent = totalDaysInCurrentMonth - absentDays; // Define the deduction percentage per excess absent day const deductionPercentagePerExcessDay = 0.07; // 7% from total monthly salary // Calculate excess absent days (beyond allowed leave) const excessAbsentDays = Math.max(0, absentDays - allowedLeaveDays); // Calculate deduction for excess absent days based on a percentage of monthly salary const absenceDeduction = excessAbsentDays * (monthlySalary * deductionPercentagePerExcessDay); // Calculate net salary const netSalary = monthlySalary - absenceDeduction + bonus - deduction; return { absentDays: absentDays, excessAbsentDays: excessAbsentDays, absenceDeduction: absenceDeduction, netSalary: netSalary, daysPresent: daysPresent, // Also return daysPresent for display }; }; // Month names for display const monthNames = [ 'يناير', 'فبراير', 'مارس', 'أبريل', 'مايو', 'يونيو', 'يوليو', 'أغسطس', 'سبتمبر', 'أكتوبر', 'نوفمبر', 'ديسمبر' ]; // Days of the week for calendar header const dayNames = ['أحد', 'اثنين', 'ثلاثاء', 'أربعاء', 'خميس', 'جمعة', 'سبت']; // Render the main application UI return (

جدول الحضور والرواتب

{error && (
خطأ! {error}
)} {userId && (

معرف المستخدم (للتخزين): {userId}

)} {/* Section for adding a new employee */}
setNewEmployeeName(e.target.value)} className="flex-grow p-3 border border-blue-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500 text-right" dir="rtl" disabled={loading} />
{/* Calendar Navigation */}
{loading ? (

جاري تحميل البيانات...

) : (
{employees.length === 0 ? ( ) : ( employees.map(employee => { const { absentDays, excessAbsentDays, absenceDeduction, netSalary, daysPresent } = calculateEmployeeSalary(employee); return ( {/* Employee Name & Job Title - Clickable to open details modal */} ); }) )}
اسم الموظف الراتب الشهري (ر.ق) أيام الحضور (في {monthNames[currentMonth]}) أيام الغياب (في {monthNames[currentMonth]}) أيام الغياب الزائدة خصم الغياب (ر.ق) مكافأة (ر.ق) خصم إضافي (ر.ق) الراتب الصافي (ر.ق) إجراءات
لا يوجد موظفون مضافون حتى الآن. ابدأ بإضافة موظف جديد!
openEmployeeDetailsModal(employee)} title="اضغط لعرض/تعديل تفاصيل الموظف" >
{employee.name}
{employee.jobTitle && (
{employee.jobTitle}
)}
handleTableInputChange(employee.id, 'monthlySalary', e.target.value)} className="w-24 p-2 border border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500 transition duration-150 ease-in-out text-center" disabled={loading} /> openAttendanceCalendarModal(employee)} title="اضغط لتحديد أيام الغياب" > {daysPresent} {absentDays} {excessAbsentDays} {absenceDeduction.toFixed(2)} handleTableInputChange(employee.id, 'bonus', e.target.value)} className="w-24 p-2 border border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500 transition duration-150 ease-in-out text-center" disabled={loading} /> handleTableInputChange(employee.id, 'deduction', e.target.value)} className="w-24 p-2 border border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500 transition duration-150 ease-in-out text-center" disabled={loading} /> {netSalary.toFixed(2)}
)}
{/* Attendance Calendar Modal */} {showAttendanceModal && selectedEmployeeForAttendance && (

تحديد أيام غياب {selectedEmployeeForAttendance.name}

للشهر: {monthNames[currentMonth]} {currentYear}

{/* Calendar grid */}
{dayNames.map(day => (
{day}
))} {/* Render empty cells for days before the 1st of the month */} {[...Array(getFirstDayOfMonth(currentYear, currentMonth))].map((_, i) => (
))} {/* Render actual days of the month */} {[...Array(getDaysInMonth(currentYear, currentMonth))].map((_, i) => { const day = i + 1; const dateString = `${currentYear}-${(currentMonth + 1).toString().padStart(2, '0')}-${day.toString().padStart(2, '0')}`; const isAbsent = (selectedEmployeeForAttendance.absentDates || []).includes(dateString); return (
toggleAbsentDate(day)} > {day}
); })}
)} {/* Employee Details Modal */} {showDetailsModal && selectedEmployeeForDetails && (

تفاصيل الموظف: {selectedEmployeeForDetails.name}

{/* Employee Name - now editable in modal */}
handleDetailsModalInputChange('name', e.target.value)} className="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline focus:ring-blue-500 focus:border-blue-500" dir="rtl" />
{/* Allowed Leave Days - Moved to details modal */}
handleDetailsModalInputChange('allowedLeaveDays', e.target.value)} className="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline focus:ring-blue-500 focus:border-blue-500" dir="rtl" />
{/* Job Title */}
handleDetailsModalInputChange('jobTitle', e.target.value)} className="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline focus:ring-blue-500 focus:border-blue-500" dir="rtl" />
{/* National ID */}
handleDetailsModalInputChange('nationalId', e.target.value)} className="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline focus:ring-blue-500 focus:border-blue-500" dir="rtl" />
{/* Nationality */}
handleDetailsModalInputChange('nationality', e.target.value)} className="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline focus:ring-blue-500 focus:border-blue-500" dir="rtl" />
{/* Marital Status */}
{/* People of Determination */}
handleDetailsModalInputChange('peopleOfDetermination', e.target.checked)} className="form-checkbox h-5 w-5 text-blue-600 rounded focus:ring-blue-500 transition duration-150 ease-in-out" />
)} ); }; export default App;
شاهد المقال

color switch apk

شاهد المقال