updates
This commit is contained in:
@@ -62,6 +62,11 @@ apiClient.interceptors.request.use(
|
||||
config.url = config.url.replace(/\/\/+/, '/');
|
||||
}
|
||||
|
||||
// Handle FormData - remove Content-Type header to let browser set it with boundary
|
||||
if (config.data instanceof FormData) {
|
||||
delete config.headers['Content-Type'];
|
||||
}
|
||||
|
||||
// Add authorization token
|
||||
const token = localStorage.getItem('token');
|
||||
if (token) {
|
||||
|
||||
@@ -212,14 +212,10 @@ const authService = {
|
||||
const formData = new FormData();
|
||||
formData.append('image', file);
|
||||
|
||||
// Don't set Content-Type header - let the browser set it with the correct boundary
|
||||
const response = await apiClient.post<AuthResponse>(
|
||||
'/api/auth/avatar/upload',
|
||||
formData,
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
},
|
||||
}
|
||||
formData
|
||||
);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
@@ -10,8 +10,9 @@ import apiClient from './apiClient';
|
||||
export interface Banner {
|
||||
id: number;
|
||||
title: string;
|
||||
description?: string;
|
||||
image_url: string;
|
||||
link?: string;
|
||||
link_url?: string;
|
||||
position: string;
|
||||
display_order: number;
|
||||
is_active: boolean;
|
||||
@@ -157,13 +158,20 @@ export const createBanner = async (
|
||||
description?: string;
|
||||
image_url: string;
|
||||
link?: string;
|
||||
link_url?: string;
|
||||
position?: string;
|
||||
display_order?: number;
|
||||
start_date?: string;
|
||||
end_date?: string;
|
||||
}
|
||||
): Promise<{ success: boolean; data: { banner: Banner }; message: string }> => {
|
||||
const response = await apiClient.post('/banners', data);
|
||||
// Map link_url to link for backend compatibility
|
||||
const requestData = {
|
||||
...data,
|
||||
link: data.link_url || data.link,
|
||||
};
|
||||
delete requestData.link_url;
|
||||
const response = await apiClient.post('/banners', requestData);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
@@ -177,6 +185,7 @@ export const updateBanner = async (
|
||||
description?: string;
|
||||
image_url?: string;
|
||||
link?: string;
|
||||
link_url?: string;
|
||||
position?: string;
|
||||
display_order?: number;
|
||||
is_active?: boolean;
|
||||
@@ -184,7 +193,13 @@ export const updateBanner = async (
|
||||
end_date?: string;
|
||||
}
|
||||
): Promise<{ success: boolean; data: { banner: Banner }; message: string }> => {
|
||||
const response = await apiClient.put(`/banners/${id}`, data);
|
||||
// Map link_url to link for backend compatibility
|
||||
const requestData = {
|
||||
...data,
|
||||
link: data.link_url || data.link,
|
||||
};
|
||||
delete requestData.link_url;
|
||||
const response = await apiClient.put(`/banners/${id}`, requestData);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
@@ -207,11 +222,8 @@ export const uploadBannerImage = async (
|
||||
const formData = new FormData();
|
||||
formData.append('image', file);
|
||||
|
||||
const response = await apiClient.post('/banners/upload', formData, {
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
},
|
||||
});
|
||||
// Don't set Content-Type header - let the browser set it with the correct boundary
|
||||
const response = await apiClient.post('/banners/upload', formData);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ export interface BookingData {
|
||||
service_id: number;
|
||||
quantity: number;
|
||||
}>;
|
||||
promotion_code?: string;
|
||||
}
|
||||
|
||||
export interface Booking {
|
||||
@@ -205,6 +206,8 @@ export const getAllBookings = async (
|
||||
search?: string;
|
||||
page?: number;
|
||||
limit?: number;
|
||||
startDate?: string;
|
||||
endDate?: string;
|
||||
}
|
||||
): Promise<BookingsResponse> => {
|
||||
const response = await apiClient.get<BookingsResponse>('/bookings', { params });
|
||||
@@ -286,14 +289,10 @@ export const notifyPayment = async (
|
||||
formData.append('receipt', file);
|
||||
}
|
||||
|
||||
// Don't set Content-Type header - let the browser set it with the correct boundary
|
||||
const response = await apiClient.post(
|
||||
'/notify/payment',
|
||||
formData,
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
},
|
||||
}
|
||||
formData
|
||||
);
|
||||
|
||||
return response.data;
|
||||
|
||||
@@ -42,6 +42,8 @@ export interface Invoice {
|
||||
notes?: string;
|
||||
terms_and_conditions?: string;
|
||||
payment_instructions?: string;
|
||||
is_proforma?: boolean;
|
||||
promotion_code?: string;
|
||||
items: InvoiceItem[];
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
|
||||
@@ -34,12 +34,61 @@ export interface PageContent {
|
||||
support_links?: Array<{ label: string; url: string }>;
|
||||
};
|
||||
badges?: Array<{ text: string; icon: string }>;
|
||||
copyright_text?: string;
|
||||
hero_title?: string;
|
||||
hero_subtitle?: string;
|
||||
hero_image?: string;
|
||||
story_content?: string;
|
||||
values?: Array<{ icon?: string; title: string; description: string }>;
|
||||
features?: Array<{ icon?: string; title: string; description: string }>;
|
||||
features?: Array<{ icon?: string; title: string; description: string; image?: string }>;
|
||||
about_hero_image?: string;
|
||||
mission?: string;
|
||||
vision?: string;
|
||||
team?: Array<{ name: string; role: string; image?: string; bio?: string; social_links?: { linkedin?: string; twitter?: string; email?: string } }>;
|
||||
timeline?: Array<{ year: string; title: string; description: string; image?: string }>;
|
||||
achievements?: Array<{ icon?: string; title: string; description: string; year?: string; image?: string }>;
|
||||
// Home page luxury sections
|
||||
luxury_section_title?: string;
|
||||
luxury_section_subtitle?: string;
|
||||
luxury_section_image?: string;
|
||||
luxury_features?: Array<{ icon?: string; title: string; description: string }>;
|
||||
luxury_gallery_section_title?: string;
|
||||
luxury_gallery_section_subtitle?: string;
|
||||
luxury_gallery?: Array<string>;
|
||||
luxury_testimonials_section_title?: string;
|
||||
luxury_testimonials_section_subtitle?: string;
|
||||
luxury_testimonials?: Array<{ name: string; title?: string; quote: string; image?: string }>;
|
||||
amenities_section_title?: string;
|
||||
amenities_section_subtitle?: string;
|
||||
amenities?: Array<{ icon?: string; title: string; description: string; image?: string }>;
|
||||
testimonials_section_title?: string;
|
||||
testimonials_section_subtitle?: string;
|
||||
testimonials?: Array<{ name: string; role: string; image?: string; rating: number; comment: string }>;
|
||||
gallery_section_title?: string;
|
||||
gallery_section_subtitle?: string;
|
||||
gallery_images?: Array<string>;
|
||||
about_preview_title?: string;
|
||||
about_preview_subtitle?: string;
|
||||
about_preview_content?: string;
|
||||
about_preview_image?: string;
|
||||
stats?: Array<{ number: string; label: string; icon?: string }>;
|
||||
luxury_services_section_title?: string;
|
||||
luxury_services_section_subtitle?: string;
|
||||
luxury_services?: Array<{ icon?: string; title: string; description: string; image?: string }>;
|
||||
luxury_experiences_section_title?: string;
|
||||
luxury_experiences_section_subtitle?: string;
|
||||
luxury_experiences?: Array<{ icon?: string; title: string; description: string; image?: string }>;
|
||||
awards_section_title?: string;
|
||||
awards_section_subtitle?: string;
|
||||
awards?: Array<{ icon?: string; title: string; description: string; image?: string; year?: string }>;
|
||||
cta_title?: string;
|
||||
cta_subtitle?: string;
|
||||
cta_button_text?: string;
|
||||
cta_button_link?: string;
|
||||
cta_image?: string;
|
||||
partners_section_title?: string;
|
||||
partners_section_subtitle?: string;
|
||||
partners?: Array<{ name: string; logo: string; link?: string }>;
|
||||
is_active?: boolean;
|
||||
created_at?: string;
|
||||
updated_at?: string;
|
||||
@@ -84,12 +133,61 @@ export interface UpdatePageContentData {
|
||||
support_links?: Array<{ label: string; url: string }>;
|
||||
};
|
||||
badges?: Array<{ text: string; icon: string }>;
|
||||
copyright_text?: string;
|
||||
hero_title?: string;
|
||||
hero_subtitle?: string;
|
||||
hero_image?: string;
|
||||
story_content?: string;
|
||||
values?: Array<{ icon?: string; title: string; description: string }>;
|
||||
features?: Array<{ icon?: string; title: string; description: string }>;
|
||||
features?: Array<{ icon?: string; title: string; description: string; image?: string }>;
|
||||
about_hero_image?: string;
|
||||
mission?: string;
|
||||
vision?: string;
|
||||
team?: Array<{ name: string; role: string; image?: string; bio?: string; social_links?: { linkedin?: string; twitter?: string; email?: string } }>;
|
||||
timeline?: Array<{ year: string; title: string; description: string; image?: string }>;
|
||||
achievements?: Array<{ icon?: string; title: string; description: string; year?: string; image?: string }>;
|
||||
// Home page luxury sections
|
||||
luxury_section_title?: string;
|
||||
luxury_section_subtitle?: string;
|
||||
luxury_section_image?: string;
|
||||
luxury_features?: Array<{ icon?: string; title: string; description: string }>;
|
||||
luxury_gallery_section_title?: string;
|
||||
luxury_gallery_section_subtitle?: string;
|
||||
luxury_gallery?: Array<string>;
|
||||
luxury_testimonials_section_title?: string;
|
||||
luxury_testimonials_section_subtitle?: string;
|
||||
luxury_testimonials?: Array<{ name: string; title?: string; quote: string; image?: string }>;
|
||||
amenities_section_title?: string;
|
||||
amenities_section_subtitle?: string;
|
||||
amenities?: Array<{ icon?: string; title: string; description: string; image?: string }>;
|
||||
testimonials_section_title?: string;
|
||||
testimonials_section_subtitle?: string;
|
||||
testimonials?: Array<{ name: string; role: string; image?: string; rating: number; comment: string }>;
|
||||
gallery_section_title?: string;
|
||||
gallery_section_subtitle?: string;
|
||||
gallery_images?: Array<string>;
|
||||
about_preview_title?: string;
|
||||
about_preview_subtitle?: string;
|
||||
about_preview_content?: string;
|
||||
about_preview_image?: string;
|
||||
stats?: Array<{ number: string; label: string; icon?: string }>;
|
||||
luxury_services_section_title?: string;
|
||||
luxury_services_section_subtitle?: string;
|
||||
luxury_services?: Array<{ icon?: string; title: string; description: string; image?: string }>;
|
||||
luxury_experiences_section_title?: string;
|
||||
luxury_experiences_section_subtitle?: string;
|
||||
luxury_experiences?: Array<{ icon?: string; title: string; description: string; image?: string }>;
|
||||
awards_section_title?: string;
|
||||
awards_section_subtitle?: string;
|
||||
awards?: Array<{ icon?: string; title: string; description: string; image?: string; year?: string }>;
|
||||
cta_title?: string;
|
||||
cta_subtitle?: string;
|
||||
cta_button_text?: string;
|
||||
cta_button_link?: string;
|
||||
cta_image?: string;
|
||||
partners_section_title?: string;
|
||||
partners_section_subtitle?: string;
|
||||
partners?: Array<{ name: string; logo: string; link?: string }>;
|
||||
is_active?: boolean;
|
||||
}
|
||||
|
||||
@@ -103,13 +201,45 @@ const pageContentService = {
|
||||
},
|
||||
|
||||
/**
|
||||
* Get content for a specific page
|
||||
* Get content for a specific page (legacy method - kept for backward compatibility)
|
||||
*/
|
||||
getPageContent: async (pageType: PageType): Promise<PageContentResponse> => {
|
||||
const response = await apiClient.get<PageContentResponse>(`/page-content/${pageType}`);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get homepage content
|
||||
*/
|
||||
getHomeContent: async (): Promise<PageContentResponse> => {
|
||||
const response = await apiClient.get<PageContentResponse>('/home');
|
||||
return response.data;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get about page content
|
||||
*/
|
||||
getAboutContent: async (): Promise<PageContentResponse> => {
|
||||
const response = await apiClient.get<PageContentResponse>('/about');
|
||||
return response.data;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get contact page content
|
||||
*/
|
||||
getContactContent: async (): Promise<PageContentResponse> => {
|
||||
const response = await apiClient.get<PageContentResponse>('/contact-content');
|
||||
return response.data;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get footer content
|
||||
*/
|
||||
getFooterContent: async (): Promise<PageContentResponse> => {
|
||||
const response = await apiClient.get<PageContentResponse>('/footer');
|
||||
return response.data;
|
||||
},
|
||||
|
||||
/**
|
||||
* Update page content
|
||||
*/
|
||||
@@ -162,6 +292,50 @@ const pageContentService = {
|
||||
if (data.features) {
|
||||
updateData.features = data.features; // Send as array, backend will convert to JSON
|
||||
}
|
||||
|
||||
// Handle luxury content arrays
|
||||
if (data.luxury_features) {
|
||||
updateData.luxury_features = data.luxury_features; // Send as array, backend will convert to JSON
|
||||
}
|
||||
if (data.luxury_gallery) {
|
||||
updateData.luxury_gallery = data.luxury_gallery; // Send as array, backend will convert to JSON
|
||||
}
|
||||
if (data.luxury_testimonials) {
|
||||
updateData.luxury_testimonials = data.luxury_testimonials; // Send as array, backend will convert to JSON
|
||||
}
|
||||
if (data.amenities) {
|
||||
updateData.amenities = data.amenities; // Send as array, backend will convert to JSON
|
||||
}
|
||||
if (data.testimonials) {
|
||||
updateData.testimonials = data.testimonials; // Send as array, backend will convert to JSON
|
||||
}
|
||||
if (data.gallery_images) {
|
||||
updateData.gallery_images = data.gallery_images; // Send as array, backend will convert to JSON
|
||||
}
|
||||
if (data.stats) {
|
||||
updateData.stats = data.stats; // Send as array, backend will convert to JSON
|
||||
}
|
||||
if (data.luxury_services) {
|
||||
updateData.luxury_services = data.luxury_services; // Send as array, backend will convert to JSON
|
||||
}
|
||||
if (data.luxury_experiences) {
|
||||
updateData.luxury_experiences = data.luxury_experiences; // Send as array, backend will convert to JSON
|
||||
}
|
||||
if (data.awards) {
|
||||
updateData.awards = data.awards; // Send as array, backend will convert to JSON
|
||||
}
|
||||
if (data.partners) {
|
||||
updateData.partners = data.partners; // Send as array, backend will convert to JSON
|
||||
}
|
||||
if (data.team) {
|
||||
updateData.team = data.team; // Send as array, backend will convert to JSON
|
||||
}
|
||||
if (data.timeline) {
|
||||
updateData.timeline = data.timeline; // Send as array, backend will convert to JSON
|
||||
}
|
||||
if (data.achievements) {
|
||||
updateData.achievements = data.achievements; // Send as array, backend will convert to JSON
|
||||
}
|
||||
|
||||
const response = await apiClient.put<PageContentResponse>(
|
||||
`/page-content/${pageType}`,
|
||||
@@ -169,6 +343,20 @@ const pageContentService = {
|
||||
);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
/**
|
||||
* Upload page content image
|
||||
*/
|
||||
uploadImage: async (
|
||||
file: File
|
||||
): Promise<{ success: boolean; data: { image_url: string; full_url: string }; message: string }> => {
|
||||
const formData = new FormData();
|
||||
formData.append('image', file);
|
||||
|
||||
// Don't set Content-Type header - let the browser set it with the correct boundary
|
||||
const response = await apiClient.post('/page-content/upload', formData);
|
||||
return response.data;
|
||||
},
|
||||
};
|
||||
|
||||
export default pageContentService;
|
||||
|
||||
@@ -97,14 +97,10 @@ export const confirmBankTransfer = async (
|
||||
formData.append('receipt', receipt);
|
||||
}
|
||||
|
||||
// Don't set Content-Type header - let the browser set it with the correct boundary
|
||||
const response = await apiClient.post(
|
||||
'/payments/confirm',
|
||||
formData,
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
},
|
||||
}
|
||||
formData
|
||||
);
|
||||
|
||||
return response.data;
|
||||
|
||||
@@ -322,14 +322,10 @@ const systemSettingsService = {
|
||||
const formData = new FormData();
|
||||
formData.append('image', file);
|
||||
|
||||
// Don't set Content-Type header - let the browser set it with the correct boundary
|
||||
const response = await apiClient.post<UploadLogoResponse>(
|
||||
'/api/admin/system-settings/company/logo',
|
||||
formData,
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
},
|
||||
}
|
||||
formData
|
||||
);
|
||||
return response.data;
|
||||
},
|
||||
@@ -343,14 +339,10 @@ const systemSettingsService = {
|
||||
const formData = new FormData();
|
||||
formData.append('image', file);
|
||||
|
||||
// Don't set Content-Type header - let the browser set it with the correct boundary
|
||||
const response = await apiClient.post<UploadFaviconResponse>(
|
||||
'/api/admin/system-settings/company/favicon',
|
||||
formData,
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
},
|
||||
}
|
||||
formData
|
||||
);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user