Files
profile-front/src/lib/api/authors.ts

281 lines
7.6 KiB
TypeScript
Raw Normal View History

2026-03-02 23:10:31 +03:00
import { fetchGraphQL } from './graphql-client.js';
//кэширование
import { cache } from '@lib/cache/manager.js';
import { CACHE_TTL } from '@lib/cache/cache-ttl';
2026-03-05 00:23:51 +03:00
// lib/api/authors.js
export async function getPostsByCoauthorLogin(coauthorLogin, perLoad = 14, after = null) {
const cacheKey = `coauthor-posts:${coauthorLogin}:${perLoad}:${after || 'first-page'}`;
2026-03-02 23:10:31 +03:00
return await cache.wrap(
cacheKey,
async () => {
2026-03-05 00:23:51 +03:00
try {
const baseUrl = import.meta.env.WP_REST_BASE_URL?.replace(/\/$/, '');
// Формируем URL
const url = `${baseUrl}/author/${coauthorLogin}/posts?per_page=${perLoad}${
after ? `&cursor=${encodeURIComponent(after)}` : ''
}`;
const response = await fetch(url);
if (!response.ok) {
if (response.status === 404) {
return { posts: [], pageInfo: { hasNextPage: false, endCursor: null } };
2026-03-02 23:10:31 +03:00
}
2026-03-05 00:23:51 +03:00
throw new Error(`HTTP error: ${response.status}`);
}
const data = await response.json();
// Преобразуем данные для компонента
const posts = (data.data || []).map(post => ({
// ID и ссылки
databaseId: post.id,
uri: post.link, // компонент использует uri
2026-03-02 23:10:31 +03:00
2026-03-05 00:23:51 +03:00
// Основные поля
title: post.title,
date: post.date,
// Картинка - приводим к формату GraphQL
featuredImage: post.featured_image?.medium ? {
node: {
sourceUrl: post.featured_image.medium,
altText: post.title
2026-03-02 23:10:31 +03:00
}
2026-03-05 00:23:51 +03:00
} : null,
// Категории - приводим к формату nodes
categories: {
nodes: (post.categories || []).map(cat => ({
name: cat.name,
slug: cat.slug,
color: cat.color || null
}))
},
// Соавторы - компонент ожидает массив с name и nickname
coauthors: (post.coauthors || []).map(coauthor => ({
name: coauthor.name,
nickname: coauthor.id, // id используем как nickname для ссылки
node: {
name: coauthor.name,
nickname: coauthor.id
2026-03-02 23:10:31 +03:00
}
2026-03-05 00:23:51 +03:00
}))
}));
2026-03-02 23:10:31 +03:00
return {
2026-03-05 00:23:51 +03:00
posts,
pageInfo: {
hasNextPage: data.pagination?.has_next || false,
endCursor: data.pagination?.next_cursor || null
}
2026-03-02 23:10:31 +03:00
};
2026-03-05 00:23:51 +03:00
} catch (error) {
console.error(`❌ Error fetching author posts:`, error);
return { posts: [], pageInfo: { hasNextPage: false, endCursor: null } };
2026-03-02 23:10:31 +03:00
}
},
2026-03-05 00:23:51 +03:00
{ ttl: 3600 }
2026-03-02 23:10:31 +03:00
);
}
2026-03-05 00:23:51 +03:00
2026-03-02 23:10:31 +03:00
// все посты автора
2026-03-05 00:23:51 +03:00
export async function getPostsByCoauthorLoginQL(login, first = 14, after = null) {
2026-03-02 23:10:31 +03:00
// Создаем уникальный ключ для кэша
const cacheKey = `coauthor-posts-by-login:${login}:${first}:${after || 'first-page'}`;
return await cache.wrap(
cacheKey,
async () => {
const query = `
query GetPostsByCoauthorLogin($first: Int!, $after: String, $login: String!) {
contentNodes(
first: $first
after: $after
where: {
contentTypes: [PROFILE_ARTICLE, ANEW]
coauthorLogin: $login
orderby: { field: DATE, order: DESC }
}
) {
pageInfo {
hasNextPage
endCursor
}
nodes {
__typename
id
databaseId
uri
date
... on NodeWithTitle {
title
}
... on NodeWithFeaturedImage {
featuredImage {
node {
sourceUrl(size: LARGE)
altText
}
}
}
# Для ваших кастомных типов
... on ProfileArticle {
categories {
nodes {
name
slug
color
}
}
}
... on ANew {
categories {
nodes {
name
slug
color
}
}
}
... on NodeWithAuthor {
author {
node {
name
avatar {
url
}
}
}
}
# Coauthors для ProfileArticle
... on ProfileArticle {
coauthors {
id
name
firstName
lastName
url
nicename # Добавляем nicename (login)
}
}
# Coauthors для ANew
... on ANew {
coauthors {
id
name
firstName
lastName
url
nicename # Добавляем nicename (login)
}
}
}
}
}
`;
const data = await fetchGraphQL(query, {
first,
after,
login
});
// Обрабатываем посты
const posts = data.contentNodes?.nodes?.map(node => {
// Приводим coauthors к единому формату
if (node.coauthors) {
node.coauthors = node.coauthors.map(author => ({
id: author.id,
name: author.name || '',
firstName: author.firstName || '',
lastName: author.lastName || '',
url: author.url || '',
nicename: author.nicename || '' // Добавляем login
}));
}
return node;
}) || [];
return {
posts,
pageInfo: data.contentNodes?.pageInfo || {
hasNextPage: false,
endCursor: null
},
authorLogin: login
};
},
{ ttl: CACHE_TTL.POSTS }
);
}
export async function getAuthorData(slug) {
const cacheKey = `author-data:slug:${slug}`;
return await cache.wrap(
cacheKey,
async () => {
const baseUrl = import.meta.env.WP_REST_BASE_URL.replace(/\/$/, '');
try {
const response = await fetch(`${baseUrl}/author/${slug}`);
if (!response.ok) {
if (response.status === 404) {
return null;
}
throw new Error(`HTTP error: ${response.status}`);
}
const author = await response.json();
// Форматируем ответ
return {
id: author.slug || author.id,
name: author.name,
firstName: author.firstName,
lastName: author.lastName,
avatar: author.photo || author.avatar,
avatar_sizes: author.photo_sizes || {},
bio: author.description,
social: author.social || {},
url: author.url,
type: author.type,
};
} catch (error) {
console.error(`❌ Failed to fetch author ${slug}:`, error);
return null;
}
},
{ ttl: CACHE_TTL.AUTHOR }
);
}