update
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
import apiClient from '../../../shared/services/apiClient';
|
||||
|
||||
export type CookiePolicySettings = {
|
||||
analytics_enabled: boolean;
|
||||
marketing_enabled: boolean;
|
||||
preferences_enabled: boolean;
|
||||
};
|
||||
|
||||
export type CookiePolicySettingsResponse = {
|
||||
status: string;
|
||||
data: CookiePolicySettings;
|
||||
updated_at?: string;
|
||||
updated_by?: string | null;
|
||||
};
|
||||
|
||||
export type CookieIntegrationSettings = {
|
||||
ga_measurement_id?: string | null;
|
||||
fb_pixel_id?: string | null;
|
||||
};
|
||||
|
||||
export type CookieIntegrationSettingsResponse = {
|
||||
status: string;
|
||||
data: CookieIntegrationSettings;
|
||||
updated_at?: string;
|
||||
updated_by?: string | null;
|
||||
};
|
||||
|
||||
const adminPrivacyService = {
|
||||
getCookiePolicy: async (): Promise<CookiePolicySettingsResponse> => {
|
||||
const res = await apiClient.get<CookiePolicySettingsResponse>(
|
||||
'/admin/privacy/cookie-policy'
|
||||
);
|
||||
return res.data;
|
||||
},
|
||||
updateCookiePolicy: async (
|
||||
payload: CookiePolicySettings
|
||||
): Promise<CookiePolicySettingsResponse> => {
|
||||
const res = await apiClient.put<CookiePolicySettingsResponse>(
|
||||
'/admin/privacy/cookie-policy',
|
||||
payload
|
||||
);
|
||||
return res.data;
|
||||
},
|
||||
getIntegrations: async (): Promise<CookieIntegrationSettingsResponse> => {
|
||||
const res = await apiClient.get<CookieIntegrationSettingsResponse>(
|
||||
'/admin/privacy/integrations'
|
||||
);
|
||||
return res.data;
|
||||
},
|
||||
updateIntegrations: async (
|
||||
payload: CookieIntegrationSettings
|
||||
): Promise<CookieIntegrationSettingsResponse> => {
|
||||
const res = await apiClient.put<CookieIntegrationSettingsResponse>(
|
||||
'/admin/privacy/integrations',
|
||||
payload
|
||||
);
|
||||
return res.data;
|
||||
},
|
||||
};
|
||||
|
||||
export default adminPrivacyService;
|
||||
|
||||
215
Frontend/src/features/content/services/bannerService.ts
Normal file
215
Frontend/src/features/content/services/bannerService.ts
Normal file
@@ -0,0 +1,215 @@
|
||||
import apiClient from '../../../shared/services/apiClient';
|
||||
|
||||
export interface Banner {
|
||||
id: number;
|
||||
title: string;
|
||||
description?: string;
|
||||
image_url: string;
|
||||
link_url?: string;
|
||||
position: string;
|
||||
display_order: number;
|
||||
is_active: boolean;
|
||||
start_date?: string;
|
||||
end_date?: string;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
export interface BannerListResponse {
|
||||
success: boolean;
|
||||
status?: string;
|
||||
data: {
|
||||
banners: Banner[];
|
||||
};
|
||||
message?: string;
|
||||
}
|
||||
|
||||
type CacheEntry = {
|
||||
timestamp: number;
|
||||
response: BannerListResponse;
|
||||
};
|
||||
|
||||
const BANNER_CACHE_TTL_MS = 5 * 60 * 1000;
|
||||
const memoryCache = new Map<string, CacheEntry>();
|
||||
|
||||
const getCacheKey = (position?: string) =>
|
||||
position ? `banners:position:${position}` : 'banners:active';
|
||||
|
||||
const isCacheValid = (entry: CacheEntry | undefined) => {
|
||||
if (!entry) return false;
|
||||
return Date.now() - entry.timestamp < BANNER_CACHE_TTL_MS;
|
||||
};
|
||||
|
||||
const loadFromStorage = (key: string): CacheEntry | undefined => {
|
||||
if (typeof window === 'undefined') return undefined;
|
||||
try {
|
||||
const raw = window.localStorage.getItem(key);
|
||||
if (!raw) return undefined;
|
||||
const parsed = JSON.parse(raw) as CacheEntry;
|
||||
return isCacheValid(parsed) ? parsed : undefined;
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
|
||||
const saveToStorage = (key: string, entry: CacheEntry) => {
|
||||
if (typeof window === 'undefined') return;
|
||||
try {
|
||||
window.localStorage.setItem(key, JSON.stringify(entry));
|
||||
} catch {
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
const getCachedOrFetch = async (
|
||||
key: string,
|
||||
fetcher: () => Promise<BannerListResponse>
|
||||
): Promise<BannerListResponse> => {
|
||||
|
||||
const inMemory = memoryCache.get(key);
|
||||
if (isCacheValid(inMemory)) {
|
||||
return inMemory!.response;
|
||||
}
|
||||
|
||||
|
||||
const fromStorage = loadFromStorage(key);
|
||||
if (fromStorage) {
|
||||
memoryCache.set(key, fromStorage);
|
||||
return fromStorage.response;
|
||||
}
|
||||
|
||||
|
||||
const response = await fetcher();
|
||||
const entry: CacheEntry = {
|
||||
timestamp: Date.now(),
|
||||
response,
|
||||
};
|
||||
memoryCache.set(key, entry);
|
||||
saveToStorage(key, entry);
|
||||
return response;
|
||||
};
|
||||
|
||||
export const getBannersByPosition = async (
|
||||
position: string = 'home'
|
||||
): Promise<BannerListResponse> => {
|
||||
const key = getCacheKey(position);
|
||||
return getCachedOrFetch(key, async () => {
|
||||
const response = await apiClient.get('/banners', {
|
||||
params: { position },
|
||||
});
|
||||
return response.data;
|
||||
});
|
||||
};
|
||||
|
||||
export const getActiveBanners = async ():
|
||||
Promise<BannerListResponse> => {
|
||||
const key = getCacheKey();
|
||||
return getCachedOrFetch(key, async () => {
|
||||
const response = await apiClient.get('/banners');
|
||||
return response.data;
|
||||
});
|
||||
};
|
||||
|
||||
export const getAllBanners = async (
|
||||
params?: { position?: string; page?: number; limit?: number }
|
||||
): Promise<BannerListResponse> => {
|
||||
const response = await apiClient.get('/banners', { params });
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const getBannerById = async (
|
||||
id: number
|
||||
): Promise<{ success: boolean; data: { banner: Banner } }> => {
|
||||
const response = await apiClient.get(`/banners/${id}`);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const createBanner = async (
|
||||
data: {
|
||||
title: string;
|
||||
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 requestData = {
|
||||
...data,
|
||||
link: data.link_url || data.link,
|
||||
};
|
||||
delete requestData.link_url;
|
||||
const response = await apiClient.post('/banners', requestData);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const updateBanner = async (
|
||||
id: number,
|
||||
data: {
|
||||
title?: string;
|
||||
description?: string;
|
||||
image_url?: string;
|
||||
link?: string;
|
||||
link_url?: string;
|
||||
position?: string;
|
||||
display_order?: number;
|
||||
is_active?: boolean;
|
||||
start_date?: string;
|
||||
end_date?: string;
|
||||
}
|
||||
): Promise<{ success: boolean; data: { banner: Banner }; message: string }> => {
|
||||
|
||||
const requestData = {
|
||||
...data,
|
||||
link: data.link_url || data.link,
|
||||
};
|
||||
delete requestData.link_url;
|
||||
const response = await apiClient.put(`/banners/${id}`, requestData);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const deleteBanner = async (
|
||||
id: number
|
||||
): Promise<{ success: boolean; message: string }> => {
|
||||
const response = await apiClient.delete(`/banners/${id}`);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const uploadBannerImage = async (
|
||||
file: File
|
||||
): Promise<{ success: boolean; data: { image_url: string; full_url: string }; message: string }> => {
|
||||
const formData = new FormData();
|
||||
formData.append('image', file);
|
||||
|
||||
|
||||
const response = await apiClient.post('/banners/upload', formData);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export interface BannerService {
|
||||
getBannersByPosition: typeof getBannersByPosition;
|
||||
getActiveBanners: typeof getActiveBanners;
|
||||
getAllBanners: typeof getAllBanners;
|
||||
getBannerById: typeof getBannerById;
|
||||
createBanner: typeof createBanner;
|
||||
updateBanner: typeof updateBanner;
|
||||
deleteBanner: typeof deleteBanner;
|
||||
uploadBannerImage: typeof uploadBannerImage;
|
||||
}
|
||||
|
||||
const bannerService: BannerService = {
|
||||
getBannersByPosition,
|
||||
getActiveBanners,
|
||||
getAllBanners,
|
||||
getBannerById,
|
||||
createBanner,
|
||||
updateBanner,
|
||||
deleteBanner,
|
||||
uploadBannerImage,
|
||||
};
|
||||
|
||||
export default bannerService as BannerService;
|
||||
150
Frontend/src/features/content/services/blogService.ts
Normal file
150
Frontend/src/features/content/services/blogService.ts
Normal file
@@ -0,0 +1,150 @@
|
||||
import apiClient from '../../../shared/services/apiClient';
|
||||
|
||||
export interface BlogSection {
|
||||
type: 'hero' | 'text' | 'image' | 'gallery' | 'quote' | 'features' | 'cta' | 'video';
|
||||
title?: string;
|
||||
content?: string;
|
||||
image?: string;
|
||||
images?: string[];
|
||||
quote?: string;
|
||||
author?: string;
|
||||
features?: Array<{ title: string; description: string; icon?: string }>;
|
||||
cta_text?: string;
|
||||
cta_link?: string;
|
||||
video_url?: string;
|
||||
alignment?: 'left' | 'center' | 'right';
|
||||
background_color?: string;
|
||||
text_color?: string;
|
||||
is_visible?: boolean;
|
||||
}
|
||||
|
||||
export interface BlogPost {
|
||||
id: number;
|
||||
title: string;
|
||||
slug: string;
|
||||
excerpt?: string;
|
||||
content?: string;
|
||||
featured_image?: string;
|
||||
author_id: number;
|
||||
author_name?: string;
|
||||
published_at?: string;
|
||||
is_published?: boolean;
|
||||
views_count: number;
|
||||
tags?: string[];
|
||||
meta_title?: string;
|
||||
meta_description?: string;
|
||||
meta_keywords?: string;
|
||||
sections?: BlogSection[];
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
export interface BlogPostCreate {
|
||||
title: string;
|
||||
slug?: string;
|
||||
excerpt?: string;
|
||||
content: string;
|
||||
featured_image?: string;
|
||||
tags?: string[];
|
||||
meta_title?: string;
|
||||
meta_description?: string;
|
||||
meta_keywords?: string;
|
||||
is_published?: boolean;
|
||||
published_at?: string;
|
||||
sections?: BlogSection[];
|
||||
}
|
||||
|
||||
export interface BlogPostUpdate {
|
||||
title?: string;
|
||||
slug?: string;
|
||||
excerpt?: string;
|
||||
content?: string;
|
||||
featured_image?: string;
|
||||
tags?: string[];
|
||||
meta_title?: string;
|
||||
meta_description?: string;
|
||||
meta_keywords?: string;
|
||||
is_published?: boolean;
|
||||
published_at?: string;
|
||||
sections?: BlogSection[];
|
||||
}
|
||||
|
||||
export interface BlogListResponse {
|
||||
posts: BlogPost[];
|
||||
pagination: {
|
||||
page: number;
|
||||
limit: number;
|
||||
total: number;
|
||||
pages: number;
|
||||
};
|
||||
all_tags?: string[];
|
||||
}
|
||||
|
||||
export interface BlogPostResponse {
|
||||
post: BlogPost;
|
||||
}
|
||||
|
||||
class BlogService {
|
||||
// Public endpoints
|
||||
async getBlogPosts(params?: {
|
||||
page?: number;
|
||||
limit?: number;
|
||||
search?: string;
|
||||
tag?: string;
|
||||
published_only?: boolean;
|
||||
}): Promise<{ status: string; data: BlogListResponse }> {
|
||||
const response = await apiClient.get('/blog/', { params });
|
||||
return response.data;
|
||||
}
|
||||
|
||||
async getBlogPostBySlug(slug: string): Promise<{ status: string; data: BlogPostResponse }> {
|
||||
const response = await apiClient.get(`/blog/${slug}`);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
// Admin endpoints
|
||||
async getAllBlogPosts(params?: {
|
||||
page?: number;
|
||||
limit?: number;
|
||||
search?: string;
|
||||
published?: boolean;
|
||||
}): Promise<{ status: string; data: BlogListResponse }> {
|
||||
const response = await apiClient.get('/blog/admin/posts', { params });
|
||||
return response.data;
|
||||
}
|
||||
|
||||
async getBlogPostById(id: number): Promise<{ status: string; data: BlogPostResponse }> {
|
||||
const response = await apiClient.get(`/blog/admin/posts/${id}`);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
async createBlogPost(data: BlogPostCreate): Promise<{ status: string; data: BlogPostResponse; message?: string }> {
|
||||
const response = await apiClient.post('/blog/admin/posts', data);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
async updateBlogPost(id: number, data: BlogPostUpdate): Promise<{ status: string; data: BlogPostResponse; message?: string }> {
|
||||
const response = await apiClient.put(`/blog/admin/posts/${id}`, data);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
async deleteBlogPost(id: number): Promise<{ status: string; message?: string }> {
|
||||
const response = await apiClient.delete(`/blog/admin/posts/${id}`);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
async uploadBlogImage(file: File): Promise<{ status: string; data: { image_url: string; full_url: string }; message?: string }> {
|
||||
const formData = new FormData();
|
||||
formData.append('image', file);
|
||||
const response = await apiClient.post('/blog/admin/upload-image', formData, {
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
},
|
||||
});
|
||||
return response.data;
|
||||
}
|
||||
}
|
||||
|
||||
export const blogService = new BlogService();
|
||||
export default blogService;
|
||||
|
||||
26
Frontend/src/features/content/services/contactService.ts
Normal file
26
Frontend/src/features/content/services/contactService.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import apiClient from '../../../shared/services/apiClient';
|
||||
|
||||
export interface ContactFormData {
|
||||
name: string;
|
||||
email: string;
|
||||
subject: string;
|
||||
message: string;
|
||||
phone?: string;
|
||||
}
|
||||
|
||||
export interface ContactResponse {
|
||||
status: string;
|
||||
message: string;
|
||||
}
|
||||
|
||||
export const submitContactForm = async (
|
||||
formData: ContactFormData
|
||||
): Promise<ContactResponse> => {
|
||||
const response = await apiClient.post('/contact/submit', formData);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export default {
|
||||
submitContactForm,
|
||||
};
|
||||
|
||||
0
Frontend/src/features/content/services/index.ts
Normal file
0
Frontend/src/features/content/services/index.ts
Normal file
377
Frontend/src/features/content/services/pageContentService.ts
Normal file
377
Frontend/src/features/content/services/pageContentService.ts
Normal file
@@ -0,0 +1,377 @@
|
||||
import apiClient from '../../../shared/services/apiClient';
|
||||
|
||||
export type PageType = 'home' | 'contact' | 'about' | 'footer' | 'seo' | 'privacy' | 'terms' | 'refunds' | 'cancellation' | 'accessibility' | 'faq';
|
||||
|
||||
export interface PageContent {
|
||||
id?: number;
|
||||
page_type: PageType;
|
||||
title?: string;
|
||||
subtitle?: string;
|
||||
description?: string;
|
||||
content?: string;
|
||||
meta_title?: string;
|
||||
meta_description?: string;
|
||||
meta_keywords?: string;
|
||||
og_title?: string;
|
||||
og_description?: string;
|
||||
og_image?: string;
|
||||
canonical_url?: string;
|
||||
contact_info?: {
|
||||
phone?: string;
|
||||
email?: string;
|
||||
address?: string;
|
||||
};
|
||||
map_url?: string;
|
||||
social_links?: {
|
||||
facebook?: string;
|
||||
twitter?: string;
|
||||
instagram?: string;
|
||||
linkedin?: string;
|
||||
youtube?: string;
|
||||
};
|
||||
footer_links?: {
|
||||
quick_links?: Array<{ label: string; url: string }>;
|
||||
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; 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 }>;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
export interface PageContentResponse {
|
||||
status: string;
|
||||
data: {
|
||||
page_content?: PageContent | null;
|
||||
page_contents?: PageContent[];
|
||||
};
|
||||
message?: string;
|
||||
}
|
||||
|
||||
export interface UpdatePageContentData {
|
||||
title?: string;
|
||||
subtitle?: string;
|
||||
description?: string;
|
||||
content?: string;
|
||||
meta_title?: string;
|
||||
meta_description?: string;
|
||||
meta_keywords?: string;
|
||||
og_title?: string;
|
||||
og_description?: string;
|
||||
og_image?: string;
|
||||
canonical_url?: string;
|
||||
contact_info?: {
|
||||
phone?: string;
|
||||
email?: string;
|
||||
address?: string;
|
||||
};
|
||||
map_url?: string;
|
||||
social_links?: {
|
||||
facebook?: string;
|
||||
twitter?: string;
|
||||
instagram?: string;
|
||||
linkedin?: string;
|
||||
youtube?: string;
|
||||
};
|
||||
footer_links?: {
|
||||
quick_links?: Array<{ label: string; url: string }>;
|
||||
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; 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 }>;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
const pageContentService = {
|
||||
|
||||
getAllPageContents: async (): Promise<PageContentResponse> => {
|
||||
const response = await apiClient.get<PageContentResponse>('/page-content');
|
||||
return response.data;
|
||||
},
|
||||
|
||||
|
||||
getPageContent: async (pageType: PageType): Promise<PageContentResponse> => {
|
||||
const response = await apiClient.get<PageContentResponse>(`/page-content/${pageType}`);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
|
||||
getHomeContent: async (): Promise<PageContentResponse> => {
|
||||
const response = await apiClient.get<PageContentResponse>('/home');
|
||||
return response.data;
|
||||
},
|
||||
|
||||
|
||||
getAboutContent: async (): Promise<PageContentResponse> => {
|
||||
const response = await apiClient.get<PageContentResponse>('/about');
|
||||
return response.data;
|
||||
},
|
||||
|
||||
|
||||
getContactContent: async (): Promise<PageContentResponse> => {
|
||||
const response = await apiClient.get<PageContentResponse>('/contact-content');
|
||||
return response.data;
|
||||
},
|
||||
|
||||
|
||||
getFooterContent: async (): Promise<PageContentResponse> => {
|
||||
const response = await apiClient.get<PageContentResponse>('/footer');
|
||||
return response.data;
|
||||
},
|
||||
|
||||
getPrivacyContent: async (): Promise<PageContentResponse> => {
|
||||
const response = await apiClient.get<PageContentResponse>('/privacy');
|
||||
return response.data;
|
||||
},
|
||||
|
||||
getTermsContent: async (): Promise<PageContentResponse> => {
|
||||
const response = await apiClient.get<PageContentResponse>('/terms');
|
||||
return response.data;
|
||||
},
|
||||
|
||||
getRefundsContent: async (): Promise<PageContentResponse> => {
|
||||
const response = await apiClient.get<PageContentResponse>('/refunds');
|
||||
return response.data;
|
||||
},
|
||||
|
||||
getCancellationContent: async (): Promise<PageContentResponse> => {
|
||||
const response = await apiClient.get<PageContentResponse>('/cancellation');
|
||||
return response.data;
|
||||
},
|
||||
|
||||
getAccessibilityContent: async (): Promise<PageContentResponse> => {
|
||||
const response = await apiClient.get<PageContentResponse>('/accessibility');
|
||||
return response.data;
|
||||
},
|
||||
|
||||
getFAQContent: async (): Promise<PageContentResponse> => {
|
||||
const response = await apiClient.get<PageContentResponse>('/faq');
|
||||
return response.data;
|
||||
},
|
||||
|
||||
|
||||
updatePageContent: async (
|
||||
pageType: PageType,
|
||||
data: UpdatePageContentData
|
||||
): Promise<PageContentResponse> => {
|
||||
|
||||
const updateData: any = { ...data };
|
||||
|
||||
|
||||
if (data.contact_info) {
|
||||
const contactInfo = {
|
||||
phone: data.contact_info.phone || '',
|
||||
email: data.contact_info.email || '',
|
||||
address: data.contact_info.address || '',
|
||||
};
|
||||
updateData.contact_info = contactInfo;
|
||||
}
|
||||
|
||||
|
||||
if (data.social_links) {
|
||||
const socialLinks = {
|
||||
facebook: data.social_links.facebook || '',
|
||||
twitter: data.social_links.twitter || '',
|
||||
instagram: data.social_links.instagram || '',
|
||||
linkedin: data.social_links.linkedin || '',
|
||||
youtube: data.social_links.youtube || '',
|
||||
};
|
||||
updateData.social_links = socialLinks;
|
||||
}
|
||||
|
||||
|
||||
if (data.footer_links) {
|
||||
updateData.footer_links = {
|
||||
quick_links: data.footer_links.quick_links || [],
|
||||
support_links: data.footer_links.support_links || [],
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
if (data.badges) {
|
||||
updateData.badges = data.badges;
|
||||
}
|
||||
|
||||
|
||||
if (data.values) {
|
||||
updateData.values = data.values;
|
||||
}
|
||||
if (data.features) {
|
||||
updateData.features = data.features;
|
||||
}
|
||||
|
||||
|
||||
if (data.luxury_features) {
|
||||
updateData.luxury_features = data.luxury_features;
|
||||
}
|
||||
if (data.luxury_gallery) {
|
||||
updateData.luxury_gallery = data.luxury_gallery;
|
||||
}
|
||||
if (data.luxury_testimonials) {
|
||||
updateData.luxury_testimonials = data.luxury_testimonials;
|
||||
}
|
||||
if (data.amenities) {
|
||||
updateData.amenities = data.amenities;
|
||||
}
|
||||
if (data.testimonials) {
|
||||
updateData.testimonials = data.testimonials;
|
||||
}
|
||||
if (data.gallery_images) {
|
||||
updateData.gallery_images = data.gallery_images;
|
||||
}
|
||||
if (data.stats) {
|
||||
updateData.stats = data.stats;
|
||||
}
|
||||
if (data.luxury_services) {
|
||||
updateData.luxury_services = data.luxury_services;
|
||||
}
|
||||
if (data.luxury_experiences) {
|
||||
updateData.luxury_experiences = data.luxury_experiences;
|
||||
}
|
||||
if (data.awards) {
|
||||
updateData.awards = data.awards;
|
||||
}
|
||||
if (data.partners) {
|
||||
updateData.partners = data.partners;
|
||||
}
|
||||
if (data.team) {
|
||||
updateData.team = data.team;
|
||||
}
|
||||
if (data.timeline) {
|
||||
updateData.timeline = data.timeline;
|
||||
}
|
||||
if (data.achievements) {
|
||||
updateData.achievements = data.achievements;
|
||||
}
|
||||
|
||||
const response = await apiClient.put<PageContentResponse>(
|
||||
`/page-content/${pageType}`,
|
||||
updateData
|
||||
);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
|
||||
uploadImage: async (
|
||||
file: File
|
||||
): Promise<{ success: boolean; data: { image_url: string; full_url: string }; message: string }> => {
|
||||
const formData = new FormData();
|
||||
formData.append('image', file);
|
||||
|
||||
|
||||
const response = await apiClient.post('/page-content/upload', formData);
|
||||
return response.data;
|
||||
},
|
||||
};
|
||||
|
||||
export default pageContentService;
|
||||
|
||||
75
Frontend/src/features/content/services/privacyService.ts
Normal file
75
Frontend/src/features/content/services/privacyService.ts
Normal file
@@ -0,0 +1,75 @@
|
||||
import apiClient from '../../../shared/services/apiClient';
|
||||
|
||||
export type CookieCategoryPreferences = {
|
||||
necessary: boolean;
|
||||
analytics: boolean;
|
||||
marketing: boolean;
|
||||
preferences: boolean;
|
||||
};
|
||||
|
||||
export type CookieConsent = {
|
||||
version: number;
|
||||
updated_at: string;
|
||||
has_decided: boolean;
|
||||
categories: CookieCategoryPreferences;
|
||||
};
|
||||
|
||||
export type CookieConsentResponse = {
|
||||
status: string;
|
||||
data: CookieConsent;
|
||||
};
|
||||
|
||||
export type UpdateCookieConsentRequest = {
|
||||
analytics?: boolean;
|
||||
marketing?: boolean;
|
||||
preferences?: boolean;
|
||||
};
|
||||
|
||||
export type PublicPrivacyConfig = {
|
||||
policy: {
|
||||
analytics_enabled: boolean;
|
||||
marketing_enabled: boolean;
|
||||
preferences_enabled: boolean;
|
||||
};
|
||||
integrations: {
|
||||
ga_measurement_id?: string | null;
|
||||
fb_pixel_id?: string | null;
|
||||
};
|
||||
};
|
||||
|
||||
export type PublicPrivacyConfigResponse = {
|
||||
status: string;
|
||||
data: PublicPrivacyConfig;
|
||||
};
|
||||
|
||||
const privacyService = {
|
||||
|
||||
getCookieConsent: async (): Promise<CookieConsent> => {
|
||||
const response = await apiClient.get<CookieConsentResponse>(
|
||||
'/privacy/cookie-consent'
|
||||
);
|
||||
return response.data.data;
|
||||
},
|
||||
|
||||
|
||||
getPublicConfig: async (): Promise<PublicPrivacyConfig> => {
|
||||
const response = await apiClient.get<PublicPrivacyConfigResponse>(
|
||||
'/privacy/config'
|
||||
);
|
||||
return response.data.data;
|
||||
},
|
||||
|
||||
|
||||
updateCookieConsent: async (
|
||||
payload: UpdateCookieConsentRequest
|
||||
): Promise<CookieConsent> => {
|
||||
const response = await apiClient.post<CookieConsentResponse>(
|
||||
'/privacy/cookie-consent',
|
||||
payload
|
||||
);
|
||||
return response.data.data;
|
||||
},
|
||||
};
|
||||
|
||||
export default privacyService;
|
||||
|
||||
Reference in New Issue
Block a user