Edit admin page

Edit home image
Added properties page
This commit is contained in:
Rahaf
2026-02-15 01:53:37 +03:00
parent 61c16f6cec
commit 6d81ff56a8
19 changed files with 4200 additions and 828 deletions

View File

@ -0,0 +1,103 @@
'use client';
import { createContext, useContext, useState, useCallback } from 'react';
const PropertyContext = createContext();
export const useProperties = () => {
const context = useContext(PropertyContext);
if (!context) {
throw new Error('useProperties must be used within PropertyProvider');
}
return context;
};
export const PropertyProvider = ({ children }) => {
const [properties, setProperties] = useState([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const addProperty = useCallback(async (propertyData) => {
setLoading(true);
try {
const newProperty = {
id: Date.now().toString(),
...propertyData,
createdAt: new Date().toISOString(),
status: 'available',
bookings: [],
commission: {
rate: propertyData.commissionRate || 5,
type: propertyData.commissionType || 'from_owner',
isActive: true
}
};
setProperties(prev => [...prev, newProperty]);
return newProperty;
} catch (err) {
setError(err.message);
throw err;
} finally {
setLoading(false);
}
}, []);
const updateProperty = useCallback(async (id, updates) => {
setLoading(true);
try {
setProperties(prev =>
prev.map(p => p.id === id ? { ...p, ...updates } : p)
);
} catch (err) {
setError(err.message);
throw err;
} finally {
setLoading(false);
}
}, []);
const deleteProperty = useCallback(async (id) => {
setLoading(true);
try {
setProperties(prev => prev.filter(p => p.id !== id));
} catch (err) {
setError(err.message);
throw err;
} finally {
setLoading(false);
}
}, []);
const checkAvailability = useCallback((propertyId, startDate, endDate) => {
const property = properties.find(p => p.id === propertyId);
if (!property) return false;
return !property.bookings?.some(booking => {
const bookingStart = new Date(booking.startDate);
const bookingEnd = new Date(booking.endDate);
const checkStart = new Date(startDate);
const checkEnd = new Date(endDate);
return (
(checkStart >= bookingStart && checkStart <= bookingEnd) ||
(checkEnd >= bookingStart && checkEnd <= bookingEnd) ||
(checkStart <= bookingStart && checkEnd >= bookingEnd)
);
});
}, [properties]);
return (
<PropertyContext.Provider value={{
properties,
loading,
error,
addProperty,
updateProperty,
deleteProperty,
checkAvailability
}}>
{children}
</PropertyContext.Provider>
);
};

67
app/utils/calculations.js Normal file
View File

@ -0,0 +1,67 @@
export const calculateRentWithCommission = (
dailyPrice,
numberOfDays,
commissionRate,
commissionType
) => {
const baseRent = dailyPrice * numberOfDays;
const commission = (baseRent * commissionRate) / 100;
switch(commissionType) {
case 'from_tenant':
return {
totalForTenant: baseRent + commission,
totalForOwner: baseRent,
commission: commission
};
case 'from_owner':
return {
totalForTenant: baseRent,
totalForOwner: baseRent - commission,
commission: commission
};
case 'from_both':
return {
totalForTenant: baseRent + (commission / 2),
totalForOwner: baseRent - (commission / 2),
commission: commission
};
default:
return {
totalForTenant: baseRent,
totalForOwner: baseRent,
commission: 0
};
}
};
export const calculateDaysBetween = (startDate, endDate) => {
const start = new Date(startDate);
const end = new Date(endDate);
const diffTime = Math.abs(end - start);
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
return diffDays;
};
export const formatCurrency = (amount) => {
return new Intl.NumberFormat('ar-SY', {
style: 'currency',
currency: 'SYP',
minimumFractionDigits: 0,
maximumFractionDigits: 0
}).format(amount).replace('SYP', '') + ' ل.س';
};
export const calculateTenantBalance = (bookings, securityDeposits) => {
return bookings.reduce((acc, booking) => {
const deposit = securityDeposits.find(d => d.bookingId === booking.id) || 0;
return {
totalRent: acc.totalRent + booking.totalAmount,
paidAmount: acc.paidAmount + booking.paidAmount,
securityDeposit: acc.securityDeposit + deposit.amount,
pendingAmount: (acc.pendingAmount + (booking.totalAmount - booking.paidAmount))
};
}, { totalRent: 0, paidAmount: 0, securityDeposit: 0, pendingAmount: 0 });
};

41
app/utils/constants.js Normal file
View File

@ -0,0 +1,41 @@
export const PROPERTY_STATUS = {
AVAILABLE: 'available',
BOOKED: 'booked',
MAINTENANCE: 'maintenance'
};
export const BOOKING_STATUS = {
PENDING: 'pending',
OWNER_APPROVED: 'owner_approved',
ADMIN_APPROVED: 'admin_approved',
REJECTED: 'rejected',
ACTIVE: 'active',
COMPLETED: 'completed',
CANCELLED: 'cancelled'
};
export const COMMISSION_TYPE = {
FROM_OWNER: 'from_owner',
FROM_TENANT: 'from_tenant',
FROM_BOTH: 'from_both'
};
export const IDENTITY_TYPE = {
SYRIAN: 'syrian',
PASSPORT: 'passport'
};
export const PAYMENT_METHOD = {
CASH: 'cash',
ELECTRONIC: 'electronic'
};
export const CITIES = {
DAMASCUS: 'damascus',
ALEPPO: 'aleppo',
HOMS: 'homs',
LATTAKIA: 'latakia',
DARAA: 'daraa'
};
export const DEFAULT_COMMISSION_RATE = 5;