@deepsel/cms-utils 1.1.3 → 1.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/blog/fetchBlogList.d.ts +15 -0
- package/dist/blog/fetchBlogList.js +51 -0
- package/dist/blog/fetchBlogPost.d.ts +14 -0
- package/dist/blog/fetchBlogPost.js +61 -0
- package/dist/blog/index.d.ts +3 -0
- package/dist/blog/index.js +3 -0
- package/dist/blog/types.d.ts +45 -0
- package/dist/blog/types.js +1 -0
- package/dist/constants/index.d.ts +1 -0
- package/dist/constants/index.js +1 -0
- package/dist/constants/websiteDataTypes.d.ts +7 -0
- package/dist/constants/websiteDataTypes.js +6 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/menus/isActiveMenu.d.ts +2 -2
- package/dist/menus/isActiveMenu.js +2 -2
- package/dist/page/fetchPageData.d.ts +9 -1
- package/dist/page/fetchPageData.js +22 -22
- package/dist/page/fetchSearchResults.d.ts +31 -0
- package/dist/page/fetchSearchResults.js +73 -0
- package/dist/page/getPathType.d.ts +9 -0
- package/dist/page/getPathType.js +46 -0
- package/dist/page/index.d.ts +3 -2
- package/dist/page/index.js +3 -2
- package/dist/page/isCrossingTemplateBoundary.d.ts +1 -0
- package/dist/page/isCrossingTemplateBoundary.js +6 -0
- package/dist/page/parseSlug.d.ts +12 -0
- package/dist/page/{parseSlugForLangAndPath.js → parseSlug.js} +8 -6
- package/dist/page/types.d.ts +2 -30
- package/dist/types.d.ts +8 -0
- package/package.json +6 -65
- package/dist/language/index.d.ts +0 -1
- package/dist/language/index.js +0 -1
- package/dist/page/constants.d.ts +0 -0
- package/dist/page/constants.js +0 -1
- package/dist/page/fetchFormData.d.ts +0 -4
- package/dist/page/fetchFormData.js +0 -38
- package/dist/page/parseSlugForLangAndPath.d.ts +0 -5
- /package/dist/{language → page}/isValidLanguageCode.d.ts +0 -0
- /package/dist/{language → page}/isValidLanguageCode.js +0 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { BlogListData } from './types';
|
|
2
|
+
import type { Pagination } from '../page/getPathType';
|
|
3
|
+
interface FetchBlogListProps {
|
|
4
|
+
lang?: string;
|
|
5
|
+
pagination?: Pagination;
|
|
6
|
+
astroRequest?: Request;
|
|
7
|
+
authToken?: string;
|
|
8
|
+
backendHost?: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Fetches blog list from the backend by language
|
|
12
|
+
* Corresponds to GET /blog_post/website/{lang}
|
|
13
|
+
*/
|
|
14
|
+
export declare function fetchBlogList({ astroRequest, pagination, authToken, lang, backendHost, }: FetchBlogListProps): Promise<BlogListData>;
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fetches blog list from the backend by language
|
|
3
|
+
* Corresponds to GET /blog_post/website/{lang}
|
|
4
|
+
*/
|
|
5
|
+
export async function fetchBlogList({ astroRequest, pagination, authToken, lang = 'default', backendHost = 'http://localhost:8000/api/v1', }) {
|
|
6
|
+
try {
|
|
7
|
+
let url = `${backendHost}/blog_post/list/${lang}`;
|
|
8
|
+
if (pagination) {
|
|
9
|
+
const searchParams = new URLSearchParams();
|
|
10
|
+
if (pagination.page)
|
|
11
|
+
searchParams.append('page', pagination.page.toString());
|
|
12
|
+
if (pagination.pageSize)
|
|
13
|
+
searchParams.append('page_size', pagination.pageSize.toString());
|
|
14
|
+
url += `?${searchParams.toString()}`;
|
|
15
|
+
}
|
|
16
|
+
const fetchOptions = {
|
|
17
|
+
method: 'GET',
|
|
18
|
+
headers: {
|
|
19
|
+
'Content-Type': 'application/json',
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
let hostname = null;
|
|
23
|
+
if (astroRequest) {
|
|
24
|
+
const url = new URL(astroRequest.url);
|
|
25
|
+
hostname = url.hostname;
|
|
26
|
+
}
|
|
27
|
+
else if (typeof window !== 'undefined') {
|
|
28
|
+
hostname = window.location.hostname;
|
|
29
|
+
}
|
|
30
|
+
if (hostname) {
|
|
31
|
+
fetchOptions.headers['X-Original-Host'] = hostname;
|
|
32
|
+
fetchOptions.headers['X-Frontend-Host'] = hostname;
|
|
33
|
+
}
|
|
34
|
+
if (authToken) {
|
|
35
|
+
fetchOptions.headers['Authorization'] = `Bearer ${authToken}`;
|
|
36
|
+
}
|
|
37
|
+
const response = await fetch(url, fetchOptions);
|
|
38
|
+
if (response.status === 401) {
|
|
39
|
+
throw new Error('Authentication required');
|
|
40
|
+
}
|
|
41
|
+
if (!response.ok) {
|
|
42
|
+
throw new Error(`Failed to fetch blog list: ${response.statusText}`);
|
|
43
|
+
}
|
|
44
|
+
const jsonData = await response.json();
|
|
45
|
+
return jsonData;
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
console.error('Error fetching blog list:', error);
|
|
49
|
+
throw error;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { BlogPostData } from './types';
|
|
2
|
+
interface FetchBlogPostProps {
|
|
3
|
+
path: string;
|
|
4
|
+
lang?: string;
|
|
5
|
+
astroRequest?: Request;
|
|
6
|
+
authToken?: string;
|
|
7
|
+
backendHost?: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Fetches a single blog post from the backend by language and path
|
|
11
|
+
* Corresponds to GET /blog_post/website/{lang}/{path}
|
|
12
|
+
*/
|
|
13
|
+
export declare function fetchBlogPost({ path, lang, astroRequest, authToken, backendHost, }: FetchBlogPostProps): Promise<BlogPostData>;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { fetchPublicSettings } from '../page';
|
|
2
|
+
/**
|
|
3
|
+
* Fetches a single blog post from the backend by language and path
|
|
4
|
+
* Corresponds to GET /blog_post/website/{lang}/{path}
|
|
5
|
+
*/
|
|
6
|
+
export async function fetchBlogPost({ path, lang = 'default', astroRequest, authToken, backendHost = 'http://localhost:8000/api/v1', }) {
|
|
7
|
+
try {
|
|
8
|
+
const cleanPath = path.startsWith('/') ? path.substring(1) : path;
|
|
9
|
+
let postSlug = cleanPath;
|
|
10
|
+
// rm the blog/ prefix
|
|
11
|
+
if (cleanPath.startsWith('blog/')) {
|
|
12
|
+
postSlug = cleanPath.substring('blog/'.length);
|
|
13
|
+
}
|
|
14
|
+
const url = `${backendHost}/blog_post/single/${lang}/${postSlug}`;
|
|
15
|
+
const fetchOptions = {
|
|
16
|
+
method: 'GET',
|
|
17
|
+
headers: {
|
|
18
|
+
'Content-Type': 'application/json',
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
let hostname = null;
|
|
22
|
+
if (astroRequest) {
|
|
23
|
+
const url = new URL(astroRequest.url);
|
|
24
|
+
hostname = url.hostname;
|
|
25
|
+
}
|
|
26
|
+
else if (typeof window !== 'undefined') {
|
|
27
|
+
hostname = window.location.hostname;
|
|
28
|
+
}
|
|
29
|
+
if (hostname) {
|
|
30
|
+
fetchOptions.headers['X-Original-Host'] = hostname;
|
|
31
|
+
fetchOptions.headers['X-Frontend-Host'] = hostname;
|
|
32
|
+
}
|
|
33
|
+
if (authToken) {
|
|
34
|
+
fetchOptions.headers['Authorization'] = `Bearer ${authToken}`;
|
|
35
|
+
}
|
|
36
|
+
const response = await fetch(url, fetchOptions);
|
|
37
|
+
if (response.status === 401) {
|
|
38
|
+
throw new Error('Authentication required');
|
|
39
|
+
}
|
|
40
|
+
if (response.status === 404) {
|
|
41
|
+
try {
|
|
42
|
+
const { detail } = (await response.json());
|
|
43
|
+
console.warn('404', url, { detail });
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
console.warn('404', url);
|
|
47
|
+
}
|
|
48
|
+
const siteSettings = await fetchPublicSettings(null, astroRequest, lang, backendHost);
|
|
49
|
+
return {
|
|
50
|
+
notFound: true,
|
|
51
|
+
public_settings: siteSettings,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
const jsonData = await response.json();
|
|
55
|
+
return jsonData;
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
console.error('Error fetching blog post:', error);
|
|
59
|
+
throw error;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { SiteSettings } from '../types';
|
|
2
|
+
import type { SeoMetadata, LanguageAlternative } from '../page/types';
|
|
3
|
+
export interface BlogPostAuthor {
|
|
4
|
+
id: number;
|
|
5
|
+
display_name?: string;
|
|
6
|
+
username: string;
|
|
7
|
+
image?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface BlogPostListItem {
|
|
10
|
+
id: number;
|
|
11
|
+
title: string;
|
|
12
|
+
slug: string;
|
|
13
|
+
excerpt?: string;
|
|
14
|
+
featured_image_id?: number;
|
|
15
|
+
featured_image_name?: string;
|
|
16
|
+
publish_date?: string;
|
|
17
|
+
author?: BlogPostAuthor;
|
|
18
|
+
lang: string;
|
|
19
|
+
}
|
|
20
|
+
export interface BlogListData {
|
|
21
|
+
lang: string;
|
|
22
|
+
public_settings: SiteSettings;
|
|
23
|
+
blog_posts: BlogPostListItem[];
|
|
24
|
+
page: number;
|
|
25
|
+
page_size: number;
|
|
26
|
+
total_count: number;
|
|
27
|
+
total_pages: number;
|
|
28
|
+
}
|
|
29
|
+
export interface BlogPostData {
|
|
30
|
+
id?: number;
|
|
31
|
+
title?: string;
|
|
32
|
+
content?: string;
|
|
33
|
+
lang?: string;
|
|
34
|
+
public_settings: SiteSettings;
|
|
35
|
+
seo_metadata?: SeoMetadata;
|
|
36
|
+
custom_code?: string | null;
|
|
37
|
+
page_custom_code?: string | null;
|
|
38
|
+
require_login?: boolean | null;
|
|
39
|
+
featured_image_id?: number | null;
|
|
40
|
+
featured_image_name?: string | null;
|
|
41
|
+
publish_date?: string | null;
|
|
42
|
+
author?: BlogPostAuthor | null;
|
|
43
|
+
language_alternatives?: LanguageAlternative[];
|
|
44
|
+
notFound?: boolean;
|
|
45
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './websiteDataTypes';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './websiteDataTypes';
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare const WebsiteDataTypes: {
|
|
2
|
+
readonly Page: "Page";
|
|
3
|
+
readonly BlogList: "BlogList";
|
|
4
|
+
readonly BlogPost: "BlogPost";
|
|
5
|
+
readonly SearchResults: "SearchResults";
|
|
6
|
+
};
|
|
7
|
+
export type WebsiteDataType = (typeof WebsiteDataTypes)[keyof typeof WebsiteDataTypes];
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { MenuItem } from './types';
|
|
2
|
-
import type {
|
|
3
|
-
export declare const isActiveMenu: (menuItem: MenuItem,
|
|
2
|
+
import type { WebsiteData } from '../types';
|
|
3
|
+
export declare const isActiveMenu: (menuItem: MenuItem, websiteData: WebsiteData) => boolean;
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
// Check if a menu item should be marked as active
|
|
2
|
-
export const isActiveMenu = (menuItem,
|
|
2
|
+
export const isActiveMenu = (menuItem, websiteData) => {
|
|
3
3
|
// return if not browser
|
|
4
4
|
if (typeof window === 'undefined') {
|
|
5
5
|
return false;
|
|
6
6
|
}
|
|
7
7
|
const location = window.location;
|
|
8
|
-
const currentLang =
|
|
8
|
+
const currentLang = websiteData.data.lang;
|
|
9
9
|
let result;
|
|
10
10
|
if (menuItem.url === '/') {
|
|
11
11
|
result =
|
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import type { PageData } from './types';
|
|
2
|
+
interface FetchPageDataProps {
|
|
3
|
+
path: string;
|
|
4
|
+
lang?: string;
|
|
5
|
+
astroRequest?: Request;
|
|
6
|
+
authToken?: string;
|
|
7
|
+
backendHost?: string;
|
|
8
|
+
}
|
|
2
9
|
/**
|
|
3
10
|
* Fetches page data from the backend by language and slug
|
|
4
11
|
*/
|
|
5
|
-
export declare function fetchPageData(
|
|
12
|
+
export declare function fetchPageData({ path, lang, astroRequest, authToken, backendHost, }: FetchPageDataProps): Promise<PageData>;
|
|
13
|
+
export {};
|
|
@@ -2,25 +2,23 @@ import { fetchPublicSettings } from './fetchPublicSettings';
|
|
|
2
2
|
/**
|
|
3
3
|
* Fetches page data from the backend by language and slug
|
|
4
4
|
*/
|
|
5
|
-
export async function fetchPageData(
|
|
5
|
+
export async function fetchPageData({ path, lang, astroRequest, authToken, backendHost = 'http://localhost:8000/api/v1', }) {
|
|
6
6
|
try {
|
|
7
|
-
// Format the
|
|
8
|
-
let
|
|
7
|
+
// Format the path properly, make sure it starts with a slash
|
|
8
|
+
let formattedPath = path.startsWith('/') ? path : `/${path}`;
|
|
9
9
|
// Backend will consider 'default' as the home slug
|
|
10
|
-
if (
|
|
11
|
-
|
|
10
|
+
if (formattedPath === '/') {
|
|
11
|
+
formattedPath = '/default';
|
|
12
12
|
}
|
|
13
13
|
// Determine the URL based on whether a language is provided
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
url = `${backendHost}/page/website/${lang}${formattedSlug}`;
|
|
17
|
-
}
|
|
18
|
-
else {
|
|
19
|
-
url = `${backendHost}/page/website/default${formattedSlug}`;
|
|
20
|
-
}
|
|
14
|
+
const langPrefix = lang || 'default';
|
|
15
|
+
let url = `${backendHost}/page/website/${langPrefix}${formattedPath}`;
|
|
21
16
|
// Add preview parameter if enabled
|
|
22
|
-
if (
|
|
23
|
-
|
|
17
|
+
if (astroRequest) {
|
|
18
|
+
const previewParam = new URL(astroRequest.url).searchParams.get('preview');
|
|
19
|
+
if (previewParam === 'true') {
|
|
20
|
+
url += `?preview=true`;
|
|
21
|
+
}
|
|
24
22
|
}
|
|
25
23
|
// Prepare fetch options
|
|
26
24
|
const fetchOptions = {
|
|
@@ -33,8 +31,8 @@ export async function fetchPageData(lang, slug, isPreview = false, authToken = n
|
|
|
33
31
|
let hostname = null;
|
|
34
32
|
// Server-side: Extract hostname from Astro request
|
|
35
33
|
if (astroRequest) {
|
|
36
|
-
const
|
|
37
|
-
hostname =
|
|
34
|
+
const requestUrl = new URL(astroRequest.url);
|
|
35
|
+
hostname = requestUrl.hostname;
|
|
38
36
|
}
|
|
39
37
|
// Client-side: Extract hostname from window
|
|
40
38
|
else if (typeof window !== 'undefined') {
|
|
@@ -57,22 +55,24 @@ export async function fetchPageData(lang, slug, isPreview = false, authToken = n
|
|
|
57
55
|
}
|
|
58
56
|
// Only treat actual 404 as not found
|
|
59
57
|
if (response.status === 404) {
|
|
60
|
-
|
|
61
|
-
|
|
58
|
+
try {
|
|
59
|
+
const { detail } = await response.json();
|
|
60
|
+
console.warn('404', url, { detail });
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
console.warn('404', url);
|
|
64
|
+
}
|
|
62
65
|
// When page is not found, still fetch menus and site settings
|
|
63
66
|
try {
|
|
64
67
|
const siteSettings = await fetchPublicSettings(null, astroRequest, lang, backendHost);
|
|
65
68
|
return {
|
|
66
69
|
notFound: true,
|
|
67
|
-
status: 404,
|
|
68
|
-
detail,
|
|
69
70
|
public_settings: siteSettings,
|
|
70
|
-
lang: lang || siteSettings.default_language?.iso_code || 'en',
|
|
71
71
|
};
|
|
72
72
|
}
|
|
73
73
|
catch (settingsError) {
|
|
74
74
|
console.warn('Could not fetch site settings for 404 page:', settingsError);
|
|
75
|
-
throw new Error(`Page not found
|
|
75
|
+
throw new Error(`Page not found`);
|
|
76
76
|
}
|
|
77
77
|
}
|
|
78
78
|
try {
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { SiteSettings } from '../types';
|
|
2
|
+
export interface SearchResultItem {
|
|
3
|
+
id: string;
|
|
4
|
+
title: string;
|
|
5
|
+
url: string;
|
|
6
|
+
publishDate: string | null;
|
|
7
|
+
contentType: string;
|
|
8
|
+
relevanceScore: number;
|
|
9
|
+
}
|
|
10
|
+
export interface SearchResultsData {
|
|
11
|
+
lang: string;
|
|
12
|
+
query: string;
|
|
13
|
+
public_settings: SiteSettings;
|
|
14
|
+
results: SearchResultItem[];
|
|
15
|
+
total: number;
|
|
16
|
+
suggestions: string[];
|
|
17
|
+
}
|
|
18
|
+
interface FetchSearchResultsProps {
|
|
19
|
+
lang?: string;
|
|
20
|
+
q: string;
|
|
21
|
+
limit?: number;
|
|
22
|
+
astroRequest?: Request;
|
|
23
|
+
authToken?: string;
|
|
24
|
+
backendHost?: string;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Fetches search results from the backend.
|
|
28
|
+
* Calls GET /api/v1/page/website_search/{lang}?q=...&limit=...
|
|
29
|
+
*/
|
|
30
|
+
export declare function fetchSearchResults({ lang, q, limit, astroRequest, authToken, backendHost, }: FetchSearchResultsProps): Promise<SearchResultsData>;
|
|
31
|
+
export {};
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { fetchPublicSettings } from './fetchPublicSettings';
|
|
2
|
+
/**
|
|
3
|
+
* Fetches search results from the backend.
|
|
4
|
+
* Calls GET /api/v1/page/website_search/{lang}?q=...&limit=...
|
|
5
|
+
*/
|
|
6
|
+
export async function fetchSearchResults({ lang = 'default', q, limit = 100, astroRequest, authToken, backendHost = 'http://localhost:8000/api/v1', }) {
|
|
7
|
+
// Build hostname for headers
|
|
8
|
+
let hostname = null;
|
|
9
|
+
if (astroRequest) {
|
|
10
|
+
const requestUrl = new URL(astroRequest.url);
|
|
11
|
+
hostname = requestUrl.hostname;
|
|
12
|
+
}
|
|
13
|
+
else if (typeof window !== 'undefined') {
|
|
14
|
+
hostname = window.location.hostname;
|
|
15
|
+
}
|
|
16
|
+
const headers = {
|
|
17
|
+
'Content-Type': 'application/json',
|
|
18
|
+
};
|
|
19
|
+
if (hostname) {
|
|
20
|
+
headers['X-Original-Host'] = hostname;
|
|
21
|
+
headers['X-Frontend-Host'] = hostname;
|
|
22
|
+
}
|
|
23
|
+
if (authToken) {
|
|
24
|
+
headers['Authorization'] = `Bearer ${authToken}`;
|
|
25
|
+
}
|
|
26
|
+
// Always fetch public_settings alongside the search call
|
|
27
|
+
const settingsPromise = fetchPublicSettings(null, astroRequest ?? null, lang, `http://localhost:8000`);
|
|
28
|
+
// If no query, skip the search call and return empty results
|
|
29
|
+
if (!q.trim()) {
|
|
30
|
+
const public_settings = await settingsPromise;
|
|
31
|
+
// Normalize lang: replace 'default' with the actual ISO code from settings
|
|
32
|
+
const resolvedLang = lang === 'default' ? public_settings.default_language?.iso_code || lang : lang;
|
|
33
|
+
return {
|
|
34
|
+
lang: resolvedLang,
|
|
35
|
+
query: q,
|
|
36
|
+
public_settings,
|
|
37
|
+
results: [],
|
|
38
|
+
total: 0,
|
|
39
|
+
suggestions: [],
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
const searchParams = new URLSearchParams({ q, limit: String(limit) });
|
|
43
|
+
const searchUrl = `${backendHost}/page/website_search/${lang}?${searchParams.toString()}`;
|
|
44
|
+
const [public_settings, searchResponse] = await Promise.allSettled([
|
|
45
|
+
settingsPromise,
|
|
46
|
+
fetch(searchUrl, { method: 'GET', headers }),
|
|
47
|
+
]);
|
|
48
|
+
const resolvedSettings = public_settings.status === 'fulfilled' ? public_settings.value : {};
|
|
49
|
+
// Normalize lang: replace 'default' with the actual ISO code from settings
|
|
50
|
+
const resolvedLang = lang === 'default' ? resolvedSettings.default_language?.iso_code || lang : lang;
|
|
51
|
+
if (searchResponse.status === 'rejected' || !searchResponse.value.ok) {
|
|
52
|
+
console.error('Error fetching search results:', searchResponse.status === 'rejected'
|
|
53
|
+
? searchResponse.reason
|
|
54
|
+
: searchResponse.value.statusText);
|
|
55
|
+
return {
|
|
56
|
+
lang: resolvedLang,
|
|
57
|
+
query: q,
|
|
58
|
+
public_settings: resolvedSettings,
|
|
59
|
+
results: [],
|
|
60
|
+
total: 0,
|
|
61
|
+
suggestions: [],
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
const apiData = await searchResponse.value.json();
|
|
65
|
+
return {
|
|
66
|
+
lang: resolvedLang,
|
|
67
|
+
query: q,
|
|
68
|
+
public_settings: resolvedSettings,
|
|
69
|
+
results: apiData.results ?? [],
|
|
70
|
+
total: apiData.total ?? 0,
|
|
71
|
+
suggestions: apiData.suggestions ?? [],
|
|
72
|
+
};
|
|
73
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { WebsiteDataTypes } from '../constants';
|
|
2
|
+
export function getPathType(path) {
|
|
3
|
+
let pathType = WebsiteDataTypes.Page;
|
|
4
|
+
let pagination = undefined;
|
|
5
|
+
// delete forward at the beginning
|
|
6
|
+
if (path.startsWith('/')) {
|
|
7
|
+
path = path.slice(1);
|
|
8
|
+
}
|
|
9
|
+
if (path === 'search' || path.startsWith('search?') || path.startsWith('search/')) {
|
|
10
|
+
return { pathType: WebsiteDataTypes.SearchResults };
|
|
11
|
+
}
|
|
12
|
+
if (path.startsWith('blog')) {
|
|
13
|
+
// split
|
|
14
|
+
const parts = path.split('/');
|
|
15
|
+
let pageSize = undefined;
|
|
16
|
+
// extract query parameters if any
|
|
17
|
+
const queryString = path.split('?')[1];
|
|
18
|
+
if (queryString) {
|
|
19
|
+
const params = new URLSearchParams(queryString);
|
|
20
|
+
const size = params.get('pageSize');
|
|
21
|
+
if (size && !isNaN(Number(size))) {
|
|
22
|
+
pageSize = Number(size);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
// check which blog list format, either /blog, /blog/page/2, or /blog/{slug}
|
|
26
|
+
if (parts.length > 1 && parts[1] !== '') {
|
|
27
|
+
// /blog/page/2
|
|
28
|
+
if (parts[1] === 'page' && parts[2] && !isNaN(Number(parts[2]))) {
|
|
29
|
+
pathType = WebsiteDataTypes.BlogList;
|
|
30
|
+
pagination = { page: Number(parts[2]), pageSize };
|
|
31
|
+
}
|
|
32
|
+
// /blog/{slug}
|
|
33
|
+
else {
|
|
34
|
+
pathType = WebsiteDataTypes.BlogPost;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
// /blog
|
|
39
|
+
pathType = WebsiteDataTypes.BlogList;
|
|
40
|
+
if (pageSize) {
|
|
41
|
+
pagination = { pageSize };
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return { pathType, pagination };
|
|
46
|
+
}
|
package/dist/page/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
export * from './fetchFormData';
|
|
2
1
|
export * from './fetchPageData';
|
|
3
2
|
export * from './fetchPublicSettings';
|
|
3
|
+
export * from './fetchSearchResults';
|
|
4
4
|
export * from './getAuthToken';
|
|
5
|
-
export * from './
|
|
5
|
+
export * from './parseSlug';
|
|
6
6
|
export * from './types';
|
|
7
|
+
export * from './isCrossingTemplateBoundary';
|
package/dist/page/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
export * from './fetchFormData';
|
|
2
1
|
export * from './fetchPageData';
|
|
3
2
|
export * from './fetchPublicSettings';
|
|
3
|
+
export * from './fetchSearchResults';
|
|
4
4
|
export * from './getAuthToken';
|
|
5
|
-
export * from './
|
|
5
|
+
export * from './parseSlug';
|
|
6
6
|
export * from './types';
|
|
7
|
+
export * from './isCrossingTemplateBoundary';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const isCrossingTemplateBoundary: (fromPath: string, toPath: string) => boolean;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Pagination } from './getPathType';
|
|
2
|
+
import type { WebsiteDataType } from '../constants';
|
|
3
|
+
export interface SlugParseResult {
|
|
4
|
+
lang?: string;
|
|
5
|
+
path: string;
|
|
6
|
+
pathType: WebsiteDataType;
|
|
7
|
+
pagination?: Pagination;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Parses a slug to determine language and path
|
|
11
|
+
*/
|
|
12
|
+
export declare function parseSlug(slug: string | null): SlugParseResult;
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { isValidLanguageCode } from '
|
|
1
|
+
import { isValidLanguageCode } from './isValidLanguageCode';
|
|
2
|
+
import { getPathType } from './getPathType';
|
|
2
3
|
/**
|
|
3
4
|
* Parses a slug to determine language and path
|
|
4
5
|
*/
|
|
5
|
-
export function
|
|
6
|
+
export function parseSlug(slug) {
|
|
6
7
|
const slugParts = slug ? slug.split('/').filter(Boolean) : [];
|
|
7
|
-
let lang
|
|
8
|
+
let lang;
|
|
8
9
|
let path = '/';
|
|
9
10
|
// Check if the first part is a valid language code
|
|
10
11
|
if (slugParts.length > 0 && isValidLanguageCode(slugParts[0])) {
|
|
@@ -15,8 +16,9 @@ export function parseSlugForLangAndPath(slug) {
|
|
|
15
16
|
}
|
|
16
17
|
}
|
|
17
18
|
else {
|
|
18
|
-
// No language in URL, use the path as is
|
|
19
|
-
path = slugParts.length > 0 ?
|
|
19
|
+
// No language in URL, use the path as is
|
|
20
|
+
path = slugParts.length > 0 ? slugParts.join('/') : '/';
|
|
20
21
|
}
|
|
21
|
-
|
|
22
|
+
const { pathType, pagination } = getPathType(path);
|
|
23
|
+
return { lang, path, pathType, pagination };
|
|
22
24
|
}
|
package/dist/page/types.d.ts
CHANGED
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
import type { SiteSettings } from '../types';
|
|
2
2
|
import type { MenuItem } from '../menus/types';
|
|
3
|
-
export interface SlugParseResult {
|
|
4
|
-
lang: string | null;
|
|
5
|
-
path: string;
|
|
6
|
-
}
|
|
7
3
|
export interface Language {
|
|
8
4
|
id: number;
|
|
9
5
|
name: string;
|
|
@@ -35,41 +31,17 @@ export interface LanguageAlternative {
|
|
|
35
31
|
slug: string;
|
|
36
32
|
locale: Language;
|
|
37
33
|
}
|
|
38
|
-
export interface BlogPostAuthor {
|
|
39
|
-
id: number;
|
|
40
|
-
display_name?: string;
|
|
41
|
-
username: string;
|
|
42
|
-
image?: string;
|
|
43
|
-
}
|
|
44
|
-
export interface BlogPostListItem {
|
|
45
|
-
id: number;
|
|
46
|
-
title: string;
|
|
47
|
-
slug: string;
|
|
48
|
-
excerpt?: string;
|
|
49
|
-
featured_image_id?: number;
|
|
50
|
-
publish_date?: string;
|
|
51
|
-
author?: BlogPostAuthor;
|
|
52
|
-
lang: string;
|
|
53
|
-
}
|
|
54
34
|
export interface PageData {
|
|
55
35
|
id?: number;
|
|
56
36
|
title?: string;
|
|
57
37
|
content?: Content;
|
|
58
|
-
|
|
38
|
+
slug?: string;
|
|
39
|
+
lang?: string;
|
|
59
40
|
public_settings: SiteSettings;
|
|
60
41
|
seo_metadata?: SeoMetadata;
|
|
61
42
|
language_alternatives?: LanguageAlternative[];
|
|
62
|
-
is_frontend_page?: boolean | null;
|
|
63
|
-
string_id?: string | null;
|
|
64
|
-
contents?: unknown;
|
|
65
43
|
page_custom_code?: string | null;
|
|
66
44
|
custom_code?: string | null;
|
|
67
45
|
require_login?: boolean;
|
|
68
|
-
blog_posts?: BlogPostListItem[];
|
|
69
|
-
featured_image_id?: number;
|
|
70
|
-
publish_date?: string;
|
|
71
|
-
author?: BlogPostAuthor;
|
|
72
46
|
notFound?: boolean;
|
|
73
|
-
status?: number;
|
|
74
|
-
detail?: string;
|
|
75
47
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import type { MenuItem } from './menus/types';
|
|
2
2
|
import type { SpecialTemplate } from './page/types';
|
|
3
|
+
import type { WebsiteDataType } from './constants';
|
|
4
|
+
import type { PageData, SearchResultsData } from './page';
|
|
5
|
+
import type { BlogListData, BlogPostData } from './blog';
|
|
6
|
+
export type WebsiteData = {
|
|
7
|
+
type: WebsiteDataType;
|
|
8
|
+
data: PageData | BlogListData | BlogPostData | SearchResultsData;
|
|
9
|
+
settings?: SiteSettings;
|
|
10
|
+
};
|
|
3
11
|
export interface SiteSettings {
|
|
4
12
|
id: number;
|
|
5
13
|
name: string;
|
package/package.json
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deepsel/cms-utils",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.5",
|
|
4
4
|
"description": "Helper utilities for Deepsel CMS",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "https://github.com/DeepselSystems/deepsel-cms",
|
|
8
|
+
"directory": "packages/cms-utils"
|
|
9
|
+
},
|
|
5
10
|
"publishConfig": {
|
|
6
11
|
"access": "public"
|
|
7
12
|
},
|
|
@@ -20,70 +25,6 @@
|
|
|
20
25
|
".": {
|
|
21
26
|
"import": "./dist/index.js",
|
|
22
27
|
"types": "./dist/index.d.ts"
|
|
23
|
-
},
|
|
24
|
-
"./types": {
|
|
25
|
-
"import": "./dist/types.js",
|
|
26
|
-
"types": "./dist/types.d.ts"
|
|
27
|
-
},
|
|
28
|
-
"./language": {
|
|
29
|
-
"import": "./dist/language/index.js",
|
|
30
|
-
"types": "./dist/language/index.d.ts"
|
|
31
|
-
},
|
|
32
|
-
"./language/isValidLanguageCode": {
|
|
33
|
-
"import": "./dist/language/isValidLanguageCode.js",
|
|
34
|
-
"types": "./dist/language/isValidLanguageCode.d.ts"
|
|
35
|
-
},
|
|
36
|
-
"./menus": {
|
|
37
|
-
"import": "./dist/menus/index.js",
|
|
38
|
-
"types": "./dist/menus/index.d.ts"
|
|
39
|
-
},
|
|
40
|
-
"./menus/isActiveMenu": {
|
|
41
|
-
"import": "./dist/menus/isActiveMenu.js",
|
|
42
|
-
"types": "./dist/menus/isActiveMenu.d.ts"
|
|
43
|
-
},
|
|
44
|
-
"./menus/types": {
|
|
45
|
-
"import": "./dist/menus/types.js",
|
|
46
|
-
"types": "./dist/menus/types.d.ts"
|
|
47
|
-
},
|
|
48
|
-
"./page": {
|
|
49
|
-
"import": "./dist/page/index.js",
|
|
50
|
-
"types": "./dist/page/index.d.ts"
|
|
51
|
-
},
|
|
52
|
-
"./page/constants": {
|
|
53
|
-
"import": "./dist/page/constants.js",
|
|
54
|
-
"types": "./dist/page/constants.d.ts"
|
|
55
|
-
},
|
|
56
|
-
"./page/types": {
|
|
57
|
-
"import": "./dist/page/types.js",
|
|
58
|
-
"types": "./dist/page/types.d.ts"
|
|
59
|
-
},
|
|
60
|
-
"./page/fetchBlogListData": {
|
|
61
|
-
"import": "./dist/page/fetchBlogListData.js",
|
|
62
|
-
"types": "./dist/page/fetchBlogListData.d.ts"
|
|
63
|
-
},
|
|
64
|
-
"./page/fetchBlogPostData": {
|
|
65
|
-
"import": "./dist/page/fetchBlogPostData.js",
|
|
66
|
-
"types": "./dist/page/fetchBlogPostData.d.ts"
|
|
67
|
-
},
|
|
68
|
-
"./page/fetchFormData": {
|
|
69
|
-
"import": "./dist/page/fetchFormData.js",
|
|
70
|
-
"types": "./dist/page/fetchFormData.d.ts"
|
|
71
|
-
},
|
|
72
|
-
"./page/fetchPageData": {
|
|
73
|
-
"import": "./dist/page/fetchPageData.js",
|
|
74
|
-
"types": "./dist/page/fetchPageData.d.ts"
|
|
75
|
-
},
|
|
76
|
-
"./page/fetchPublicSettings": {
|
|
77
|
-
"import": "./dist/page/fetchPublicSettings.js",
|
|
78
|
-
"types": "./dist/page/fetchPublicSettings.d.ts"
|
|
79
|
-
},
|
|
80
|
-
"./page/getAuthToken": {
|
|
81
|
-
"import": "./dist/page/getAuthToken.js",
|
|
82
|
-
"types": "./dist/page/getAuthToken.d.ts"
|
|
83
|
-
},
|
|
84
|
-
"./page/parseSlugForLangAndPath": {
|
|
85
|
-
"import": "./dist/page/parseSlugForLangAndPath.js",
|
|
86
|
-
"types": "./dist/page/parseSlugForLangAndPath.d.ts"
|
|
87
28
|
}
|
|
88
29
|
},
|
|
89
30
|
"files": [
|
package/dist/language/index.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './isValidLanguageCode';
|
package/dist/language/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './isValidLanguageCode';
|
package/dist/page/constants.d.ts
DELETED
|
File without changes
|
package/dist/page/constants.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Fetches Form data from the backend by language and slug
|
|
3
|
-
*/
|
|
4
|
-
export async function fetchFormData(lang, slug, backendHost = 'http://localhost:8000') {
|
|
5
|
-
try {
|
|
6
|
-
// Format the slug properly
|
|
7
|
-
const formattedSlug = slug.replace(/^\/forms\//, '');
|
|
8
|
-
// Determine the URL based on whether a language is provided
|
|
9
|
-
const url = `${backendHost}/form/website/${lang}/${formattedSlug}`;
|
|
10
|
-
// Prepare fetch options
|
|
11
|
-
const fetchOptions = {
|
|
12
|
-
method: 'GET',
|
|
13
|
-
headers: {
|
|
14
|
-
'Content-Type': 'application/json',
|
|
15
|
-
},
|
|
16
|
-
};
|
|
17
|
-
// Fetch the page data from the backend
|
|
18
|
-
const response = await fetch(url, fetchOptions);
|
|
19
|
-
// Only treat actual 404 as not found
|
|
20
|
-
if (response.status === 404) {
|
|
21
|
-
const { detail } = await response.json();
|
|
22
|
-
console.warn('404', url, { detail });
|
|
23
|
-
return { notFound: true, status: 404, detail };
|
|
24
|
-
}
|
|
25
|
-
try {
|
|
26
|
-
// Parse the JSON
|
|
27
|
-
return await response.json();
|
|
28
|
-
}
|
|
29
|
-
catch (parseError) {
|
|
30
|
-
console.error(`Failed to parse response: ${parseError.message}`);
|
|
31
|
-
return { error: true, parseError: parseError.message };
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
catch (error) {
|
|
35
|
-
console.error('Error fetching page data:', error);
|
|
36
|
-
return { error: true, message: error.message };
|
|
37
|
-
}
|
|
38
|
-
}
|
|
File without changes
|
|
File without changes
|