Files
profile-front/src/lib/api/posts.ts
Profile Profile 1b5530392f add real authors
2026-01-28 12:02:55 +03:00

507 lines
10 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { fetchGraphQL } from './graphql-client.js';
import type { ProfileArticle } from '../types/graphql.js';
//кэширование
import { cache } from '@lib/cache/manager.js';
import { CACHE_TTL } from '@lib/cache/cache-ttl';
export interface AnewsPost {
title: string;
uri: string;
date: string;
}
export async function getLatestPosts(first = 14, after = null) {
// Создаем уникальный ключ для кэша
const cacheKey = `latest-posts:${first}:${after || 'first-page'}`;
return await cache.wrap(
cacheKey,
async () => {
const query = `
query GetLatestProfileArticles($first: Int!, $after: String) {
profileArticles(
first: $first
after: $after
where: { orderby: { field: DATE, order: DESC } }
) {
pageInfo {
hasNextPage
endCursor
}
edges {
cursor
node {
id
databaseId
title
uri
date
featuredImage {
node {
sourceUrl(size: LARGE)
altText
}
}
author {
node {
id
name
firstName
lastName
avatar {
url
}
uri
}
}
# Соавторы как массив
coauthors {
id
name
firstName
lastName
url
description
}
categories {
nodes {
id
name
color
slug
uri
databaseId
}
}
tags {
nodes {
id
name
slug
uri
}
}
}
}
}
}
`;
const data = await fetchGraphQL(query, { first, after });
// Преобразуем edges в nodes
const posts = data.profileArticles?.edges?.map(edge => edge.node) || [];
return {
posts,
pageInfo: data.profileArticles?.pageInfo || { hasNextPage: false, endCursor: null }
};
},
{ ttl: CACHE_TTL.POSTS } // из конфигурации
);
}
//последние новости (кэшированная версия)
export async function getLatestAnews(count = 12): Promise<AnewsPost[]> {
const cacheKey = `latest-anews:${count}`;
return await cache.wrap(
cacheKey,
async () => {
const query = `
query GetAnews($count: Int!) {
aNews(first: $count, where: {orderby: {field: DATE, order: DESC}}) {
nodes {
title
uri
date
}
}
}
`;
const data = await fetchGraphQL(query, { count });
return data.aNews?.nodes || [];
},
{ ttl: CACHE_TTL.POSTS }
);
}
// Получить ProfileArticle по databaseId
export async function getProfileArticleById(databaseId) {
const query = `
query GetProfileArticleById($id: ID!) {
profileArticle(id: $id, idType: DATABASE_ID) {
id
databaseId
title
content
excerpt
uri
slug
date
modified
status
featuredImage {
node {
id
sourceUrl
altText
caption
mediaDetails {
width
height
}
}
}
author {
node {
id
name
firstName
lastName
avatar {
url
}
description
uri
}
}
categories {
nodes {
id
name
slug
uri
description
}
}
tags {
nodes {
id
name
slug
uri
}
}
}
}
`;
const data = await fetchGraphQL(query, { id: databaseId });
return data?.profileArticle || null;
}
/**
* Получить Anews пост по databaseId
*/
export async function getAnewsById(databaseId: number): Promise<SingleAnewsPost | null> {
const cacheKey = `anews:${databaseId}`;
return await cache.wrap(
cacheKey,
async () => {
const query = `
query GetAnewsById($id: ID!) {
aNews(id: $id, idType: DATABASE_ID) {
id
databaseId
title
content
excerpt
uri
slug
date
modified
status
featuredImage {
node {
id
sourceUrl
altText
caption
mediaDetails {
width
height
}
}
}
author {
node {
id
name
firstName
lastName
avatar {
url
}
description
uri
}
}
categories {
nodes {
id
name
slug
uri
description
}
}
tags {
nodes {
id
name
slug
uri
}
}
seo {
title
metaDesc
canonical
opengraphTitle
opengraphDescription
opengraphImage {
sourceUrl
}
}
}
}
`;
try {
const data = await fetchGraphQL(query, { id: databaseId });
return data?.aNews || null;
} catch (error) {
console.error(`Error fetching Anews post with ID ${databaseId}:`, error);
return null;
}
},
{ ttl: CACHE_TTL.POST_DETAIL } // Можно использовать отдельный TTL для деталей постов
);
}
/**
* Получить тег по slug
*/
export async function getTagBySlug(slug) {
const query = `
query GetTagBySlug($slug: ID!) {
tag(id: $slug, idType: SLUG) {
id
databaseId
name
slug
description
count
}
}
`;
try {
const data = await fetchGraphQL(query, { slug });
return data?.tag || null;
} catch (error) {
console.error('Error fetching tag:', error);
return null;
}
}
/**
* Получить тег с постами по slug с пагинацией
*/
export async function getTagWithPostsPaginated(
tagSlug: string,
perPage: number = 12,
page: number = 1
) {
const offset = (page - 1) * perPage;
const query = `
query GetTagWithPostsPaginated($slug: ID!, $first: Int!, $offset: Int!) {
tag(id: $slug, idType: SLUG) {
id
databaseId
name
slug
description
count
seo {
title
metaDesc
canonical
opengraphTitle
opengraphDescription
opengraphImage {
sourceUrl
}
}
posts(
first: $first
offset: $offset
where: {
orderby: {
field: DATE,
order: DESC
}
}
) {
nodes {
id
databaseId
title
excerpt
uri
slug
date
modified
featuredImage {
node {
sourceUrl(size: MEDIUM_LARGE)
altText
caption
mediaDetails {
width
height
}
}
}
author {
node {
id
name
firstName
lastName
avatar {
url
}
}
}
categories {
nodes {
id
name
slug
uri
}
}
tags {
nodes {
id
name
slug
}
}
seo {
title
metaDesc
}
}
pageInfo {
offsetPagination {
total
}
}
}
}
}
`;
try {
const data = await fetchGraphQL(query, {
slug: tagSlug,
first: perPage,
offset
});
const tag = data?.tag;
if (!tag) {
return {
tag: null,
posts: [],
total: 0,
totalPages: 0,
currentPage: page,
hasNext: false,
hasPrevious: false
};
}
const posts = tag.posts?.nodes || [];
const total = tag.posts?.pageInfo?.offsetPagination?.total || 0;
const totalPages = Math.ceil(total / perPage);
return {
tag,
posts,
total,
totalPages,
currentPage: page,
hasNext: page < totalPages,
hasPrevious: page > 1,
perPage
};
} catch (error) {
console.error('Error fetching tag with posts:', error);
return {
tag: null,
posts: [],
total: 0,
totalPages: 0,
currentPage: page,
hasNext: false,
hasPrevious: false
};
}
}
/**
* Получить общее количество постов для всех тегов
*/
export async function getAllTagsWithCount(first = 100) {
const query = `
query GetAllTagsWithCount($first: Int!) {
tags(first: $first, where: { hideEmpty: true }) {
nodes {
id
databaseId
name
slug
count
posts(first: 1) {
pageInfo {
offsetPagination {
total
}
}
}
}
}
}
`;
const data = await fetchGraphQL(query, { first });
return data?.tags?.nodes || [];
}