diff --git a/frontend/src/globalInterfaces.ts b/frontend/src/globalInterfaces.ts index 64c16ba..a88fd88 100644 --- a/frontend/src/globalInterfaces.ts +++ b/frontend/src/globalInterfaces.ts @@ -64,9 +64,52 @@ export interface DocumentItem { tags?: string[]; } -export interface NavLink { +export interface PostVotes { + id: string; + post_id: string; + user_id: string; + vote_type: 'like' | 'dislike'; + created: string; + updated: string; +} + +export interface VoteStats { + likes: number; + dislikes: number; + userVote: 'like' | 'dislike' | null; +} + +export interface Comment { + id: string; + post_id: string; + user_id: string; + author_name: string; + content: string; + status: 'pending' | 'published'; + created: string; + updated: string; +} + +export interface Consultation { + id: string; name: string; - url: string; + phone: string; + question: string; + status: 'new' | 'in_progress' | 'completed'; + created: string; +} + +export interface PostResponse { + id: string; + slug: string; + title: string; + description: string; + author: string; + category: string; + categoryColor: string; + date: string; + readTime: string; + image: string | null; } export interface CompanyInfo { diff --git a/frontend/src/layouts/Layout.astro b/frontend/src/layouts/Layout.astro index 478af40..817fb16 100644 --- a/frontend/src/layouts/Layout.astro +++ b/frontend/src/layouts/Layout.astro @@ -14,9 +14,10 @@ export interface Props { description: string; canonicalLink?: string; breadcrumbs?: Array<{ label: string; href?: string }>; + ogImage?: string; } -const { title, description, canonicalLink, breadcrumbs } = Astro.props; +const { title, description, canonicalLink, breadcrumbs, ogImage } = Astro.props; --- @@ -32,6 +33,17 @@ const { title, description, canonicalLink, breadcrumbs } = Astro.props; {title} {SITE_TITLE_SUFFIX} {canonicalLink && } + + + + + {canonicalLink && } + {ogImage && } + + + + + {ogImage && } diff --git a/frontend/src/lib/pb.ts b/frontend/src/lib/pb.ts index b6f0b1d..d898212 100644 --- a/frontend/src/lib/pb.ts +++ b/frontend/src/lib/pb.ts @@ -60,13 +60,12 @@ export async function getPostVotes(postId: string): Promise { } export async function getPostVotesStats(postId: string): Promise<{ likes: number; dislikes: number }> { - // Получаем данные из коллекции голосов const votes = await pb.collection('post_votes').getList(1, 1000, { filter: `post="${postId}"`, }); - const likes = votes.items.filter((v: any) => v.vote_type === 'like').length; - const dislikes = votes.items.filter((v: any) => v.vote_type === 'dislike').length; + const likes = votes.items.filter((v) => v.vote_type === 'like').length; + const dislikes = votes.items.filter((v) => v.vote_type === 'dislike').length; return { likes, dislikes }; } diff --git a/frontend/src/pages/api/auth/confirm.ts b/frontend/src/pages/api/auth/confirm.ts index 04b8e57..dfaa160 100644 --- a/frontend/src/pages/api/auth/confirm.ts +++ b/frontend/src/pages/api/auth/confirm.ts @@ -61,7 +61,7 @@ export const POST: APIRoute = async ({ request }) => { message: 'Email подтверждён' }), { status: 200 }); - } catch (error: any) { + } catch (error: unknown) { console.error('Confirm error:', error); return new Response(JSON.stringify({ diff --git a/frontend/src/pages/api/auth/forgot-password.ts b/frontend/src/pages/api/auth/forgot-password.ts index 175f130..a68b14c 100644 --- a/frontend/src/pages/api/auth/forgot-password.ts +++ b/frontend/src/pages/api/auth/forgot-password.ts @@ -118,7 +118,7 @@ export const POST: APIRoute = async ({ request }) => { message: 'Ссылка для сброса пароля отправлена' }), { status: 200 }); - } catch (error: any) { + } catch (error: unknown) { console.error('Forgot password error:', error); return new Response(JSON.stringify({ diff --git a/frontend/src/pages/api/auth/request-password-reset.ts b/frontend/src/pages/api/auth/request-password-reset.ts index 8b35a29..21a8b0a 100644 --- a/frontend/src/pages/api/auth/request-password-reset.ts +++ b/frontend/src/pages/api/auth/request-password-reset.ts @@ -182,7 +182,7 @@ export const POST: APIRoute = async ({ request }) => { }); const collectionData = await collectionResponse.json(); - const fieldExists = collectionData.fields?.some((f: any) => f.name === 'reset_token'); + const fieldExists = collectionData.fields?.some((f: { name: string }) => f.name === 'reset_token'); if (!fieldExists) { // Добавляем поля в коллекцию diff --git a/frontend/src/pages/api/auth/reset-password.ts b/frontend/src/pages/api/auth/reset-password.ts index e78ea53..21c6033 100644 --- a/frontend/src/pages/api/auth/reset-password.ts +++ b/frontend/src/pages/api/auth/reset-password.ts @@ -59,7 +59,7 @@ export const POST: APIRoute = async ({ request }) => { message: 'Пароль успешно изменён' }), { status: 200 }); - } catch (error: any) { + } catch (error: unknown) { console.error('Reset password error:', error); return new Response(JSON.stringify({ diff --git a/frontend/src/pages/api/auth/sign-in.ts b/frontend/src/pages/api/auth/sign-in.ts index b29afa2..fd4ee14 100644 --- a/frontend/src/pages/api/auth/sign-in.ts +++ b/frontend/src/pages/api/auth/sign-in.ts @@ -53,12 +53,12 @@ export const POST: APIRoute = async ({ request, cookies, url }) => { redirect: redirectUrl }), { status: 200 }); - } catch (error: any) { + } catch (error: unknown) { console.error('Sign in error:', error); return new Response(JSON.stringify({ success: false, - error: error.message || 'Неверный email или пароль' + error: error instanceof Error ? error.message : 'Неверный email или пароль' }), { status: 401 }); } }; \ No newline at end of file diff --git a/frontend/src/pages/api/auth/sign-up.ts b/frontend/src/pages/api/auth/sign-up.ts index 92fd492..f4477de 100644 --- a/frontend/src/pages/api/auth/sign-up.ts +++ b/frontend/src/pages/api/auth/sign-up.ts @@ -80,19 +80,20 @@ export const POST: APIRoute = async ({ request, redirect }) => { email }), { status: 201 }); - } catch (error: any) { + } catch (error: unknown) { console.error('Sign up error:', error); let errorMessage = 'Ошибка при регистрации'; - if (error.response?.data) { - const data = error.response.data; - if (data.email) { - errorMessage = `Email: ${data.email.message || 'уже используется'}`; - } else if (data.password) { - errorMessage = `Пароль: ${data.password.message || 'некорректный'}`; + if (error && typeof error === 'object' && 'response' in error) { + const errWithResponse = error as { response?: { data?: Record } }; + const data = errWithResponse.response?.data as Record | undefined; + if (data?.email) { + errorMessage = `Email: ${(data.email as { message?: string }).message || 'уже используется'}`; + } else if (data?.password) { + errorMessage = `Пароль: ${(data.password as { message?: string }).message || 'некорректный'}`; } - } else if (error.message) { + } else if (error instanceof Error) { errorMessage = error.message; } diff --git a/frontend/src/pages/api/consultation.ts b/frontend/src/pages/api/consultation.ts index 8e70bdf..3a12eac 100644 --- a/frontend/src/pages/api/consultation.ts +++ b/frontend/src/pages/api/consultation.ts @@ -146,12 +146,13 @@ export const POST: APIRoute = async ({ request }) => { id: result.id }), { status: 201, headers: { 'Content-Type': 'application/json' } }); - } catch (error: any) { + } catch (error: unknown) { console.error('Consultation error:', error); + const message = error instanceof Error ? error.message : 'Ошибка при отправке заявки'; return new Response(JSON.stringify({ success: false, - error: error.message || 'Ошибка при отправке заявки' + error: message }), { status: 400, headers: { 'Content-Type': 'application/json' } }); } }; \ No newline at end of file diff --git a/frontend/src/pages/api/posts/[slug].ts b/frontend/src/pages/api/posts/[slug].ts index 7372625..779c46f 100644 --- a/frontend/src/pages/api/posts/[slug].ts +++ b/frontend/src/pages/api/posts/[slug].ts @@ -38,11 +38,13 @@ export const GET: APIRoute = async ({ params }) => { content: post.content, }), { status: 200 }); - } catch (error: any) { + } catch (error: unknown) { console.error('API post error:', error); + const message = error instanceof Error ? error.message : 'Ошибка при получении поста'; + return new Response(JSON.stringify({ - error: error.message || 'Ошибка при получении поста' + error: message }), { status: 500 }); } }; \ No newline at end of file diff --git a/frontend/src/pages/api/posts/index.ts b/frontend/src/pages/api/posts/index.ts index f790e4f..7ede8d5 100644 --- a/frontend/src/pages/api/posts/index.ts +++ b/frontend/src/pages/api/posts/index.ts @@ -1,5 +1,6 @@ import type { APIRoute } from 'astro'; import PocketBase from 'pocketbase'; +import type { PostResponse } from '../../globalInterfaces'; const PB_URL = import.meta.env.PB_POCKETBASE_URL || 'http://127.0.0.1:8090'; @@ -27,7 +28,7 @@ export const GET: APIRoute = async ({ url }) => { sort: '-date', }); - const getImageUrl = (post: any) => { + const getImageUrl = (post: PostResponse) => { if (!post.image) return null; const fileUrl = pb.files.getUrl(post, post.image); if (fileUrl.startsWith('/')) { @@ -37,7 +38,7 @@ export const GET: APIRoute = async ({ url }) => { }; return new Response(JSON.stringify({ - posts: result.items.map(post => ({ + posts: result.items.map((post) => ({ id: post.id, slug: post.slug, title: post.title, @@ -55,11 +56,13 @@ export const GET: APIRoute = async ({ url }) => { totalPages: result.totalPages, }), { status: 200 }); - } catch (error: any) { + } catch (error: unknown) { console.error('API posts error:', error); + const message = error instanceof Error ? error.message : 'Ошибка при получении постов'; + return new Response(JSON.stringify({ - error: error.message || 'Ошибка при получении постов' + error: message }), { status: 500 }); } }; \ No newline at end of file diff --git a/frontend/src/pages/api/reviews/vote.ts b/frontend/src/pages/api/reviews/vote.ts index cd98dca..2ef91e6 100644 --- a/frontend/src/pages/api/reviews/vote.ts +++ b/frontend/src/pages/api/reviews/vote.ts @@ -125,8 +125,8 @@ export const POST: APIRoute = async ({ request, cookies }) => { if (votesRes.ok) { const votesData = await votesRes.json(); console.log('[ReviewVote API] Votes data:', JSON.stringify(votesData)); - likes = votesData.items?.filter((v: any) => v.vote_type === 'likes').length || 0; - dislikes = votesData.items?.filter((v: any) => v.vote_type === 'dislikes').length || 0; + likes = votesData.items?.filter((v: { vote_type: string }) => v.vote_type === 'likes').length || 0; + dislikes = votesData.items?.filter((v: { vote_type: string }) => v.vote_type === 'dislikes').length || 0; } else { const errorText = await votesRes.text(); console.error('[ReviewVote API] Votes error:', errorText); @@ -179,8 +179,8 @@ export const GET: APIRoute = async ({ url, cookies }) => { if (votesRes.ok) { const votesData = await votesRes.json(); console.log('[ReviewVote API GET] Votes data:', JSON.stringify(votesData)); - likes = votesData.items?.filter((v: any) => v.vote_type === 'likes').length || 0; - dislikes = votesData.items?.filter((v: any) => v.vote_type === 'dislikes').length || 0; + likes = votesData.items?.filter((v: { vote_type: string }) => v.vote_type === 'likes').length || 0; + dislikes = votesData.items?.filter((v: { vote_type: string }) => v.vote_type === 'dislikes').length || 0; } let userVote: 'likes' | 'dislikes' | null = null; diff --git a/frontend/src/pages/api/votes.ts b/frontend/src/pages/api/votes.ts index 47fa68f..a6306b6 100644 --- a/frontend/src/pages/api/votes.ts +++ b/frontend/src/pages/api/votes.ts @@ -167,8 +167,8 @@ export const POST: APIRoute = async ({ request, cookies }) => { if (votesRes.ok) { const votesData = await votesRes.json(); - likes = votesData.items.filter((v: any) => v.vote_type === 'like').length; - dislikes = votesData.items.filter((v: any) => v.vote_type === 'dislike').length; + likes = votesData.items.filter((v: { vote_type: string }) => v.vote_type === 'like').length; + dislikes = votesData.items.filter((v: { vote_type: string }) => v.vote_type === 'dislike').length; } // Обновляем счетчики в посте только если есть токен @@ -243,8 +243,8 @@ export const GET: APIRoute = async ({ url, cookies }) => { if (votesCountRes.ok) { const votesData = await votesCountRes.json(); - likes = votesData.items.filter((v: any) => v.vote_type === 'like').length; - dislikes = votesData.items.filter((v: any) => v.vote_type === 'dislike').length; + likes = votesData.items.filter((v: { vote_type: string }) => v.vote_type === 'like').length; + dislikes = votesData.items.filter((v: { vote_type: string }) => v.vote_type === 'dislike').length; } // Определяем голос текущего пользователя diff --git a/frontend/src/pages/blog/category/[category].astro b/frontend/src/pages/blog/category/[category].astro index c715ffd..3ae46e7 100644 --- a/frontend/src/pages/blog/category/[category].astro +++ b/frontend/src/pages/blog/category/[category].astro @@ -7,6 +7,7 @@ import BlogCard from '@components/blog/BlogCard.astro'; import Pagination from '@components/base/Pagination.astro'; import SearchModal from '@components/base/SearchModal.astro'; import { getPosts, getAllCategories, getPostImageUrl } from '@lib/pb'; +import type { Post } from '@globalInterfaces'; export const prerender = false; @@ -65,7 +66,7 @@ const formatDate = (date: string) => {
{posts.length > 0 ? ( - posts.map((post: any) => ( + posts.map((post: Post) => (
{
{posts.length > 0 ? ( - posts.map((post: any) => ( + posts.map((post: Post) => (
- {posts.map((post: any) => ( + {posts.map((post: Post) => (
{
- {posts.map((post: any) => ( + {posts.map((post: Post) => (
{
- {searchResults.map((post: any) => ( + {searchResults.map((post: Post) => (