Add enums, AuthService, and integrate backend registration endpoints
All checks were successful
Build frontend / build (push) Successful in 57s
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:
@ -1,7 +1,12 @@
|
||||
import AuthService from '../services/AuthService';
|
||||
|
||||
const API_BASE = process.env.NEXT_PUBLIC_API_URL || 'http://45.93.137.91/api';
|
||||
|
||||
/**
|
||||
* Generic API fetch — attaches auth token, unwraps { data } envelope
|
||||
*/
|
||||
async function apiFetch(endpoint, options = {}) {
|
||||
const token = typeof window !== 'undefined' ? localStorage.getItem('token') : null;
|
||||
const token = AuthService.getToken();
|
||||
|
||||
const headers = {
|
||||
'Content-Type': 'application/json',
|
||||
@ -9,7 +14,7 @@ async function apiFetch(endpoint, options = {}) {
|
||||
...options.headers,
|
||||
};
|
||||
|
||||
console.log('[API] Request:', `${API_BASE}${endpoint}`, options.method || 'GET');
|
||||
console.log('[API] Request:', options.method || 'GET', `${API_BASE}${endpoint}`);
|
||||
|
||||
const res = await fetch(`${API_BASE}${endpoint}`, {
|
||||
...options,
|
||||
@ -38,7 +43,9 @@ async function apiFetch(endpoint, options = {}) {
|
||||
}
|
||||
}
|
||||
|
||||
// Raw fetch for auth (no token, returns full response for status code handling)
|
||||
/**
|
||||
* Auth fetch — no token attached, returns full { status, data, ok } for status-code handling
|
||||
*/
|
||||
async function authFetch(endpoint, body) {
|
||||
console.log('[Auth] Request:', `${API_BASE}${endpoint}`);
|
||||
|
||||
@ -61,7 +68,10 @@ async function authFetch(endpoint, body) {
|
||||
data = text;
|
||||
}
|
||||
|
||||
return { status: res.status, data, ok: res.ok || res.status === 206 };
|
||||
// Build message from response for toast display
|
||||
const message = (typeof data === 'object' && data?.message) ? data.message : null;
|
||||
|
||||
return { status: res.status, data, ok: res.ok || res.status === 206, message };
|
||||
}
|
||||
|
||||
// ─── Rent Properties ───
|
||||
@ -143,9 +153,32 @@ export async function getTerms() {
|
||||
return apiFetch('/Terms/GetTerms');
|
||||
}
|
||||
|
||||
// ─── Auth ───
|
||||
// ─── Auth: Registration ───
|
||||
|
||||
/**
|
||||
* Register a new owner
|
||||
* @param {Object} data — { name, email, phoneNumber, whatsAppNumber, password, ownerType }
|
||||
* @returns {Promise<{status, data, ok, message}>}
|
||||
*/
|
||||
export async function addOwner(data) {
|
||||
console.log('[Auth] Registering owner:', data.email);
|
||||
return authFetch('/Owner/Add', data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a new customer/tenant
|
||||
* @param {Object} data — { name, email, phoneNumber, password, customerType }
|
||||
* @returns {Promise<{status, data, ok, message}>}
|
||||
*/
|
||||
export async function addCustomer(data) {
|
||||
console.log('[Auth] Registering customer:', data.email);
|
||||
return authFetch('/Customer/Add', data);
|
||||
}
|
||||
|
||||
// ─── Auth: Login ───
|
||||
|
||||
export async function loginWithEmail(credential, password) {
|
||||
console.log('[Auth] Login with email:', credential);
|
||||
return authFetch('/Auth/LogInWithEmail', {
|
||||
credential,
|
||||
password,
|
||||
@ -155,6 +188,7 @@ export async function loginWithEmail(credential, password) {
|
||||
}
|
||||
|
||||
export async function loginWithPhone(credential, password) {
|
||||
console.log('[Auth] Login with phone:', credential);
|
||||
return authFetch('/Auth/LogInWithPhoneNumber', {
|
||||
credential,
|
||||
password,
|
||||
@ -163,6 +197,8 @@ export async function loginWithPhone(credential, password) {
|
||||
});
|
||||
}
|
||||
|
||||
// ─── Auth: OTP ───
|
||||
|
||||
export async function sendEmailOTP() {
|
||||
console.log('[Auth] Sending email OTP...');
|
||||
return apiFetch('/Auth/SendEmailOTP', { method: 'POST' });
|
||||
@ -183,7 +219,8 @@ export async function verifyPhone(code) {
|
||||
return authFetch(`/Auth/VerifyPhoneNumber?code=${encodeURIComponent(code)}`, {});
|
||||
}
|
||||
|
||||
// Helpers
|
||||
// ─── Helpers ───
|
||||
|
||||
export function isEmail(value) {
|
||||
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
|
||||
}
|
||||
|
||||
@ -1,41 +1,71 @@
|
||||
export const PROPERTY_STATUS = {
|
||||
AVAILABLE: 'available',
|
||||
BOOKED: 'booked',
|
||||
MAINTENANCE: 'maintenance'
|
||||
};
|
||||
/**
|
||||
* Constants — re-exports from enums for backward compatibility
|
||||
*
|
||||
* New code should import directly from:
|
||||
* import { BuildingType, BookingStatus, City, ... } from '@/app/enums';
|
||||
*
|
||||
* Old imports from '@/app/utils/constants' continue to work.
|
||||
*/
|
||||
|
||||
export const BOOKING_STATUS = {
|
||||
PENDING: 'pending',
|
||||
OWNER_APPROVED: 'owner_approved',
|
||||
ADMIN_APPROVED: 'admin_approved',
|
||||
REJECTED: 'rejected',
|
||||
ACTIVE: 'active',
|
||||
COMPLETED: 'completed',
|
||||
CANCELLED: 'cancelled'
|
||||
};
|
||||
// Re-export all enums
|
||||
export {
|
||||
BuildingType,
|
||||
BuildingTypeLabels,
|
||||
BuildingTypeKeys,
|
||||
BuildingTypeByKey,
|
||||
} from '../enums/BuildingType';
|
||||
|
||||
export const COMMISSION_TYPE = {
|
||||
FROM_OWNER: 'from_owner',
|
||||
FROM_TENANT: 'from_tenant',
|
||||
FROM_BOTH: 'from_both'
|
||||
};
|
||||
export {
|
||||
PropertyStatus,
|
||||
PropertyStatusLabels,
|
||||
PropertyStatusKeys,
|
||||
PropertyStatusByKey,
|
||||
} from '../enums/PropertyStatus';
|
||||
|
||||
export const IDENTITY_TYPE = {
|
||||
SYRIAN: 'syrian',
|
||||
PASSPORT: 'passport'
|
||||
};
|
||||
export {
|
||||
BookingStatus,
|
||||
BookingStatusLabels,
|
||||
BookingStatusColors,
|
||||
} from '../enums/BookingStatus';
|
||||
|
||||
export const PAYMENT_METHOD = {
|
||||
export {
|
||||
CommissionType,
|
||||
CommissionTypeLabels,
|
||||
} from '../enums/CommissionType';
|
||||
|
||||
export {
|
||||
IdentityType,
|
||||
IdentityTypeLabels,
|
||||
IdentityTypeFlags,
|
||||
} from '../enums/IdentityType';
|
||||
|
||||
export {
|
||||
UserRole,
|
||||
UserRoleLabels,
|
||||
UserRoleColors,
|
||||
} from '../enums/UserRole';
|
||||
|
||||
export {
|
||||
City,
|
||||
CitiesList,
|
||||
extractCity,
|
||||
} from '../enums/City';
|
||||
|
||||
export { LoginMethod } from '../enums/LoginMethod';
|
||||
export { OwnerType, OwnerTypeLabels } from '../enums/OwnerType';
|
||||
export { CustomerType, CustomerTypeLabels } from '../enums/CustomerType';
|
||||
|
||||
// ─── Legacy aliases (keep old imports working) ───
|
||||
export const PROPERTY_STATUS = PropertyStatusKeys;
|
||||
export const BOOKING_STATUS = BookingStatus;
|
||||
export const COMMISSION_TYPE = CommissionType;
|
||||
export const IDENTITY_TYPE = IdentityType;
|
||||
export const CITIES = City;
|
||||
|
||||
// ─── Misc constants ───
|
||||
export const PAYMENT_METHOD = Object.freeze({
|
||||
CASH: 'cash',
|
||||
ELECTRONIC: 'electronic'
|
||||
};
|
||||
ELECTRONIC: 'electronic',
|
||||
});
|
||||
|
||||
export const CITIES = {
|
||||
DAMASCUS: 'damascus',
|
||||
ALEPPO: 'aleppo',
|
||||
HOMS: 'homs',
|
||||
LATTAKIA: 'latakia',
|
||||
DARAA: 'daraa'
|
||||
};
|
||||
|
||||
export const DEFAULT_COMMISSION_RATE = 5;
|
||||
export const DEFAULT_COMMISSION_RATE = 5;
|
||||
|
||||
Reference in New Issue
Block a user