import { getDirectusClient, readItems, readItem, readSingleton, aggregate } from './client'; import type { Page, Post, Site, Globals, Navigation } from '@/types/schema'; const directus = getDirectusClient(); /** * Fetch a page by permalink (tenant-safe) */ export async function fetchPageByPermalink( permalink: string, siteId: string, options?: { preview?: boolean; token?: string } ): Promise { const filter: Record = { permalink: { _eq: permalink }, site: { _eq: siteId } }; if (!options?.preview) { filter.status = { _eq: 'published' }; } try { const pages = await directus.request( readItems('pages', { filter, limit: 1, fields: [ 'id', 'title', 'permalink', 'status', 'seo_title', 'seo_description', 'seo_image', { blocks: { id: true, sort: true, hide_block: true, collection: true, item: true } } ], deep: { blocks: { _sort: ['sort'], _filter: { hide_block: { _neq: true } } } } }) ); return pages?.[0] || null; } catch (err) { console.error('Error fetching page:', err); return null; } } /** * Fetch site globals */ export async function fetchSiteGlobals(siteId: string): Promise { try { const globals = await directus.request( readItems('globals', { filter: { site: { _eq: siteId } }, limit: 1, fields: ['*'] }) ); return globals?.[0] || null; } catch (err) { console.error('Error fetching globals:', err); return null; } } /** * Fetch site navigation */ export async function fetchNavigation(siteId: string): Promise { try { const nav = await directus.request( readItems('navigation', { filter: { site: { _eq: siteId } }, sort: ['sort'], fields: ['id', 'label', 'url', 'parent', 'target', 'sort'] }) ); return nav || []; } catch (err) { console.error('Error fetching navigation:', err); return []; } } /** * Fetch posts for a site */ export async function fetchPosts( siteId: string, options?: { limit?: number; page?: number; category?: string } ): Promise<{ posts: Post[]; total: number }> { const limit = options?.limit || 10; const page = options?.page || 1; const offset = (page - 1) * limit; const filter: Record = { site: { _eq: siteId }, status: { _eq: 'published' } }; if (options?.category) { filter.category = { _eq: options.category }; } try { const [posts, countResult] = await Promise.all([ directus.request( readItems('posts', { filter, limit, offset, sort: ['-published_at'], fields: [ 'id', 'title', 'slug', 'excerpt', 'featured_image', 'published_at', 'category', 'author' ] }) ), directus.request( aggregate('posts', { aggregate: { count: '*' }, query: { filter } }) ) ]); return { posts: posts || [], total: Number(countResult?.[0]?.count || 0) }; } catch (err) { console.error('Error fetching posts:', err); return { posts: [], total: 0 }; } } /** * Fetch a single post by slug */ export async function fetchPostBySlug( slug: string, siteId: string ): Promise { try { const posts = await directus.request( readItems('posts', { filter: { slug: { _eq: slug }, site: { _eq: siteId }, status: { _eq: 'published' } }, limit: 1, fields: ['*'] }) ); return posts?.[0] || null; } catch (err) { console.error('Error fetching post:', err); return null; } } /** * Fetch generated articles for a site */ export async function fetchGeneratedArticles( siteId: string, options?: { limit?: number; page?: number } ): Promise<{ articles: any[]; total: number }> { const limit = options?.limit || 20; const page = options?.page || 1; const offset = (page - 1) * limit; try { const [articles, countResult] = await Promise.all([ directus.request( readItems('generated_articles', { filter: { site: { _eq: siteId } }, limit, offset, sort: ['-date_created'], fields: ['*'] }) ), directus.request( aggregate('generated_articles', { aggregate: { count: '*' }, query: { filter: { site: { _eq: siteId } } } }) ) ]); return { articles: articles || [], total: Number(countResult?.[0]?.count || 0) }; } catch (err) { console.error('Error fetching articles:', err); return { articles: [], total: 0 }; } } /** * Fetch SEO campaigns */ export async function fetchCampaigns(siteId?: string) { const filter: Record = {}; if (siteId) { filter._or = [ { site: { _eq: siteId } }, { site: { _null: true } } ]; } try { return await directus.request( readItems('campaign_masters', { filter, sort: ['-date_created'], fields: ['*'] }) ); } catch (err) { console.error('Error fetching campaigns:', err); return []; } } /** * Fetch locations (states, counties, cities) */ export async function fetchStates() { return directus.request( readItems('locations_states', { sort: ['name'], fields: ['id', 'name', 'code'] }) ); } export async function fetchCountiesByState(stateId: string) { return directus.request( readItems('locations_counties', { filter: { state: { _eq: stateId } }, sort: ['name'], fields: ['id', 'name', 'fips_code', 'population'] }) ); } export async function fetchCitiesByCounty(countyId: string, limit = 50) { return directus.request( readItems('locations_cities', { filter: { county: { _eq: countyId } }, sort: ['-population'], limit, fields: ['id', 'name', 'population', 'lat', 'lng', 'postal_code'] }) ); }