166 lines
5.2 KiB
TypeScript
166 lines
5.2 KiB
TypeScript
import type { RegisterHotelStaffDto, StaffAccess } from "@/lib/types";
|
|
|
|
const API_ROOT = "/api";
|
|
|
|
let getPropertyId: () => string | null = () => null;
|
|
|
|
/** Register property scope for hotel auth-API paths (e.g. staff management). */
|
|
export function registerHotelAuthApiContext(ctx: {
|
|
getPropertyId: () => string | null;
|
|
}) {
|
|
getPropertyId = ctx.getPropertyId;
|
|
}
|
|
|
|
function shouldRewriteForHotel(path: string): boolean {
|
|
const first = path.split("?")[0];
|
|
if (first.startsWith("/auth")) return false;
|
|
if (first.startsWith("/properties")) return false;
|
|
if (first.startsWith("/admin")) return false;
|
|
return true;
|
|
}
|
|
|
|
function rewriteHotelPath(path: string): string {
|
|
const pid = getPropertyId();
|
|
if (!pid || !shouldRewriteForHotel(path)) return path;
|
|
|
|
const [pathname, query] = path.split("?");
|
|
const q = query ? `?${query}` : "";
|
|
return `/properties/${pid}/hotel${pathname}${q}`;
|
|
}
|
|
|
|
function apiUrl(path: string): string {
|
|
const base = import.meta.env.VITE_API_BASE_URL ?? "";
|
|
const resolved = rewriteHotelPath(path);
|
|
return `${base}${API_ROOT}${resolved}`;
|
|
}
|
|
|
|
export async function parseApiError(res: Response): Promise<string> {
|
|
const t = await res.text();
|
|
try {
|
|
const j = JSON.parse(t) as { message?: string | string[]; error?: string };
|
|
if (Array.isArray(j.message)) return j.message.join(", ");
|
|
if (typeof j.message === "string") return j.message;
|
|
if (j.error) return j.error;
|
|
} catch {
|
|
/* ignore */
|
|
}
|
|
return t || res.statusText;
|
|
}
|
|
|
|
export type AuthUser = {
|
|
id: string;
|
|
name: string;
|
|
email?: string | null;
|
|
phone?: string | null;
|
|
role: string;
|
|
status?: string;
|
|
propertyId?: string | null;
|
|
};
|
|
|
|
export async function postLogin(identifier: string, password: string) {
|
|
const res = await fetch(apiUrl("/auth/login"), {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({ identifier, password }),
|
|
});
|
|
if (!res.ok) throw new Error(await parseApiError(res));
|
|
return res.json() as Promise<{ access_token: string; user: AuthUser }>;
|
|
}
|
|
|
|
export async function postLoginPhoneRequest(phone: string) {
|
|
const res = await fetch(apiUrl("/auth/login-phone-request"), {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({ phone }),
|
|
});
|
|
if (!res.ok) throw new Error(await parseApiError(res));
|
|
return res.json() as Promise<{
|
|
message: string;
|
|
loginRequestToken?: string;
|
|
}>;
|
|
}
|
|
|
|
export async function postLoginPhoneVerify(loginRequestToken: string, otp: string) {
|
|
const res = await fetch(apiUrl("/auth/login-phone-verify"), {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({ loginRequestToken, otp }),
|
|
});
|
|
if (!res.ok) throw new Error(await parseApiError(res));
|
|
return res.json() as Promise<{ access_token: string; user: AuthUser }>;
|
|
}
|
|
|
|
export async function postSendOtp(identifier: string) {
|
|
const res = await fetch(apiUrl("/auth/sendOtp"), {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({ identifier: identifier.trim() }),
|
|
});
|
|
if (!res.ok) throw new Error(await parseApiError(res));
|
|
return res.json() as Promise<{ message: string }>;
|
|
}
|
|
|
|
export async function postHotelGuestLoginEmailOtp(email: string, otp: string) {
|
|
const res = await fetch(apiUrl("/auth/hotel-user/login-email-otp"), {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({ email: email.trim().toLowerCase(), otp: otp.trim() }),
|
|
});
|
|
if (!res.ok) throw new Error(await parseApiError(res));
|
|
return res.json() as Promise<{ access_token: string; user: AuthUser }>;
|
|
}
|
|
|
|
export type PropertyRow = {
|
|
id: string;
|
|
name: string;
|
|
accommodationMode?: string;
|
|
};
|
|
|
|
export async function getProfile(token: string) {
|
|
const res = await fetch(apiUrl("/auth/profile"), {
|
|
headers: { Authorization: `Bearer ${token}` },
|
|
});
|
|
if (!res.ok) throw new Error(await parseApiError(res));
|
|
return res.json() as Promise<AuthUser & Record<string, unknown>>;
|
|
}
|
|
|
|
export async function getProperties(token: string) {
|
|
const res = await fetch(apiUrl("/properties/hotels"), {
|
|
headers: { Authorization: `Bearer ${token}` },
|
|
});
|
|
if (!res.ok) throw new Error(await parseApiError(res));
|
|
return res.json() as Promise<PropertyRow[]>;
|
|
}
|
|
|
|
export async function getStaffAccess(token: string) {
|
|
const res = await fetch(apiUrl("/staff-access"), {
|
|
headers: { Authorization: `Bearer ${token}` },
|
|
});
|
|
if (!res.ok) throw new Error(await parseApiError(res));
|
|
const data = await res.json();
|
|
return data.data || data as StaffAccess[];
|
|
}
|
|
|
|
|
|
export async function postStaff(token: string, dto: RegisterHotelStaffDto) {
|
|
const res = await fetch(apiUrl("/staff"), {
|
|
method: "POST",
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
Authorization: `Bearer ${token}`
|
|
},
|
|
body: JSON.stringify(dto),
|
|
});
|
|
if (!res.ok) throw new Error(await parseApiError(res));
|
|
return res.json() as Promise<StaffAccess>;
|
|
}
|
|
|
|
export async function deleteStaffAccess(token: string, accessId: string) {
|
|
const res = await fetch(apiUrl(`/staff-access/${accessId}`), {
|
|
method: "DELETE",
|
|
headers: { Authorization: `Bearer ${token}` },
|
|
});
|
|
if (!res.ok) throw new Error(await parseApiError(res));
|
|
return;
|
|
}
|