Add enums, AuthService, and integrate backend registration endpoints
All checks were successful
Build frontend / build (push) Successful in 57s

- Add separate enum files: BuildingType, PropertyStatus, BookingStatus, CommissionType, IdentityType, UserRole, City, LoginMethod, OwnerType, CustomerType
- Add AuthService (addToken/getToken/deleteToken)
- Update api.js: use AuthService, add Owner/Add and Customer/Add endpoints
- Update login page to use AuthService for token storage
- Rewrite owner register: 3-step flow with OwnerType dropdown, backend integration, OTP verification
- Rewrite tenant register: 2-step flow with CustomerType dropdown, backend integration, OTP verification
- Update homepage and property detail to use enums instead of hardcoded maps
- Update AddPropertyForm to import from enums directly
- Add console logs and status toasts linked to API response messages
This commit is contained in:
Claw AI
2026-03-27 18:01:42 +00:00
parent 2fb55db360
commit eff0b41b78
20 changed files with 1099 additions and 843 deletions

View File

@ -0,0 +1,38 @@
/**
* BookingStatus Enum
* Backend values are strings
* Used in: Reservation workflow
*/
const BookingStatus = Object.freeze({
PENDING: 'pending',
OWNER_APPROVED: 'owner_approved',
ADMIN_APPROVED: 'admin_approved',
ACTIVE: 'active',
COMPLETED: 'completed',
REJECTED: 'rejected',
CANCELLED: 'cancelled',
});
// Map status → Arabic label
const BookingStatusLabels = Object.freeze({
[BookingStatus.PENDING]: 'بانتظار الموافقة',
[BookingStatus.OWNER_APPROVED]: 'موافقة المالك',
[BookingStatus.ADMIN_APPROVED]: 'موافقة الإدارة',
[BookingStatus.ACTIVE]: 'إيجار نشط',
[BookingStatus.COMPLETED]: 'منتهي',
[BookingStatus.REJECTED]: 'مرفوض',
[BookingStatus.CANCELLED]: 'ملغي',
});
// Map status → color class (Tailwind bg)
const BookingStatusColors = Object.freeze({
[BookingStatus.PENDING]: 'yellow',
[BookingStatus.OWNER_APPROVED]: 'blue',
[BookingStatus.ADMIN_APPROVED]: 'green',
[BookingStatus.ACTIVE]: 'purple',
[BookingStatus.COMPLETED]: 'gray',
[BookingStatus.REJECTED]: 'red',
[BookingStatus.CANCELLED]: 'red',
});
export { BookingStatus, BookingStatusLabels, BookingStatusColors };

33
app/enums/BuildingType.js Normal file
View File

@ -0,0 +1,33 @@
/**
* BuildingType Enum
* Backend values are numeric (0, 1, 2)
* Used in: PropertyInformation.buildingType
*/
const BuildingType = Object.freeze({
APARTMENT: 0,
VILLA: 1,
HOUSE: 2,
});
// Map numeric value → Arabic label
const BuildingTypeLabels = Object.freeze({
[BuildingType.APARTMENT]: 'شقة',
[BuildingType.VILLA]: 'فيلا',
[BuildingType.HOUSE]: 'بيت',
});
// Map numeric value → English key (for UI filters)
const BuildingTypeKeys = Object.freeze({
[BuildingType.APARTMENT]: 'apartment',
[BuildingType.VILLA]: 'villa',
[BuildingType.HOUSE]: 'house',
});
// Reverse map: English key → numeric value
const BuildingTypeByKey = Object.freeze({
apartment: BuildingType.APARTMENT,
villa: BuildingType.VILLA,
house: BuildingType.HOUSE,
});
export { BuildingType, BuildingTypeLabels, BuildingTypeKeys, BuildingTypeByKey };

38
app/enums/City.js Normal file
View File

@ -0,0 +1,38 @@
/**
* City Enum
* Syrian cities used in property locations
* Used in: Property search filters, location display
*/
const City = Object.freeze({
DAMASCUS: 'دمشق',
ALEPPO: 'حلب',
HOMS: 'حمص',
LATAKIA: 'اللاذقية',
DARAA: 'درعا',
TARTOUS: 'طرطوس',
SUWEIDA: 'السويداء',
DEIR_EZZOR: 'دير الزور',
RAQQA: 'الرقة',
IDLIB: 'إدلب',
HASAKAH: 'الحسكة',
QAMISHLI: 'القامشلي',
RURAL_DAMASCUS: 'ريف دمشق',
});
// All cities as a flat array
const CitiesList = Object.freeze(Object.values(City));
/**
* Extract city name from a full address string
* @param {string} address
* @returns {string}
*/
function extractCity(address) {
if (!address) return '';
for (const city of CitiesList) {
if (address.includes(city)) return city;
}
return '';
}
export { City, CitiesList, extractCity };

View File

@ -0,0 +1,19 @@
/**
* CommissionType Enum
* Defines who pays the platform commission
* Used in: Property pricing, booking financials
*/
const CommissionType = Object.freeze({
FROM_OWNER: 'from_owner',
FROM_TENANT: 'from_tenant',
FROM_BOTH: 'from_both',
});
// Map type → Arabic label
const CommissionTypeLabels = Object.freeze({
[CommissionType.FROM_OWNER]: 'من المالك',
[CommissionType.FROM_TENANT]: 'من المستأجر',
[CommissionType.FROM_BOTH]: 'من الاثنين',
});
export { CommissionType, CommissionTypeLabels };

