split category fetching from menu items
This commit is contained in:
@@ -1,13 +0,0 @@
|
|||||||
/* eslint-disable */
|
|
||||||
/* Generated by scripts/endpoint-generate.mjs — do not edit by hand */
|
|
||||||
import type { ExecutionResult } from "graphql";
|
|
||||||
|
|
||||||
import { execute } from "../graphql/execute";
|
|
||||||
import type { CategoriesListQuery, CategoriesListQueryVariables } from "../graphql/graphql";
|
|
||||||
import { categoriesListDocument } from "./categories.gql";
|
|
||||||
|
|
||||||
export const categoriesListQuery = {
|
|
||||||
async execute(variables?: CategoriesListQueryVariables): Promise<ExecutionResult<CategoriesListQuery>> {
|
|
||||||
return execute<CategoriesListQuery, CategoriesListQueryVariables>(categoriesListDocument, variables);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
import gql from 'graphql-tag'
|
|
||||||
|
|
||||||
export const categoriesListDocument = gql`
|
|
||||||
query CategoriesList($group: String) {
|
|
||||||
categories(filters: { group: { eq: $group } }) {
|
|
||||||
documentId
|
|
||||||
slug
|
|
||||||
title
|
|
||||||
sortOrder
|
|
||||||
group
|
|
||||||
badge
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`
|
|
||||||
13
src/graphql-documents/category.gql.generated.ts
Normal file
13
src/graphql-documents/category.gql.generated.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
/* eslint-disable */
|
||||||
|
/* Generated by scripts/endpoint-generate.mjs — do not edit by hand */
|
||||||
|
import type { ExecutionResult } from "graphql";
|
||||||
|
|
||||||
|
import { execute } from "../graphql/execute";
|
||||||
|
import type { CategoryQuery, CategoryQueryVariables } from "../graphql/graphql";
|
||||||
|
import { categoryDocument } from "./category.gql";
|
||||||
|
|
||||||
|
export const categoryQuery = {
|
||||||
|
async execute(variables?: CategoryQueryVariables): Promise<ExecutionResult<CategoryQuery>> {
|
||||||
|
return execute<CategoryQuery, CategoryQueryVariables>(categoryDocument, variables);
|
||||||
|
},
|
||||||
|
};
|
||||||
22
src/graphql-documents/category.gql.ts
Normal file
22
src/graphql-documents/category.gql.ts
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import gql from 'graphql-tag'
|
||||||
|
|
||||||
|
export const categoryDocument = gql`
|
||||||
|
query Category($slug: String!) {
|
||||||
|
categories(filters: { slug: { eq: $slug } }, pagination: { pageSize: 1 }) {
|
||||||
|
slug
|
||||||
|
title
|
||||||
|
description
|
||||||
|
group
|
||||||
|
badge
|
||||||
|
vendors(pagination: { pageSize: 200 }) {
|
||||||
|
slug
|
||||||
|
title
|
||||||
|
description
|
||||||
|
products(pagination: { pageSize: 200 }) {
|
||||||
|
id
|
||||||
|
value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
@@ -1554,12 +1554,12 @@ export type VendorRelationResponseCollection = {
|
|||||||
nodes: Array<Vendor>;
|
nodes: Array<Vendor>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type CategoriesListQueryVariables = Exact<{
|
export type CategoryQueryVariables = Exact<{
|
||||||
group?: InputMaybe<Scalars['String']['input']>;
|
slug: Scalars['String']['input'];
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
|
||||||
export type CategoriesListQuery = { __typename?: 'Query', categories: Array<{ __typename?: 'Category', documentId: string, slug: string, title?: string | null, sortOrder: number, group: Enum_Category_Group, badge?: string | null } | null> };
|
export type CategoryQuery = { __typename?: 'Query', categories: Array<{ __typename?: 'Category', slug: string, title?: string | null, description?: string | null, group: Enum_Category_Group, badge?: string | null, vendors: Array<{ __typename?: 'Vendor', slug: string, title?: string | null, description?: string | null, products?: Array<{ __typename?: 'ComponentSharedString', id: string, value: string } | null> | null } | null> } | null> };
|
||||||
|
|
||||||
export type HomePageQueryVariables = Exact<{ [key: string]: never; }>;
|
export type HomePageQueryVariables = Exact<{ [key: string]: never; }>;
|
||||||
|
|
||||||
@@ -1602,18 +1602,26 @@ export class TypedDocumentString<TResult, TVariables>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CategoriesListDocument = new TypedDocumentString(`
|
export const CategoryDocument = new TypedDocumentString(`
|
||||||
query CategoriesList($group: String) {
|
query Category($slug: String!) {
|
||||||
categories(filters: {group: {eq: $group}}) {
|
categories(filters: {slug: {eq: $slug}}, pagination: {pageSize: 1}) {
|
||||||
documentId
|
|
||||||
slug
|
slug
|
||||||
title
|
title
|
||||||
sortOrder
|
description
|
||||||
group
|
group
|
||||||
badge
|
badge
|
||||||
|
vendors(pagination: {pageSize: 200}) {
|
||||||
|
slug
|
||||||
|
title
|
||||||
|
description
|
||||||
|
products(pagination: {pageSize: 200}) {
|
||||||
|
id
|
||||||
|
value
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`) as unknown as TypedDocumentString<CategoriesListQuery, CategoriesListQueryVariables>;
|
`) as unknown as TypedDocumentString<CategoryQuery, CategoryQueryVariables>;
|
||||||
export const HomePageDocument = new TypedDocumentString(`
|
export const HomePageDocument = new TypedDocumentString(`
|
||||||
query HomePage {
|
query HomePage {
|
||||||
homePage {
|
homePage {
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
---
|
---
|
||||||
import Layout from '../layouts/Layout.astro'
|
import Layout from '../layouts/Layout.astro'
|
||||||
import '../styles/globals.css'
|
import '../styles/globals.css'
|
||||||
import { getCollection, type CollectionEntry } from 'astro:content'
|
|
||||||
import { Header } from '../sections/Header'
|
import { Header } from '../sections/Header'
|
||||||
import { Footer } from '../sections/Footer'
|
import { Footer } from '../sections/Footer'
|
||||||
import { Enum_Category_Group } from '../graphql/graphql'
|
import { Enum_Category_Group } from '../graphql/graphql'
|
||||||
@@ -10,9 +9,9 @@ import type { MenuItemsQuery } from '../graphql/graphql'
|
|||||||
import type { SiteConfigContact } from '../lib/cms/contact/types'
|
import type { SiteConfigContact } from '../lib/cms/contact/types'
|
||||||
import { siteConfigQuery } from '../graphql-documents/site-config.gql.generated'
|
import { siteConfigQuery } from '../graphql-documents/site-config.gql.generated'
|
||||||
import { menuItemsQuery } from '../graphql-documents/menu-items.gql.generated'
|
import { menuItemsQuery } from '../graphql-documents/menu-items.gql.generated'
|
||||||
|
import { categoryQuery } from '../graphql-documents/category.gql.generated'
|
||||||
|
|
||||||
export async function getStaticPaths() {
|
export async function getStaticPaths() {
|
||||||
const categories = await getCollection('categories')
|
|
||||||
const [siteResult, menuItemsResult] = await Promise.all([siteConfigQuery.execute(), menuItemsQuery.execute()])
|
const [siteResult, menuItemsResult] = await Promise.all([siteConfigQuery.execute(), menuItemsQuery.execute()])
|
||||||
if (siteResult.errors?.length) {
|
if (siteResult.errors?.length) {
|
||||||
throw new Error(siteResult.errors.map(e => e.message).join(', '))
|
throw new Error(siteResult.errors.map(e => e.message).join(', '))
|
||||||
@@ -27,12 +26,9 @@ export async function getStaticPaths() {
|
|||||||
const solutionCategories = menuItems.filter(c => c.group === Enum_Category_Group.Solution)
|
const solutionCategories = menuItems.filter(c => c.group === Enum_Category_Group.Solution)
|
||||||
const serviceCategories = menuItems.filter(c => c.group === Enum_Category_Group.Service)
|
const serviceCategories = menuItems.filter(c => c.group === Enum_Category_Group.Service)
|
||||||
|
|
||||||
return categories.map((entry: CollectionEntry<'categories'>) => ({
|
return menuItems.map(category => ({
|
||||||
params: { slug: entry.id },
|
params: { slug: category.slug },
|
||||||
props: {
|
props: {
|
||||||
title: entry.data.title,
|
|
||||||
description: entry.data.description,
|
|
||||||
vendors: entry.data.vendors,
|
|
||||||
contacts,
|
contacts,
|
||||||
solutionCategories,
|
solutionCategories,
|
||||||
serviceCategories,
|
serviceCategories,
|
||||||
@@ -41,25 +37,44 @@ export async function getStaticPaths() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
title: string
|
|
||||||
description: string
|
|
||||||
vendors: {
|
|
||||||
name: string
|
|
||||||
description: string
|
|
||||||
products?: string[]
|
|
||||||
}[]
|
|
||||||
contacts: SiteConfigContact[]
|
contacts: SiteConfigContact[]
|
||||||
solutionCategories: NonNullable<MenuItemsQuery['categories'][number]>[]
|
solutionCategories: NonNullable<MenuItemsQuery['categories'][number]>[]
|
||||||
serviceCategories: NonNullable<MenuItemsQuery['categories'][number]>[]
|
serviceCategories: NonNullable<MenuItemsQuery['categories'][number]>[]
|
||||||
}
|
}
|
||||||
|
|
||||||
const { title, description, vendors, contacts, solutionCategories, serviceCategories } = Astro.props as Props
|
const { contacts, solutionCategories, serviceCategories } = Astro.props as Props
|
||||||
|
const slug = Astro.params.slug
|
||||||
|
|
||||||
|
if (!slug) {
|
||||||
|
throw new Error('Missing slug param for category page')
|
||||||
|
}
|
||||||
|
|
||||||
|
const categoryResult = await categoryQuery.execute({ slug })
|
||||||
|
|
||||||
|
if (categoryResult.errors?.length) {
|
||||||
|
throw new Error(categoryResult.errors.map(e => e.message).join(', '))
|
||||||
|
}
|
||||||
|
|
||||||
|
const category = categoryResult.data?.categories?.find(c => c != null)
|
||||||
|
|
||||||
|
if (!category) {
|
||||||
|
throw new Error(`Category not found for slug: ${slug}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
const title = category.title ?? undefined
|
||||||
|
const description = category.description ?? undefined
|
||||||
|
const badge = category.badge ?? undefined
|
||||||
|
const vendors = (category.vendors?.filter(v => v != null) ?? []).map(vendor => ({
|
||||||
|
name: vendor.title ?? undefined,
|
||||||
|
description: vendor.description ?? undefined,
|
||||||
|
products: (vendor.products?.filter(p => p != null) ?? []).map(product => product.value),
|
||||||
|
}))
|
||||||
---
|
---
|
||||||
|
|
||||||
<Layout>
|
<Layout>
|
||||||
<div class="min-h-screen bg-white w-full overflow-x-hidden">
|
<div class="min-h-screen bg-white w-full overflow-x-hidden">
|
||||||
<Header client:load contacts={contacts} solutions={solutionCategories} services={serviceCategories} />
|
<Header client:load contacts={contacts} solutions={solutionCategories} services={serviceCategories} />
|
||||||
<CategoryView client:load title={title} description={description} vendors={vendors} />
|
<CategoryView client:load badge={badge} title={title} description={description} vendors={vendors} />
|
||||||
<Footer client:load contacts={contacts} solutionCategories={solutionCategories} />
|
<Footer client:load contacts={contacts} solutionCategories={solutionCategories} />
|
||||||
</div>
|
</div>
|
||||||
</Layout>
|
</Layout>
|
||||||
|
|||||||
@@ -30,8 +30,10 @@ const contacts = siteResult.data?.siteConfig?.contacts?.filter(c => c != null) ?
|
|||||||
const menuItems = (menuItemsResult.data?.categories?.filter(c => c != null) ?? []).sort(
|
const menuItems = (menuItemsResult.data?.categories?.filter(c => c != null) ?? []).sort(
|
||||||
(a, b) => a.sortOrder - b.sortOrder
|
(a, b) => a.sortOrder - b.sortOrder
|
||||||
)
|
)
|
||||||
|
|
||||||
const solutionCategories = menuItems.filter(c => c.group === Enum_Category_Group.Solution)
|
const solutionCategories = menuItems.filter(c => c.group === Enum_Category_Group.Solution)
|
||||||
const serviceCategories = menuItems.filter(c => c.group === Enum_Category_Group.Service)
|
const serviceCategories = menuItems.filter(c => c.group === Enum_Category_Group.Service)
|
||||||
|
console.log(solutionCategories);
|
||||||
---
|
---
|
||||||
|
|
||||||
<Layout>
|
<Layout>
|
||||||
|
|||||||
@@ -20,9 +20,10 @@ export function CategoryPageHero({ title, description, badge }: CategoryPageHero
|
|||||||
|
|
||||||
<div className="flex items-start gap-8">
|
<div className="flex items-start gap-8">
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
{badge && (
|
<div className="inline-block px-4 py-1.5 bg-blue-50 text-blue-600 rounded-full text-sm mb-6">
|
||||||
<div className="inline-block px-4 py-1.5 bg-blue-50 text-blue-600 rounded-full text-sm mb-6">{badge}</div>
|
{badge || 'Каталог решений'}
|
||||||
)}
|
</div>
|
||||||
|
|
||||||
{title && <h1 className="text-5xl lg:text-6xl mb-6 leading-tight text-gray-900">{title}</h1>}
|
{title && <h1 className="text-5xl lg:text-6xl mb-6 leading-tight text-gray-900">{title}</h1>}
|
||||||
{description && <p className="text-xl text-gray-600 max-w-3xl leading-relaxed">{description}</p>}
|
{description && <p className="text-xl text-gray-600 max-w-3xl leading-relaxed">{description}</p>}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -5,12 +5,13 @@ import { Vendors } from '../sections/Vendors'
|
|||||||
export type CategoryViewProps = {
|
export type CategoryViewProps = {
|
||||||
title?: string
|
title?: string
|
||||||
description?: string
|
description?: string
|
||||||
|
badge?: string
|
||||||
} & ComponentProps<typeof Vendors>
|
} & ComponentProps<typeof Vendors>
|
||||||
|
|
||||||
export function CategoryView({ title, description, vendors }: CategoryViewProps) {
|
export function CategoryView({ title, description, vendors, badge }: CategoryViewProps) {
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-gray-50">
|
<div className="min-h-screen bg-gray-50">
|
||||||
<CategoryPageHero badge="Каталог решений" title={title} description={description} />
|
<CategoryPageHero badge={badge} title={title} description={description} />
|
||||||
<Vendors vendors={vendors} />
|
<Vendors vendors={vendors} />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user