17
app/enums/CustomerType.js Normal file
View File

@ -0,0 +1,17 @@
/**
* CustomerType Enum
* Backend values for customer sub-types
* Used in: Customer registration (Customer/Add)
*/
const CustomerType = Object.freeze({
PERSONAL: 'Personal',
FAMILY: 'Family',
});
// Map value → Arabic label
const CustomerTypeLabels = Object.freeze({
[CustomerType.PERSONAL]: 'شخصي',
[CustomerType.FAMILY]: 'عائلي',
});
export { CustomerType, CustomerTypeLabels };

23
app/enums/IdentityType.js Normal file
View File

@ -0,0 +1,23 @@
/**
* IdentityType Enum
* Tenant identity document type
* Used in: Property booking, allowedIdentities filter
*/
const IdentityType = Object.freeze({
SYRIAN: 'syrian',
PASSPORT: 'passport',
});
// Map type → Arabic label
const IdentityTypeLabels = Object.freeze({
[IdentityType.SYRIAN]: 'هوية سورية',
[IdentityType.PASSPORT]: 'جواز سفر',
});
// Map type → flag emoji
const IdentityTypeFlags = Object.freeze({
[IdentityType.SYRIAN]: '🇸🇾',
[IdentityType.PASSPORT]: '🛂',
});
export { IdentityType, IdentityTypeLabels, IdentityTypeFlags };

11
app/enums/LoginMethod.js Normal file
View File

@ -0,0 +1,11 @@
/**
* LoginMethod Enum
* Authentication method type
* Used in: Login page, OTP verification
*/
const LoginMethod = Object.freeze({
EMAIL: 'email',
PHONE: 'phone',
});
export { LoginMethod };

17
app/enums/OwnerType.js Normal file
View File

@ -0,0 +1,17 @@
/**
* OwnerType Enum
* Backend values for owner sub-types
* Used in: Owner registration (Owner/Add)
*/
const OwnerType = Object.freeze({
PERSON: 'peerson',
REAL_ESTATE_AGENCY: 'RealEstateAgency',
});
// Map value → Arabic label
const OwnerTypeLabels = Object.freeze({
[OwnerType.PERSON]: 'شخص',
[OwnerType.REAL_ESTATE_AGENCY]: 'وكالة عقارية',
});
export { OwnerType, OwnerTypeLabels };

View File

@ -0,0 +1,33 @@
/**
* PropertyStatus Enum
* Backend values are numeric (0, 1, 2)
* Used in: PropertyInformation.status
*/
const PropertyStatus = Object.freeze({
AVAILABLE: 0,
BOOKED: 1,
MAINTENANCE: 2,
});
// Map numeric value → Arabic label
const PropertyStatusLabels = Object.freeze({
[PropertyStatus.AVAILABLE]: 'متاح',
[PropertyStatus.BOOKED]: 'محجوز',
[PropertyStatus.MAINTENANCE]: 'صيانة',
});
// Map numeric value → English key (for UI filters)
const PropertyStatusKeys = Object.freeze({
[PropertyStatus.AVAILABLE]: 'available',
[PropertyStatus.BOOKED]: 'booked',
[PropertyStatus.MAINTENANCE]: 'maintenance',
});
// Reverse map: English key → numeric value
const PropertyStatusByKey = Object.freeze({
available: PropertyStatus.AVAILABLE,
booked: PropertyStatus.BOOKED,
maintenance: PropertyStatus.MAINTENANCE,
});
export { PropertyStatus, PropertyStatusLabels, PropertyStatusKeys, PropertyStatusByKey };

26
app/enums/UserRole.js Normal file
View File

@ -0,0 +1,26 @@
/**
* UserRole Enum
* User account roles in the system
* Used in: JWT payload, registration, routing
*/
const UserRole = Object.freeze({
OWNER: 'owner',
TENANT: 'tenant',
ADMIN: 'admin',
});
// Map role → Arabic label
const UserRoleLabels = Object.freeze({
[UserRole.OWNER]: 'مالك عقار',
[UserRole.TENANT]: 'مستأجر',
[UserRole.ADMIN]: 'مدير النظام',
});
// Map role → color theme (used in UI)
const UserRoleColors = Object.freeze({
[UserRole.OWNER]: 'amber',
[UserRole.TENANT]: 'blue',
[UserRole.ADMIN]: 'red',
});
export { UserRole, UserRoleLabels, UserRoleColors };

15
app/enums/index.js Normal file
View File

@ -0,0 +1,15 @@
/**
* Enums Index
* Central export for all enum modules
*/
export { BuildingType, BuildingTypeLabels, BuildingTypeKeys, BuildingTypeByKey } from './BuildingType';
export { PropertyStatus, PropertyStatusLabels, PropertyStatusKeys, PropertyStatusByKey } from './PropertyStatus';
export { BookingStatus, BookingStatusLabels, BookingStatusColors } from './BookingStatus';
export { CommissionType, CommissionTypeLabels } from './CommissionType';
export { IdentityType, IdentityTypeLabels, IdentityTypeFlags } from './IdentityType';
export { UserRole, UserRoleLabels, UserRoleColors } from './UserRole';
export { City, CitiesList, extractCity } from './City';
export { LoginMethod } from './LoginMethod';
export { OwnerType, OwnerTypeLabels } from './OwnerType';
export { CustomerType, CustomerTypeLabels } from './CustomerType';