mirror of
https://github.com/vercel/commerce.git
synced 2025-07-22 20:26:49 +00:00
🐛 bug: fix bug get-all-blog
:%s
This commit is contained in:
@@ -1,7 +1,8 @@
|
|||||||
|
import { GetAllRecipePathsOperation, GetRecipeDetailOperation,GetAllRecipesOperation } from './../types/recipes';
|
||||||
import { GetAllFacetsOperation } from './../types/facet';
|
import { GetAllFacetsOperation } from './../types/facet';
|
||||||
import type { ServerResponse } from 'http'
|
import type { ServerResponse } from 'http'
|
||||||
import type { LoginOperation } from '../types/login'
|
import type { LoginOperation } from '../types/login'
|
||||||
import type { GetAllPagesOperation, GetPageOperation } from '../types/page'
|
import type { GetAllPagesOperation } from '../types/page'
|
||||||
import type { GetSiteInfoOperation } from '../types/site'
|
import type { GetSiteInfoOperation } from '../types/site'
|
||||||
import type { GetCustomerWishlistOperation } from '../types/wishlist'
|
import type { GetCustomerWishlistOperation } from '../types/wishlist'
|
||||||
import type {
|
import type {
|
||||||
@@ -11,8 +12,13 @@ import type {
|
|||||||
} from '../types/product'
|
} from '../types/product'
|
||||||
import type {
|
import type {
|
||||||
GetAllBlogsOperation,
|
GetAllBlogsOperation,
|
||||||
GetFeaturedBlogsOperation
|
GetFeaturedBlogsOperation,
|
||||||
|
GetAllBlogPathsOperation,
|
||||||
|
GetBlogDetailOperation,
|
||||||
|
GetRelevantBlogsOperation
|
||||||
} from '../types/blogs'
|
} from '../types/blogs'
|
||||||
|
|
||||||
|
|
||||||
import type { APIProvider, CommerceAPI } from '.'
|
import type { APIProvider, CommerceAPI } from '.'
|
||||||
import { GetAllCollectionsOperation } from '@commerce/types/collection';
|
import { GetAllCollectionsOperation } from '@commerce/types/collection';
|
||||||
|
|
||||||
@@ -32,7 +38,13 @@ export const OPERATIONS = [
|
|||||||
'getAllFacets',
|
'getAllFacets',
|
||||||
'getAllCollections',
|
'getAllCollections',
|
||||||
'getAllBlogs',
|
'getAllBlogs',
|
||||||
'getFeaturedBlog'
|
'getFeaturedBlog',
|
||||||
|
'getAllBlogPaths',
|
||||||
|
'getBlogDetail',
|
||||||
|
'getRelevantBlogs',
|
||||||
|
'getAllRecipes',
|
||||||
|
'getAllRecipePaths',
|
||||||
|
'getRecipeDetail'
|
||||||
] as const
|
] as const
|
||||||
|
|
||||||
export const defaultOperations = OPERATIONS.reduce((ops, k) => {
|
export const defaultOperations = OPERATIONS.reduce((ops, k) => {
|
||||||
@@ -73,14 +85,14 @@ export type Operations<P extends APIProvider> = {
|
|||||||
): Promise<T['data']>
|
): Promise<T['data']>
|
||||||
}
|
}
|
||||||
|
|
||||||
getPage: {
|
getRecipeDetail: {
|
||||||
<T extends GetPageOperation>(opts: {
|
<T extends GetRecipeDetailOperation>(opts: {
|
||||||
variables: T['variables']
|
variables: T['variables']
|
||||||
config?: P['config']
|
config?: P['config']
|
||||||
preview?: boolean
|
preview?: boolean
|
||||||
}): Promise<T['data']>
|
}): Promise<T['data']>
|
||||||
|
|
||||||
<T extends GetPageOperation>(
|
<T extends GetRecipeDetailOperation>(
|
||||||
opts: {
|
opts: {
|
||||||
variables: T['variables']
|
variables: T['variables']
|
||||||
config?: P['config']
|
config?: P['config']
|
||||||
@@ -133,6 +145,50 @@ export type Operations<P extends APIProvider> = {
|
|||||||
): Promise<T['data']>
|
): Promise<T['data']>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
getAllBlogPaths: {
|
||||||
|
<T extends GetAllBlogPathsOperation>(opts: {
|
||||||
|
variables?: T['variables']
|
||||||
|
config?: P['config']
|
||||||
|
}): Promise<T['data']>
|
||||||
|
|
||||||
|
<T extends GetAllBlogPathsOperation>(
|
||||||
|
opts: {
|
||||||
|
variables?: T['variables']
|
||||||
|
config?: P['config']
|
||||||
|
} & OperationOptions
|
||||||
|
): Promise<T['data']>
|
||||||
|
}
|
||||||
|
|
||||||
|
getAllRecipePaths: {
|
||||||
|
<T extends GetAllRecipePathsOperation>(opts: {
|
||||||
|
variables?: T['variables']
|
||||||
|
config?: P['config']
|
||||||
|
}): Promise<T['data']>
|
||||||
|
|
||||||
|
<T extends GetAllRecipePathsOperation>(
|
||||||
|
opts: {
|
||||||
|
variables?: T['variables']
|
||||||
|
config?: P['config']
|
||||||
|
} & OperationOptions
|
||||||
|
): Promise<T['data']>
|
||||||
|
}
|
||||||
|
|
||||||
|
getAllRecipe: {
|
||||||
|
<T extends GetAllRecipePathsOperation>(opts: {
|
||||||
|
variables?: T['variables']
|
||||||
|
config?: P['config']
|
||||||
|
}): Promise<T['data']>
|
||||||
|
|
||||||
|
<T extends GetAllRecipePathsOperation>(
|
||||||
|
opts: {
|
||||||
|
variables?: T['variables']
|
||||||
|
config?: P['config']
|
||||||
|
} & OperationOptions
|
||||||
|
): Promise<T['data']>
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
getAllProducts: {
|
getAllProducts: {
|
||||||
<T extends GetAllProductsOperation>(opts: {
|
<T extends GetAllProductsOperation>(opts: {
|
||||||
variables?: T['variables']
|
variables?: T['variables']
|
||||||
@@ -166,6 +222,38 @@ export type Operations<P extends APIProvider> = {
|
|||||||
): Promise<T['data']>
|
): Promise<T['data']>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getAllRecipes: {
|
||||||
|
<T extends GetAllRecipesOperation>(opts: {
|
||||||
|
variables?: T['variables']
|
||||||
|
config?: P['config']
|
||||||
|
preview?: boolean
|
||||||
|
}): Promise<T['data']>
|
||||||
|
|
||||||
|
<T extends GetAllRecipesOperation>(
|
||||||
|
opts: {
|
||||||
|
variables?: T['variables']
|
||||||
|
config?: P['config']
|
||||||
|
preview?: boolean
|
||||||
|
} & OperationOptions
|
||||||
|
): Promise<T['data']>
|
||||||
|
}
|
||||||
|
|
||||||
|
getRelevantBlogs: {
|
||||||
|
<T extends GetRelevantBlogsOperation>(opts: {
|
||||||
|
variables?: T['variables']
|
||||||
|
config?: P['config']
|
||||||
|
preview?: boolean
|
||||||
|
}): Promise<T['data']>
|
||||||
|
|
||||||
|
<T extends GetRelevantBlogsOperation>(
|
||||||
|
opts: {
|
||||||
|
variables?: T['variables']
|
||||||
|
config?: P['config']
|
||||||
|
preview?: boolean
|
||||||
|
} & OperationOptions
|
||||||
|
): Promise<T['data']>
|
||||||
|
}
|
||||||
|
|
||||||
getFeaturedBlog: {
|
getFeaturedBlog: {
|
||||||
<T extends GetFeaturedBlogsOperation>(opts: {
|
<T extends GetFeaturedBlogsOperation>(opts: {
|
||||||
variables?: T['variables']
|
variables?: T['variables']
|
||||||
@@ -182,6 +270,21 @@ export type Operations<P extends APIProvider> = {
|
|||||||
): Promise<T['data']>
|
): Promise<T['data']>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getBlogDetail: {
|
||||||
|
<T extends GetBlogDetailOperation>(opts: {
|
||||||
|
variables?: T['variables']
|
||||||
|
config?: P['config']
|
||||||
|
preview?: boolean
|
||||||
|
}): Promise<T['data']>
|
||||||
|
|
||||||
|
<T extends GetBlogDetailOperation>(
|
||||||
|
opts: {
|
||||||
|
variables?: T['variables']
|
||||||
|
config?: P['config']
|
||||||
|
preview?: boolean
|
||||||
|
} & OperationOptions
|
||||||
|
): Promise<T['data']>
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
getProduct: {
|
getProduct: {
|
||||||
|
@@ -14,13 +14,27 @@ export type BlogsType = {
|
|||||||
totalItems: number
|
totalItems: number
|
||||||
}
|
}
|
||||||
export type GetAllBlogsOperation<T extends BlogsType = BlogsType> = {
|
export type GetAllBlogsOperation<T extends BlogsType = BlogsType> = {
|
||||||
data: { items: T['items'][] }
|
data: { items: T['items'][], totalItems: number }
|
||||||
|
variables: {
|
||||||
|
productId: number,
|
||||||
|
take?: number
|
||||||
|
skip?: number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export type GetRelevantBlogsOperation<T extends BlogsType = BlogsType> = {
|
||||||
|
data: { items: T['items'][], totalItems: number }
|
||||||
variables: {
|
variables: {
|
||||||
take?: number
|
take?: number
|
||||||
skip?: number
|
skip?: number
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type GetBlogDetailOperation<T extends BlogsType = BlogsType> = {
|
||||||
|
data: T['items'],
|
||||||
|
variables: {
|
||||||
|
slug?: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export type GetFeaturedBlogsOperation<T extends BlogsType = BlogsType> = {
|
export type GetFeaturedBlogsOperation<T extends BlogsType = BlogsType> = {
|
||||||
data: { items: T['items'][] }
|
data: { items: T['items'][] }
|
||||||
@@ -28,4 +42,10 @@ export type GetFeaturedBlogsOperation<T extends BlogsType = BlogsType> = {
|
|||||||
take?: number
|
take?: number
|
||||||
skip?: number
|
skip?: number
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
export type GetAllBlogPathsOperation<
|
||||||
|
T extends BlogsType = BlogsType
|
||||||
|
> = {
|
||||||
|
data: { blogs: Pick<T['items'], 'translations'>[] }
|
||||||
|
variables: { first?: number }
|
||||||
|
}
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
import { BlogsType } from './blogs';
|
||||||
import { CurrencyCode } from './../../vendure/schema.d';
|
import { CurrencyCode } from './../../vendure/schema.d';
|
||||||
import { FacetValueFilterInput, LogicalOperator, SearchResultSortParameter } from "@framework/schema"
|
import { FacetValueFilterInput, LogicalOperator, SearchResultSortParameter } from "@framework/schema"
|
||||||
|
|
||||||
@@ -110,6 +111,8 @@ export type GetAllProductPathsOperation<
|
|||||||
variables: { first?: number }
|
variables: { first?: number }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export type GetAllProductsOperation<T extends ProductTypes = ProductTypes> = {
|
export type GetAllProductsOperation<T extends ProductTypes = ProductTypes> = {
|
||||||
data: { products: T['product'][] }
|
data: { products: T['product'][] }
|
||||||
variables: {
|
variables: {
|
||||||
|
45
framework/commerce/types/recipes.ts
Normal file
45
framework/commerce/types/recipes.ts
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
import { Asset, BlogTranslation, Maybe, Product } from './../../vendure/schema.d';
|
||||||
|
|
||||||
|
export type RecipeList = Node &{
|
||||||
|
id: string
|
||||||
|
featuredAsset?: Maybe<Asset>
|
||||||
|
isPublish:Boolean
|
||||||
|
translations: Array<BlogTranslation>
|
||||||
|
authorName: string
|
||||||
|
authorAvatarAsset:Array<Asset>
|
||||||
|
relevantProducts: Product
|
||||||
|
link:String
|
||||||
|
minutes:Number
|
||||||
|
people:Number
|
||||||
|
}
|
||||||
|
export type RecipesType = {
|
||||||
|
items: RecipeList
|
||||||
|
totalItems: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum SortRecipes {
|
||||||
|
ASC = 'ASC',
|
||||||
|
DESC = 'DESC',
|
||||||
|
}
|
||||||
|
|
||||||
|
export type GetAllRecipesOperation<T extends RecipesType = RecipesType> = {
|
||||||
|
data: { items: T['items'][], totalItems: number }
|
||||||
|
variables: {
|
||||||
|
excludeBlogIds:Array<Number>,
|
||||||
|
take?: number
|
||||||
|
id?: SortRecipes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export type GetAllRecipePathsOperation<
|
||||||
|
T extends RecipesType = RecipesType
|
||||||
|
> = {
|
||||||
|
data: { recipes: Pick<T['items'], 'translations'>[] }
|
||||||
|
variables: { first?: number }
|
||||||
|
}
|
||||||
|
|
||||||
|
export type GetRecipeDetailOperation<T extends RecipesType = RecipesType> = {
|
||||||
|
data: T['items'],
|
||||||
|
variables: {
|
||||||
|
slug?: string
|
||||||
|
}
|
||||||
|
}
|
@@ -1,18 +1,25 @@
|
|||||||
import type { CommerceAPIConfig } from '@commerce/api'
|
import type { CommerceAPIConfig } from '@commerce/api'
|
||||||
import { CommerceAPI, getCommerceApi as commerceApi } from '@commerce/api'
|
import { CommerceAPI, getCommerceApi as commerceApi } from '@commerce/api'
|
||||||
import getAllFacets from './operations/get-all-facets'
|
import getAllBlogs from './operations/get-all-blogs'
|
||||||
import getAllCollections from './operations/get-all-collection'
|
import getAllCollections from './operations/get-all-collection'
|
||||||
|
import getAllFacets from './operations/get-all-facets'
|
||||||
import getAllPages from './operations/get-all-pages'
|
import getAllPages from './operations/get-all-pages'
|
||||||
import getAllProductPaths from './operations/get-all-product-paths'
|
import getAllProductPaths from './operations/get-all-product-paths'
|
||||||
import getAllProducts from './operations/get-all-products'
|
import getAllProducts from './operations/get-all-products'
|
||||||
|
import getBlogDetail from './operations/get-blog-detail'
|
||||||
import getCustomerWishlist from './operations/get-customer-wishlist'
|
import getCustomerWishlist from './operations/get-customer-wishlist'
|
||||||
|
import getFeaturedBlog from './operations/get-featured-blog'
|
||||||
import getPage from './operations/get-page'
|
import getPage from './operations/get-page'
|
||||||
import getProduct from './operations/get-product'
|
import getProduct from './operations/get-product'
|
||||||
import getSiteInfo from './operations/get-site-info'
|
import getSiteInfo from './operations/get-site-info'
|
||||||
|
import getAllBlogPaths from './operations/get-all-blog-paths'
|
||||||
|
import getRelevantBlogs from './operations/get-relevant-blogs'
|
||||||
|
import getAllRecipes from './operations/get-all-recipes'
|
||||||
|
import getAllRecipePaths from './operations/get-all-recipe-paths'
|
||||||
|
import getRecipeDetail from './operations/get-recipe-detail'
|
||||||
|
|
||||||
import login from './operations/login'
|
import login from './operations/login'
|
||||||
import fetchGraphqlApi from './utils/fetch-graphql-api'
|
import fetchGraphqlApi from './utils/fetch-graphql-api'
|
||||||
import getAllBlogs from './operations/get-all-blogs'
|
|
||||||
import getFeaturedBlog from './operations/get-featured-blog'
|
|
||||||
|
|
||||||
export interface VendureConfig extends CommerceAPIConfig {}
|
export interface VendureConfig extends CommerceAPIConfig {}
|
||||||
|
|
||||||
@@ -46,7 +53,13 @@ const operations = {
|
|||||||
getAllFacets,
|
getAllFacets,
|
||||||
getAllCollections,
|
getAllCollections,
|
||||||
getAllBlogs,
|
getAllBlogs,
|
||||||
getFeaturedBlog
|
getFeaturedBlog,
|
||||||
|
getBlogDetail,
|
||||||
|
getAllBlogPaths,
|
||||||
|
getRelevantBlogs,
|
||||||
|
getAllRecipes,
|
||||||
|
getAllRecipePaths,
|
||||||
|
getRecipeDetail
|
||||||
}
|
}
|
||||||
|
|
||||||
export const provider = { config, operations }
|
export const provider = { config, operations }
|
||||||
|
53
framework/vendure/api/operations/get-all-blog-paths.ts
Normal file
53
framework/vendure/api/operations/get-all-blog-paths.ts
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
import { BlogList } from './../../schema.d';
|
||||||
|
import { OperationContext,OperationOptions } from '@commerce/api/operations';
|
||||||
|
import { BigcommerceConfig } from '../../../bigcommerce/api';
|
||||||
|
import type { GetAllBlogPathsQuery,BlogTranslation } from '../../schema';
|
||||||
|
import { getAllBlogPathsQuery } from '../../utils/queries/get-all-blog-paths-query';
|
||||||
|
import { Provider } from '../index';
|
||||||
|
import { GetAllBlogPathsOperation } from './../../../commerce/types/blogs';
|
||||||
|
|
||||||
|
export type GetAllBlogPathsResult = {
|
||||||
|
blogs: Array<{ node: { path: string } }>
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function getAllBlogPathsOperation({
|
||||||
|
commerce,
|
||||||
|
}: OperationContext<Provider>) {
|
||||||
|
async function getAllBlogPaths<
|
||||||
|
T extends GetAllBlogPathsOperation
|
||||||
|
>(opts?: {
|
||||||
|
variables?: T['variables']
|
||||||
|
config?: BigcommerceConfig
|
||||||
|
}): Promise<T['data']>
|
||||||
|
|
||||||
|
async function getAllBlogPaths<T extends GetAllBlogPathsOperation>(
|
||||||
|
opts: {
|
||||||
|
variables?: T['variables']
|
||||||
|
config?: BigcommerceConfig
|
||||||
|
} & OperationOptions
|
||||||
|
): Promise<T['data']>
|
||||||
|
|
||||||
|
async function getAllBlogPaths<T extends GetAllBlogPathsOperation>({
|
||||||
|
query = getAllBlogPathsQuery,
|
||||||
|
variables,
|
||||||
|
config: cfg,
|
||||||
|
}: {
|
||||||
|
query?: string
|
||||||
|
variables?: T['variables']
|
||||||
|
config?: BigcommerceConfig
|
||||||
|
} = {}): Promise<T['data']> {
|
||||||
|
const config = commerce.getConfig(cfg)
|
||||||
|
|
||||||
|
const { data } = await config.fetch<GetAllBlogPathsQuery>(query, {
|
||||||
|
variables,
|
||||||
|
})
|
||||||
|
|
||||||
|
const blogs = data.blogs.items;
|
||||||
|
|
||||||
|
return {
|
||||||
|
blogs: blogs?.map(val=>val.translations.map((p:BlogTranslation) => ({ path: `/${p.slug}` })))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return getAllBlogPaths
|
||||||
|
}
|
@@ -6,7 +6,12 @@ import { getAllBlogsQuery } from '../../utils/queries/get-all-blog-query'
|
|||||||
export type BlogVariables = {
|
export type BlogVariables = {
|
||||||
excludeBlogIds?: string[],
|
excludeBlogIds?: string[],
|
||||||
take?: number,
|
take?: number,
|
||||||
skip?:number
|
skip?:number,
|
||||||
|
filter?:{
|
||||||
|
isFeatured?:{
|
||||||
|
eq?:Boolean
|
||||||
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function getAllBlogsOperation({
|
export default function getAllBlogsOperation({
|
||||||
@@ -34,7 +39,9 @@ export default function getAllBlogsOperation({
|
|||||||
excludeBlogIds: vars.excludeBlogIds,
|
excludeBlogIds: vars.excludeBlogIds,
|
||||||
options: {
|
options: {
|
||||||
take: vars.take,
|
take: vars.take,
|
||||||
skip: vars.skip,
|
filter: {
|
||||||
|
isFeatured: vars.filter?.isFeatured
|
||||||
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
const { data } = await config.fetch<GetAllBlogsQuery>(query, {
|
const { data } = await config.fetch<GetAllBlogsQuery>(query, {
|
||||||
@@ -51,7 +58,7 @@ export default function getAllBlogsOperation({
|
|||||||
isPublish: val.isPublish,
|
isPublish: val.isPublish,
|
||||||
isFeatured: val.isFeatured,
|
isFeatured: val.isFeatured,
|
||||||
authorName: val.authorName,
|
authorName: val.authorName,
|
||||||
authorAvatarAsset : val.authorAvatarAsset?.preview,
|
authorAvatarAsset : val.authorAvatarAsset?.preview ?? null,
|
||||||
createdAt: val.createdAt
|
createdAt: val.createdAt
|
||||||
})),
|
})),
|
||||||
totalItems: data?.blogs?.totalItems || null
|
totalItems: data?.blogs?.totalItems || null
|
||||||
|
53
framework/vendure/api/operations/get-all-recipe-paths.ts
Normal file
53
framework/vendure/api/operations/get-all-recipe-paths.ts
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
import { BlogList } from '../../schema';
|
||||||
|
import { OperationContext,OperationOptions } from '@commerce/api/operations';
|
||||||
|
import { BigcommerceConfig } from '../../../bigcommerce/api';
|
||||||
|
import type { GetAllRecipePathsQuery,RecipeTranslation } from '../../schema';
|
||||||
|
import { getAllBlogPathsQuery } from '../../utils/queries/get-all-blog-paths-query';
|
||||||
|
import { Provider } from '../index';
|
||||||
|
import { GetAllRecipesPathsOperation } from '../../../commerce/types/recipes';
|
||||||
|
|
||||||
|
export type GetAllBlogPathsResult = {
|
||||||
|
blogs: Array<{ node: { path: string } }>
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function getAllRecipePathsOperation({
|
||||||
|
commerce,
|
||||||
|
}: OperationContext<Provider>) {
|
||||||
|
async function getAllRecipePaths<
|
||||||
|
T extends GetAllRecipesPathsOperation
|
||||||
|
>(opts?: {
|
||||||
|
variables?: T['variables']
|
||||||
|
config?: BigcommerceConfig
|
||||||
|
}): Promise<T['data']>
|
||||||
|
|
||||||
|
async function getAllRecipePaths<T extends GetAllRecipesPathsOperation>(
|
||||||
|
opts: {
|
||||||
|
variables?: T['variables']
|
||||||
|
config?: BigcommerceConfig
|
||||||
|
} & OperationOptions
|
||||||
|
): Promise<T['data']>
|
||||||
|
|
||||||
|
async function getAllRecipePaths<T extends GetAllRecipesPathsOperation>({
|
||||||
|
query = getAllBlogPathsQuery,
|
||||||
|
variables,
|
||||||
|
config: cfg,
|
||||||
|
}: {
|
||||||
|
query?: string
|
||||||
|
variables?: T['variables']
|
||||||
|
config?: BigcommerceConfig
|
||||||
|
} = {}): Promise<T['data']> {
|
||||||
|
const config = commerce.getConfig(cfg)
|
||||||
|
|
||||||
|
const { data } = await config.fetch<GetAllRecipePathsQuery>(query, {
|
||||||
|
variables,
|
||||||
|
})
|
||||||
|
|
||||||
|
const recipes = data.blogs.items;
|
||||||
|
|
||||||
|
return {
|
||||||
|
recipes: recipes?.map(val=>val.translations.map((p:RecipeTranslation) => ({ path: `/${p.slug}` })))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return getAllRecipePaths
|
||||||
|
}
|
70
framework/vendure/api/operations/get-all-recipes.ts
Normal file
70
framework/vendure/api/operations/get-all-recipes.ts
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
import { OperationContext } from '@commerce/api/operations'
|
||||||
|
import { Provider, VendureConfig } from '..'
|
||||||
|
import { BlogList, GetAllRecipesQuery } from '../../schema'
|
||||||
|
import { getAllBlogsQuery } from '../../utils/queries/get-all-blog-query'
|
||||||
|
|
||||||
|
export type RecipesVariables = {
|
||||||
|
excludeBlogIds?: string[],
|
||||||
|
take?:number,
|
||||||
|
id?: string,
|
||||||
|
isPublish?:Boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function getAllRecipesOperation({
|
||||||
|
commerce,
|
||||||
|
}: OperationContext<Provider>) {
|
||||||
|
async function getAllRecipes(opts?: {
|
||||||
|
variables?: RecipesVariables
|
||||||
|
config?: Partial<VendureConfig>
|
||||||
|
preview?: boolean
|
||||||
|
}): Promise<{ recipes: GetAllRecipesQuery[],totalItems:number }>
|
||||||
|
|
||||||
|
async function getAllRecipes({
|
||||||
|
query = getAllBlogsQuery,
|
||||||
|
variables: { ...vars } = {},
|
||||||
|
config: cfg,
|
||||||
|
}: {
|
||||||
|
query?: string
|
||||||
|
variables?: RecipesVariables
|
||||||
|
config?: Partial<VendureConfig>
|
||||||
|
preview?: boolean
|
||||||
|
} = {}): Promise<{ recipes: GetAllRecipesQuery[] | any[] ,totalItems?:number }> {
|
||||||
|
|
||||||
|
const config = commerce.getConfig(cfg)
|
||||||
|
const variables = {
|
||||||
|
excludeBlogIds: vars.excludeBlogIds,
|
||||||
|
options: {
|
||||||
|
take: vars.take,
|
||||||
|
sort: {
|
||||||
|
id: vars?.id
|
||||||
|
},
|
||||||
|
filter:{
|
||||||
|
isPublish: {
|
||||||
|
eq:vars.isPublish
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const { data } = await config.fetch<GetAllRecipesQuery>(query, {
|
||||||
|
variables,
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
recipes: data?.blogs?.items?.map((val:BlogList)=>({
|
||||||
|
id: val.id,
|
||||||
|
title: val.translations[0]?.title,
|
||||||
|
imageSrc: val.featuredAsset?.preview ?? null,
|
||||||
|
slug: val.translations[0]?.slug,
|
||||||
|
description: val.translations[0]?.description,
|
||||||
|
isPublish: val.isPublish,
|
||||||
|
authorName: val.authorName,
|
||||||
|
authorAvatarAsset : val.authorAvatarAsset?.preview ?? null,
|
||||||
|
createdAt: val.createdAt
|
||||||
|
})),
|
||||||
|
totalItems: data?.blogs?.totalItems || null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return getAllRecipes
|
||||||
|
}
|
55
framework/vendure/api/operations/get-blog-detail.ts
Normal file
55
framework/vendure/api/operations/get-blog-detail.ts
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
import { OperationContext } from '@commerce/api/operations'
|
||||||
|
import { Provider, VendureConfig } from '..'
|
||||||
|
import { GetBlogQuery,BlogList } from '../../schema'
|
||||||
|
import { getBlogDetailQuery } from '../../utils/queries/get-blog-detail'
|
||||||
|
|
||||||
|
export type BlogVariables = {
|
||||||
|
slug?: string,
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function getBlogDetailOperation({
|
||||||
|
commerce,
|
||||||
|
}: OperationContext<Provider>) {
|
||||||
|
async function getBlogDetail(opts?: {
|
||||||
|
variables?: BlogVariables
|
||||||
|
config?: Partial<VendureConfig>
|
||||||
|
preview?: boolean
|
||||||
|
}): Promise<{ blogDetail: BlogList}>
|
||||||
|
|
||||||
|
async function getBlogDetail({
|
||||||
|
query = getBlogDetailQuery,
|
||||||
|
variables: { ...vars } = {},
|
||||||
|
config: cfg,
|
||||||
|
}: {
|
||||||
|
query?: string
|
||||||
|
variables?: BlogVariables
|
||||||
|
config?: Partial<VendureConfig>
|
||||||
|
preview?: boolean
|
||||||
|
} = {}): Promise<{ blogDetail: BlogList | any }> {
|
||||||
|
|
||||||
|
const config = commerce.getConfig(cfg)
|
||||||
|
const variables = {
|
||||||
|
slug: vars.slug
|
||||||
|
}
|
||||||
|
const { data } = await config.fetch<GetBlogQuery>(query, {
|
||||||
|
variables,
|
||||||
|
})
|
||||||
|
return {
|
||||||
|
blogDetail: {
|
||||||
|
id:data?.blog?.id,
|
||||||
|
title: data?.blog?.translations[0].title,
|
||||||
|
imageSrc: data?.blog?.featuredAsset?.preview ?? null,
|
||||||
|
slug: data?.blog?.translations[0]?.slug,
|
||||||
|
description: data?.blog?.translations[0]?.description,
|
||||||
|
isPublish: data?.blog?.isPublish,
|
||||||
|
isFeatured: data?.blog?.isFeatured,
|
||||||
|
authorName: data?.blog?.authorName,
|
||||||
|
authorAvatarAsset : data?.blog?.authorAvatarAsset?.preview,
|
||||||
|
createdAt: data?.blog?.createdAt,
|
||||||
|
relevantProducts: data?.blog?.relevantProducts.map(val=>val.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return getBlogDetail
|
||||||
|
}
|
@@ -5,7 +5,12 @@ import { getFeatuedBlogsQuery } from '../../utils/queries/get-featued-query'
|
|||||||
|
|
||||||
export type BlogVariables = {
|
export type BlogVariables = {
|
||||||
take?: number,
|
take?: number,
|
||||||
skip?:number
|
skip?:number,
|
||||||
|
filter?:{
|
||||||
|
isFeatured?:{
|
||||||
|
eq?:Boolean
|
||||||
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function getFeaturedBlogOperation({
|
export default function getFeaturedBlogOperation({
|
||||||
@@ -31,6 +36,9 @@ export default function getFeaturedBlogOperation({
|
|||||||
const variables = {
|
const variables = {
|
||||||
options: {
|
options: {
|
||||||
take: vars.take,
|
take: vars.take,
|
||||||
|
filter: {
|
||||||
|
isFeatured: vars.filter?.isFeatured
|
||||||
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
const { data } = await config.fetch<GetFeaturedBlogQuery>(query, {
|
const { data } = await config.fetch<GetFeaturedBlogQuery>(query, {
|
||||||
@@ -46,7 +54,7 @@ export default function getFeaturedBlogOperation({
|
|||||||
isPublish: val.isPublish,
|
isPublish: val.isPublish,
|
||||||
isFeatured: val.isFeatured,
|
isFeatured: val.isFeatured,
|
||||||
authorName: val.authorName,
|
authorName: val.authorName,
|
||||||
authorAvatarAsset : val.authorAvatarAsset?.preview,
|
authorAvatarAsset : val.authorAvatarAsset?.preview ?? null,
|
||||||
createdAt: val.createdAt
|
createdAt: val.createdAt
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
98
framework/vendure/api/operations/get-recipe-detail.ts
Normal file
98
framework/vendure/api/operations/get-recipe-detail.ts
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
import { OperationContext } from '@commerce/api/operations'
|
||||||
|
import { Provider, VendureConfig } from '..'
|
||||||
|
import { GetRecipeQuery, RecipeList } from '../../schema'
|
||||||
|
import { getBlogDetailQuery } from '../../utils/queries/get-blog-detail'
|
||||||
|
|
||||||
|
|
||||||
|
export default function getRecipeDetailOperation({
|
||||||
|
commerce,
|
||||||
|
}: OperationContext<Provider>) {
|
||||||
|
|
||||||
|
async function getRecipeDetail({
|
||||||
|
query = getBlogDetailQuery,
|
||||||
|
variables,
|
||||||
|
config: cfg,
|
||||||
|
}: {
|
||||||
|
query?: string
|
||||||
|
variables: { slug: string }
|
||||||
|
config?: Partial<VendureConfig>
|
||||||
|
preview?: boolean
|
||||||
|
}): Promise<{recipeDetail: RecipeList | any }> {
|
||||||
|
const config = commerce.getConfig(cfg)
|
||||||
|
const { data } = await config.fetch<GetRecipeQuery>(query, {
|
||||||
|
variables,
|
||||||
|
})
|
||||||
|
const recipes = data.blog
|
||||||
|
|
||||||
|
if (recipes) {
|
||||||
|
return {
|
||||||
|
recipeDetail: {
|
||||||
|
id: data?.blog?.id,
|
||||||
|
title: data?.blog?.translations[0].title,
|
||||||
|
imageSrc: data?.blog?.featuredAsset?.preview ?? null,
|
||||||
|
slug: data?.blog?.translations[0]?.slug,
|
||||||
|
description: data?.blog?.translations[0]?.description,
|
||||||
|
isPublish: data?.blog?.isPublish,
|
||||||
|
authorName: data?.blog?.authorName,
|
||||||
|
authorAvatarAsset : data?.blog?.authorAvatarAsset?.preview,
|
||||||
|
createdAt: data?.blog?.createdAt,
|
||||||
|
relevantProducts: data?.blog?.relevantProducts.map(val=>val.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
return {recipeDetail:null}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return getRecipeDetail
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// export type RecipeVariables = {
|
||||||
|
// slug?: string,
|
||||||
|
// }
|
||||||
|
|
||||||
|
// export default function getRecipeDetailOperation({
|
||||||
|
// commerce,
|
||||||
|
// }: OperationContext<Provider>) {
|
||||||
|
|
||||||
|
// async function getRecipeDetail(opts?: {
|
||||||
|
// variables?: RecipeVariables
|
||||||
|
// config?: Partial<VendureConfig>
|
||||||
|
// preview?: boolean
|
||||||
|
// }): Promise<{ recipeDetail: RecipeList}>
|
||||||
|
|
||||||
|
// async function getRecipeDetail({
|
||||||
|
// query = getBlogDetailQuery,
|
||||||
|
// variables: { ...vars } = {},
|
||||||
|
// config: cfg,
|
||||||
|
// }: {
|
||||||
|
// query?: string
|
||||||
|
// variables?: RecipeVariables
|
||||||
|
// config?: Partial<VendureConfig>
|
||||||
|
// preview?: boolean
|
||||||
|
// } = {}): Promise<{ recipeDetail: RecipeList | any }> {
|
||||||
|
|
||||||
|
// const config = commerce.getConfig(cfg)
|
||||||
|
// const variables = {
|
||||||
|
// slug: vars.slug
|
||||||
|
// }
|
||||||
|
// const { data } = await config.fetch<GetRecipeQuery>(query, {
|
||||||
|
// variables,
|
||||||
|
// })
|
||||||
|
// return {
|
||||||
|
// id: data?.blog?.id,
|
||||||
|
// title: data?.blog?.translations[0].title,
|
||||||
|
// imageSrc: data?.blog?.featuredAsset?.preview ?? null,
|
||||||
|
// slug: data?.blog?.translations[0]?.slug,
|
||||||
|
// description: data?.blog?.translations[0]?.description,
|
||||||
|
// isPublish: data?.blog?.isPublish,
|
||||||
|
// authorName: data?.blog?.authorName,
|
||||||
|
// authorAvatarAsset : data?.blog?.authorAvatarAsset?.preview,
|
||||||
|
// createdAt: data?.blog?.createdAt,
|
||||||
|
// relevantProducts: data?.blog?.relevantProducts.map(val=>val.id)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return getRecipeDetail
|
||||||
|
// }
|
54
framework/vendure/api/operations/get-relevant-blogs.ts
Normal file
54
framework/vendure/api/operations/get-relevant-blogs.ts
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
import { OperationContext } from '@commerce/api/operations'
|
||||||
|
import { Provider, VendureConfig } from '..'
|
||||||
|
import { BlogList,GetRelevantBlogsQuery } from '../../schema'
|
||||||
|
import { getRelevantBlogsQuery } from '../../utils/queries/get-relevant-blogs'
|
||||||
|
|
||||||
|
export type BlogVariables = {
|
||||||
|
productId?: number,
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function getRelevantBlogsOperation({
|
||||||
|
commerce,
|
||||||
|
}: OperationContext<Provider>) {
|
||||||
|
async function getRelevantBlogs(opts?: {
|
||||||
|
variables?: BlogVariables
|
||||||
|
config?: Partial<VendureConfig>
|
||||||
|
preview?: boolean
|
||||||
|
}): Promise<{ relevantBlogs: GetRelevantBlogsQuery[]}>
|
||||||
|
|
||||||
|
async function getRelevantBlogs({
|
||||||
|
query = getRelevantBlogsQuery,
|
||||||
|
variables: { ...vars } = {},
|
||||||
|
config: cfg,
|
||||||
|
}: {
|
||||||
|
query?: string
|
||||||
|
variables?: BlogVariables
|
||||||
|
config?: Partial<VendureConfig>
|
||||||
|
preview?: boolean
|
||||||
|
} = {}): Promise<{ relevantBlogs: GetRelevantBlogsQuery[] | any[] }> {
|
||||||
|
|
||||||
|
const config = commerce.getConfig(cfg)
|
||||||
|
const variables = {
|
||||||
|
productId: vars.productId,
|
||||||
|
}
|
||||||
|
const { data } = await config.fetch<GetRelevantBlogsQuery>(query, {
|
||||||
|
variables,
|
||||||
|
})
|
||||||
|
return {
|
||||||
|
relevantBlogs: data?.relevantBlogs?.items?.map((val:BlogList)=>({
|
||||||
|
id: val.id,
|
||||||
|
title: val.translations[0]?.title,
|
||||||
|
imageSrc: val.featuredAsset?.preview ?? null,
|
||||||
|
slug: val.translations[0]?.slug,
|
||||||
|
description: val.translations[0]?.description,
|
||||||
|
isPublish: val.isPublish,
|
||||||
|
isFeatured: val.isFeatured,
|
||||||
|
authorName: val.authorName,
|
||||||
|
authorAvatarAsset : val.authorAvatarAsset?.preview,
|
||||||
|
createdAt: val.createdAt
|
||||||
|
})),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return getRelevantBlogs
|
||||||
|
}
|
113
framework/vendure/schema.d.ts
vendored
113
framework/vendure/schema.d.ts
vendored
@@ -2388,10 +2388,66 @@ export type BlogList = Node &{
|
|||||||
translations: Array<BlogTranslation>
|
translations: Array<BlogTranslation>
|
||||||
authorName: Scalars['String']
|
authorName: Scalars['String']
|
||||||
authorAvatarAsset:Asset
|
authorAvatarAsset:Asset
|
||||||
relevantProducts: Product
|
relevantProducts: Product[]
|
||||||
isFeatured: Boolean
|
isFeatured: Boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type RecipeList = Node &{
|
||||||
|
id: ID!
|
||||||
|
createdAt: DateTime!
|
||||||
|
updatedAt: DateTime!
|
||||||
|
featuredAsset?: Maybe<Asset>
|
||||||
|
isPublish:Boolean
|
||||||
|
translations: Array<RecipeTranslation>
|
||||||
|
authorName: Scalars['String']
|
||||||
|
authorAvatarAsset:Asset
|
||||||
|
relevantProducts: Product[]
|
||||||
|
link:String
|
||||||
|
minutes:Number
|
||||||
|
people:Number
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum SortRecipes {
|
||||||
|
ASC = 'ASC',
|
||||||
|
DESC = 'DESC',
|
||||||
|
}
|
||||||
|
|
||||||
|
export type RecipeTranslation = {
|
||||||
|
__typename?: 'RecipeTranslation'
|
||||||
|
id: Scalars['ID']
|
||||||
|
createdAt: Scalars['DateTime']
|
||||||
|
updatedAt: Scalars['DateTime']
|
||||||
|
languageCode: LanguageCode
|
||||||
|
title: Scalars['String']
|
||||||
|
slug: Scalars['String']
|
||||||
|
description: Scalars['String']
|
||||||
|
content: Scalars['String']
|
||||||
|
Ingredients:Scalars['String']
|
||||||
|
Preparation:Scalars['String']
|
||||||
|
}
|
||||||
|
|
||||||
|
export type IngredientProducts = {
|
||||||
|
__typename?: 'IngredientProduct'
|
||||||
|
id: Scalars['ID']
|
||||||
|
createdAt: Scalars['DateTime']
|
||||||
|
updatedAt: Scalars['DateTime']
|
||||||
|
product: Product[]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export type GetBlogQuery = { __typename?: 'Query' } & {
|
||||||
|
blog?: Maybe<
|
||||||
|
{ __typename?: 'Blog' } & BlogList
|
||||||
|
>
|
||||||
|
}
|
||||||
|
|
||||||
|
export type GetRecipeQuery = { __typename?: 'Query' } & {
|
||||||
|
recipeDetail?: Maybe<
|
||||||
|
{ __typename?: 'Recipe' } & RecipeList
|
||||||
|
>
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export type BlogTranslation = {
|
export type BlogTranslation = {
|
||||||
__typename?: 'BlogTranslation'
|
__typename?: 'BlogTranslation'
|
||||||
id: Scalars['ID']
|
id: Scalars['ID']
|
||||||
@@ -2403,6 +2459,18 @@ export type BlogTranslation = {
|
|||||||
description: Scalars['String']
|
description: Scalars['String']
|
||||||
content: Scalars['String']
|
content: Scalars['String']
|
||||||
}
|
}
|
||||||
|
export type RecipeTranslation = {
|
||||||
|
__typename?: 'BlogTranslation'
|
||||||
|
id: Scalars['ID']
|
||||||
|
createdAt: Scalars['DateTime']
|
||||||
|
updatedAt: Scalars['DateTime']
|
||||||
|
languageCode: LanguageCode
|
||||||
|
title: Scalars['String']
|
||||||
|
slug: Scalars['String']
|
||||||
|
description: Scalars['String']
|
||||||
|
content: Scalars['String']
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export type GetAllBlogsQuery = PaginatedList & {
|
export type GetAllBlogsQuery = PaginatedList & {
|
||||||
blogs: { __typename?: 'BlogList' } & {
|
blogs: { __typename?: 'BlogList' } & {
|
||||||
@@ -2410,6 +2478,21 @@ export type GetAllBlogsQuery = PaginatedList & {
|
|||||||
'totalItems'
|
'totalItems'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type GetAllRecipesQuery = PaginatedList & {
|
||||||
|
recipes: { __typename?: 'RecipeList' } & {
|
||||||
|
items: Array<{ __typename?: 'Recipe' } & RecipeList!>,
|
||||||
|
'totalItems'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export type GetRelevantBlogsQuery = PaginatedList & {
|
||||||
|
relevantBlogs: { __typename?: 'BlogList' } & {
|
||||||
|
items: Array<{ __typename?: 'Blog' } & BlogList!>,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export type GetFeaturedBlogQuery = PaginatedList & {
|
export type GetFeaturedBlogQuery = PaginatedList & {
|
||||||
id:string,
|
id:string,
|
||||||
featuredBlogs: { __typename?: 'BlogList' } & {
|
featuredBlogs: { __typename?: 'BlogList' } & {
|
||||||
@@ -2418,11 +2501,26 @@ export type GetFeaturedBlogQuery = PaginatedList & {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export type QueryBlogs = {
|
export type QueryBlogs = {
|
||||||
excludeBlogIds:Array,
|
excludeBlogIds:Array,
|
||||||
options: BlogListOptions
|
options: BlogListOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type QueryRecipes = {
|
||||||
|
excludeBlogIds?:Maybe<Array>,
|
||||||
|
options: RecipeListOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
export type RecipeListOptions = {
|
||||||
|
skip?: Maybe<Scalars['Int']>
|
||||||
|
take?: Maybe<Scalars['Int']>
|
||||||
|
sort?: RecipesSort
|
||||||
|
}
|
||||||
|
export type RecipesSort = {
|
||||||
|
id?: Maybe<Scalars['String']>
|
||||||
|
}
|
||||||
|
|
||||||
export type BlogListOptions = {
|
export type BlogListOptions = {
|
||||||
skip?: Maybe<Scalars['Int']>
|
skip?: Maybe<Scalars['Int']>
|
||||||
take?: Maybe<Scalars['Int']>
|
take?: Maybe<Scalars['Int']>
|
||||||
@@ -3448,6 +3546,19 @@ export type GetAllProductPathsQuery = { __typename?: 'Query' } & {
|
|||||||
items: Array<{ __typename?: 'Product' } & Pick<Product, 'slug'>>
|
items: Array<{ __typename?: 'Product' } & Pick<Product, 'slug'>>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type GetAllBlogPathsQuery = { __typename?: 'Query' } & {
|
||||||
|
blogs: { __typename?: 'BlogList' } & {
|
||||||
|
items: Array<{ __typename?: 'Blog' } & Pick<BlogList,'slug','translations'>>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export type GetAllRecipePathsQuery = { __typename?: 'Query' } & {
|
||||||
|
recipes: { __typename?: 'Recipes' } & {
|
||||||
|
items: Array<{ __typename?: 'Recipe' } & Pick<RecipeList,'slug','translations'>>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export type GetAllProductsQueryVariables = Exact<{
|
export type GetAllProductsQueryVariables = Exact<{
|
||||||
input: SearchInput
|
input: SearchInput
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
import { Cart, CartCheckout } from '@commerce/types/cart'
|
import { Cart } from '@commerce/types/cart'
|
||||||
import { Product, ProductCard } from '@commerce/types/product'
|
import { ProductCard, Product } from '@commerce/types/product'
|
||||||
import { CartFragment, Favorite, SearchResultFragment, ShippingMethod, BlogList } from '../schema'
|
import { CartFragment, SearchResultFragment,Favorite, BlogList, RecipeList,ShippingMethod } from '../schema'
|
||||||
|
|
||||||
export function normalizeSearchResult(item: SearchResultFragment): ProductCard {
|
export function normalizeSearchResult(item: SearchResultFragment): ProductCard {
|
||||||
return {
|
return {
|
||||||
@@ -155,4 +155,18 @@ export function normalizeBlogList(blog: BlogList) {
|
|||||||
authorAvatarAsset : blog.authorAvatarAsset?.preview,
|
authorAvatarAsset : blog.authorAvatarAsset?.preview,
|
||||||
createdAt: blog.createdAt
|
createdAt: blog.createdAt
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function normalizeRecipeList(recipe: RecipeList) {
|
||||||
|
return {
|
||||||
|
id: recipe.id,
|
||||||
|
title: recipe.translations[0]?.title,
|
||||||
|
imageSrc: recipe.featuredAsset?.preview ?? null,
|
||||||
|
slug: recipe.translations[0]?.slug,
|
||||||
|
description: recipe.translations[0]?.description,
|
||||||
|
isPublish: recipe.isPublish,
|
||||||
|
authorName: recipe.authorName,
|
||||||
|
authorAvatarAsset : recipe.authorAvatarAsset?.preview,
|
||||||
|
createdAt: recipe.createdAt
|
||||||
|
}
|
||||||
}
|
}
|
11
framework/vendure/utils/queries/get-all-blog-paths-query.ts
Normal file
11
framework/vendure/utils/queries/get-all-blog-paths-query.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
export const getAllBlogPathsQuery = /* GraphQL */ `
|
||||||
|
query getAllBlogPaths($excludeBlogIds: [ID]! = [],$options:BlogListOptions){
|
||||||
|
blogs(excludeBlogIds: $excludeBlogIds,options: $options){
|
||||||
|
items{
|
||||||
|
translations {
|
||||||
|
slug
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
26
framework/vendure/utils/queries/get-blog-detail.ts
Normal file
26
framework/vendure/utils/queries/get-blog-detail.ts
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
export const getBlogDetailQuery = /* GraphQL */ `
|
||||||
|
query getBlog($slug: String ){
|
||||||
|
blog(slug: $slug){
|
||||||
|
id
|
||||||
|
isPublish
|
||||||
|
isFeatured
|
||||||
|
authorName
|
||||||
|
createdAt
|
||||||
|
authorAvatarAsset{
|
||||||
|
preview
|
||||||
|
}
|
||||||
|
featuredAsset {
|
||||||
|
preview
|
||||||
|
}
|
||||||
|
translations {
|
||||||
|
title
|
||||||
|
slug
|
||||||
|
description
|
||||||
|
content
|
||||||
|
}
|
||||||
|
relevantProducts{
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
25
framework/vendure/utils/queries/get-relevant-blogs.ts
Normal file
25
framework/vendure/utils/queries/get-relevant-blogs.ts
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
export const getRelevantBlogsQuery = /* GraphQL */ `
|
||||||
|
query relevantBlogs($productId: ID!){
|
||||||
|
relevantBlogs(productId:$productId){
|
||||||
|
items {
|
||||||
|
id
|
||||||
|
isPublish
|
||||||
|
isFeatured
|
||||||
|
authorName
|
||||||
|
createdAt
|
||||||
|
authorAvatarAsset{
|
||||||
|
preview
|
||||||
|
}
|
||||||
|
featuredAsset {
|
||||||
|
preview
|
||||||
|
}
|
||||||
|
translations {
|
||||||
|
title
|
||||||
|
slug
|
||||||
|
description
|
||||||
|
content
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
@@ -2,16 +2,111 @@ import { Layout, RelevantBlogPosts } from 'src/components/common';
|
|||||||
import BlogContent from 'src/components/modules/blog-detail/BlogContent/BlogContent';
|
import BlogContent from 'src/components/modules/blog-detail/BlogContent/BlogContent';
|
||||||
import BlogDetailImg from 'src/components/modules/blog-detail/BlogDetailImg/BlogDetailImg';
|
import BlogDetailImg from 'src/components/modules/blog-detail/BlogDetailImg/BlogDetailImg';
|
||||||
import { BLOGS_DATA_TEST } from 'src/utils/demo-data'
|
import { BLOGS_DATA_TEST } from 'src/utils/demo-data'
|
||||||
|
import { GetStaticPropsContext,GetStaticPathsContext } from 'next';
|
||||||
|
import { PromiseWithKey } from 'src/utils/types.utils';
|
||||||
|
import { getAllPromies } from 'src/utils/funtion.utils';
|
||||||
|
import commerce from '@lib/api/commerce';
|
||||||
|
import { BlogCardProps } from 'src/components/common/CardBlog/CardBlog';
|
||||||
|
import { REVALIDATE_TIME } from 'src/utils/constanst.utils'
|
||||||
|
interface Props {
|
||||||
|
blog:{blogDetail?: BlogCardProps},
|
||||||
|
relevant:{relevantBlogs?:BlogCardProps[]}
|
||||||
|
}
|
||||||
|
export default function BlogDetailPage({blog,relevant}:Props) {
|
||||||
|
|
||||||
|
let date = new Date(blog?.blogDetail?.createdAt ?? '' );
|
||||||
export default function BlogDetailPage() {
|
let fullDate = date.toLocaleString('en-us', { month: 'long' }) + " " + date.getDate()+","+date.getFullYear();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<BlogDetailImg/>
|
<BlogDetailImg imgSrc={blog?.blogDetail?.imageSrc ?? ''} />
|
||||||
<BlogContent/>
|
<BlogContent
|
||||||
<RelevantBlogPosts data={BLOGS_DATA_TEST} title="You will like also" bgcolor="cream"/>
|
title={blog?.blogDetail?.title}
|
||||||
|
content={blog?.blogDetail?.description}
|
||||||
|
imgAuthor={blog?.blogDetail?.authorAvatarAsset}
|
||||||
|
authorName={blog?.blogDetail?.authorName}
|
||||||
|
date={fullDate}
|
||||||
|
/>
|
||||||
|
{relevant.relevantBlogs?.length> 0 && <RelevantBlogPosts data={relevant.relevantBlogs} title="You will like also" bgcolor="cream"/>}
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export async function getStaticProps({
|
||||||
|
params,
|
||||||
|
locale,
|
||||||
|
locales,
|
||||||
|
preview,
|
||||||
|
}: GetStaticPropsContext<{ slug: string }> ) {
|
||||||
|
const config = { locale, locales }
|
||||||
|
let promisesWithKey = [] as PromiseWithKey[]
|
||||||
|
let props = {} as any
|
||||||
|
|
||||||
|
// Blog detail
|
||||||
|
const blogDetailPromise = await commerce.getBlogDetail({
|
||||||
|
variables: { slug: params!.slug },
|
||||||
|
config,
|
||||||
|
preview,
|
||||||
|
})
|
||||||
|
props.blog = blogDetailPromise;
|
||||||
|
|
||||||
|
if (!blogDetailPromise) {
|
||||||
|
throw new Error(`Blog with slug '${params!.slug}' not found`)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Relevant Blogs
|
||||||
|
const relevantProductId = blogDetailPromise.blogDetail.relevantProducts?.[0];
|
||||||
|
if (relevantProductId && blogDetailPromise.blogDetail.relevantProducts.length > 0) {
|
||||||
|
|
||||||
|
const relevantBlogs = commerce.getRelevantBlogs({
|
||||||
|
variables: { productId: relevantProductId },
|
||||||
|
config,
|
||||||
|
preview,
|
||||||
|
})
|
||||||
|
promisesWithKey.push({ key: 'relevant', promise: relevantBlogs})
|
||||||
|
|
||||||
|
}else {
|
||||||
|
props.relevantBlogs = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
const promises = getAllPromies(promisesWithKey)
|
||||||
|
const rs = await Promise.all(promises)
|
||||||
|
|
||||||
|
promisesWithKey.map((item, index) => {
|
||||||
|
props[item.key] = item.keyResult ? rs[index][item.keyResult] : rs[index]
|
||||||
|
return null
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log(props.relevantBlogs);
|
||||||
|
return {
|
||||||
|
props,
|
||||||
|
revalidate: REVALIDATE_TIME,
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getStaticPaths({ locales }: GetStaticPathsContext) {
|
||||||
|
|
||||||
|
const { blogs } = await commerce.getAllBlogPaths()
|
||||||
|
|
||||||
|
return {
|
||||||
|
paths: locales
|
||||||
|
? locales.reduce<string[]>((arr, locale) => {
|
||||||
|
blogs.forEach((blog: any) => {
|
||||||
|
arr.push(`/${locale}/blog/${blog.slug}`)
|
||||||
|
})
|
||||||
|
return arr
|
||||||
|
}, [])
|
||||||
|
: blogs.map((product: any) => `/blog/${product.path}`),
|
||||||
|
fallback: 'blocking',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
BlogDetailPage.Layout = Layout
|
BlogDetailPage.Layout = Layout
|
||||||
|
@@ -13,7 +13,7 @@ interface Props {
|
|||||||
totalItems: number
|
totalItems: number
|
||||||
}
|
}
|
||||||
export default function BlogsPage({ blogs, featuredBlog, totalItems }:Props) {
|
export default function BlogsPage({ blogs, featuredBlog, totalItems }:Props) {
|
||||||
|
|
||||||
let date = new Date(featuredBlog?.[0]?.createdAt ?? '' );
|
let date = new Date(featuredBlog?.[0]?.createdAt ?? '' );
|
||||||
let fullDate = date.toLocaleString('en-us', { month: 'long' }) + " " + date.getDate()+","+date.getFullYear();
|
let fullDate = date.toLocaleString('en-us', { month: 'long' }) + " " + date.getDate()+","+date.getFullYear();
|
||||||
|
|
||||||
@@ -21,16 +21,18 @@ export default function BlogsPage({ blogs, featuredBlog, totalItems }:Props) {
|
|||||||
<>
|
<>
|
||||||
<BlogBreadCrumb />
|
<BlogBreadCrumb />
|
||||||
<BlogHeading />
|
<BlogHeading />
|
||||||
<FeaturedCardBlog
|
{ (featuredBlog?.length !=0 ) &&
|
||||||
title={featuredBlog?.[0]?.title}
|
<FeaturedCardBlog
|
||||||
slug={featuredBlog?.[0]?.slug}
|
title={featuredBlog?.[0]?.title}
|
||||||
imgSrc={featuredBlog?.[0]?.imageSrc ?? ''}
|
slug={featuredBlog?.[0]?.slug}
|
||||||
content={featuredBlog?.[0]?.description}
|
imgSrc={featuredBlog?.[0]?.imageSrc ?? ''}
|
||||||
imgAuthor={featuredBlog?.[0]?.authorAvatarAsset}
|
content={featuredBlog?.[0]?.description}
|
||||||
authorName={featuredBlog?.[0]?.authorName}
|
imgAuthor={featuredBlog?.[0]?.authorAvatarAsset}
|
||||||
date={fullDate}
|
authorName={featuredBlog?.[0]?.authorName}
|
||||||
/>
|
date={fullDate}
|
||||||
<BlogsList blogList={blogs} total={totalItems} idFeatured={featuredBlog?.[0]?.id} />
|
/>
|
||||||
|
}
|
||||||
|
<BlogsList blogList={blogs} total={totalItems} idFeatured={featuredBlog?.[0]?.id ?? ''} />
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -47,7 +49,12 @@ export async function getStaticProps({
|
|||||||
|
|
||||||
const {featuredBlogs} = await commerce.getFeaturedBlog({
|
const {featuredBlogs} = await commerce.getFeaturedBlog({
|
||||||
variables: {
|
variables: {
|
||||||
take: 1
|
take: 1,
|
||||||
|
filter: {
|
||||||
|
isFeatured: {
|
||||||
|
eq:true
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
config,
|
config,
|
||||||
preview,
|
preview,
|
||||||
@@ -58,7 +65,12 @@ export async function getStaticProps({
|
|||||||
const blogsPromise = commerce.getAllBlogs({
|
const blogsPromise = commerce.getAllBlogs({
|
||||||
variables: {
|
variables: {
|
||||||
excludeBlogIds: [idFeaturedBlog],
|
excludeBlogIds: [idFeaturedBlog],
|
||||||
take: DEFAULT_BLOG_PAGE_SIZE
|
take: DEFAULT_BLOG_PAGE_SIZE,
|
||||||
|
filter: {
|
||||||
|
isFeatured: {
|
||||||
|
eq:false
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
config,
|
config,
|
||||||
preview,
|
preview,
|
||||||
|
@@ -14,10 +14,10 @@ interface Props {
|
|||||||
facets: Facet[],
|
facets: Facet[],
|
||||||
collections: Collection[],
|
collections: Collection[],
|
||||||
productsResult: { products: ProductCard[], totalItems: number },
|
productsResult: { products: ProductCard[], totalItems: number },
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Products({ facets, collections, productsResult }: Props) {
|
export default function Products({ facets, collections, productsResult }: Props) {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ProductListBanner />
|
<ProductListBanner />
|
||||||
|
@@ -1,12 +1,98 @@
|
|||||||
|
|
||||||
|
import { useRouter } from 'next/router'
|
||||||
import { Layout, RecipeDetail, RecommendedRecipes } from 'src/components/common'
|
import { Layout, RecipeDetail, RecommendedRecipes } from 'src/components/common'
|
||||||
import { INGREDIENT_DATA_TEST, RECIPE_DATA_TEST } from 'src/utils/demo-data'
|
import { INGREDIENT_DATA_TEST, RECIPE_DATA_TEST } from 'src/utils/demo-data'
|
||||||
|
import commerce from '@lib/api/commerce';
|
||||||
|
import { PromiseWithKey } from 'src/utils/types.utils';
|
||||||
|
import { GetStaticPropsContext,GetStaticPathsContext } from 'next';
|
||||||
|
import { getAllPromies } from 'src/utils/funtion.utils';
|
||||||
|
import { REVALIDATE_TIME } from 'src/utils/constanst.utils'
|
||||||
|
import { RecipeCardProps } from 'src/components/common/RecipeCard/RecipeCard';
|
||||||
|
interface Props {
|
||||||
|
recipe:{recipeDetail?: RecipeCardProps},
|
||||||
|
relevant:{relevantBlogs?:RecipeCardProps[]}
|
||||||
|
}
|
||||||
|
export default function Slug({recipe,relevant}:Props) {
|
||||||
|
|
||||||
export default function Slug() {
|
|
||||||
return <div className="page-recipe-detail">
|
return <div className="page-recipe-detail">
|
||||||
<RecipeDetail ingredients={INGREDIENT_DATA_TEST} />
|
<RecipeDetail ingredients={INGREDIENT_DATA_TEST}
|
||||||
<RecommendedRecipes data={RECIPE_DATA_TEST} />
|
{...recipe.recipeDetail}
|
||||||
|
/>
|
||||||
|
<RecommendedRecipes data={relevant?.relevantBlogs} />
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export async function getStaticProps({
|
||||||
|
params,
|
||||||
|
locale,
|
||||||
|
locales,
|
||||||
|
preview,
|
||||||
|
}: GetStaticPropsContext<{ slug: string }> ) {
|
||||||
|
const config = { locale, locales }
|
||||||
|
let promisesWithKey = [] as PromiseWithKey[]
|
||||||
|
let props = {} as any
|
||||||
|
|
||||||
|
// Blog detail
|
||||||
|
const recipesPromise = await commerce.getRecipeDetail({
|
||||||
|
variables: { slug: params!.slug },
|
||||||
|
config,
|
||||||
|
preview,
|
||||||
|
})
|
||||||
|
props.recipe = recipesPromise;
|
||||||
|
|
||||||
|
if (recipesPromise.recipeDetail === null) {
|
||||||
|
return { notFound: true };
|
||||||
|
}
|
||||||
|
|
||||||
|
// // Relevant Blogs
|
||||||
|
const relevantProductId = recipesPromise?.recipeDetail?.relevantProducts?.[0];
|
||||||
|
if (relevantProductId && recipesPromise?.recipeDetail?.relevantProducts?.length > 0) {
|
||||||
|
|
||||||
|
const relevantBlogs = commerce.getRelevantBlogs({
|
||||||
|
variables: { productId: relevantProductId },
|
||||||
|
config,
|
||||||
|
preview,
|
||||||
|
})
|
||||||
|
promisesWithKey.push({ key: 'relevant', promise: relevantBlogs})
|
||||||
|
|
||||||
|
}else {
|
||||||
|
props.relevantBlogs = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
const promises = getAllPromies(promisesWithKey)
|
||||||
|
const rs = await Promise.all(promises)
|
||||||
|
|
||||||
|
promisesWithKey.map((item, index) => {
|
||||||
|
props[item.key] = item.keyResult ? rs[index][item.keyResult] : rs[index]
|
||||||
|
return null
|
||||||
|
})
|
||||||
|
return {
|
||||||
|
props,
|
||||||
|
revalidate: REVALIDATE_TIME,
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getStaticPaths({ locales }: GetStaticPathsContext) {
|
||||||
|
|
||||||
|
const { recipes } = await commerce.getAllRecipePaths()
|
||||||
|
return {
|
||||||
|
paths: locales
|
||||||
|
? locales.reduce<string[]>((arr, locale) => {
|
||||||
|
recipes.forEach((blog: any) => {
|
||||||
|
arr.push(`/${locale}/recipe/${blog.slug}`)
|
||||||
|
})
|
||||||
|
return arr
|
||||||
|
}, [])
|
||||||
|
: recipes.map((product: any) => `/recipe/${product.path}`),
|
||||||
|
fallback: 'blocking',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Slug.Layout = Layout
|
Slug.Layout = Layout
|
||||||
|
@@ -1,15 +1,68 @@
|
|||||||
import { Layout } from 'src/components/common';
|
import { Layout } from 'src/components/common';
|
||||||
import RecipeListBanner from 'src/components/modules/recipes-list/RecipeListBanner/RecipeListBanner';
|
import RecipeListBanner from 'src/components/modules/recipes-list/RecipeListBanner/RecipeListBanner';
|
||||||
import RecipesList from 'src/components/modules/recipes-list/RecipesList/RecipesList';
|
import RecipesList from 'src/components/modules/recipes-list/RecipesList/RecipesList';
|
||||||
|
import { GetStaticPropsContext } from 'next';
|
||||||
|
import { PromiseWithKey } from 'src/utils/types.utils';
|
||||||
|
import { DEFAULT_BLOG_PAGE_SIZE } from "src/utils/constanst.utils";
|
||||||
|
import commerce from '@lib/api/commerce';
|
||||||
|
import { getAllPromies } from 'src/utils/funtion.utils';
|
||||||
|
import { RecipeCardProps } from 'src/components/common/RecipeCard/RecipeCard';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
export default function RecipeListPage() {
|
recipesResult: {recipes: RecipeCardProps[] ,totalItems?: number},
|
||||||
|
|
||||||
|
}
|
||||||
|
export default function RecipeListPage({recipesResult}:Props) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<RecipeListBanner />
|
<RecipeListBanner />
|
||||||
<RecipesList/>
|
<RecipesList recipeList={recipesResult.recipes} total={recipesResult.totalItems ?? 0}/>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getStaticProps({
|
||||||
|
preview,
|
||||||
|
locale,
|
||||||
|
locales,
|
||||||
|
}: GetStaticPropsContext) {
|
||||||
|
|
||||||
|
const config = { locale, locales }
|
||||||
|
let promisesWithKey = [] as PromiseWithKey[]
|
||||||
|
let props = {} as any;
|
||||||
|
|
||||||
|
|
||||||
|
const recipesPromise = commerce.getAllRecipes({
|
||||||
|
variables: {
|
||||||
|
excludeBlogIds: [],
|
||||||
|
take: DEFAULT_BLOG_PAGE_SIZE,
|
||||||
|
id: 'DESC',
|
||||||
|
isPublish:true
|
||||||
|
},
|
||||||
|
config,
|
||||||
|
preview,
|
||||||
|
})
|
||||||
|
promisesWithKey.push({ key: 'recipesResult', promise: recipesPromise})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
const promises = getAllPromies(promisesWithKey)
|
||||||
|
const rs = await Promise.all(promises)
|
||||||
|
|
||||||
|
promisesWithKey.map((item, index) => {
|
||||||
|
props[item.key] = item.keyResult ? rs[index][item.keyResult] : rs[index]
|
||||||
|
return null
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
props,
|
||||||
|
revalidate: 60
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
RecipeListPage.Layout = Layout
|
RecipeListPage.Layout = Layout
|
||||||
|
@@ -5,7 +5,9 @@
|
|||||||
.authorImage {
|
.authorImage {
|
||||||
width:3.2rem;
|
width:3.2rem;
|
||||||
height:3.2rem;
|
height:3.2rem;
|
||||||
border-radius:3.2rem;
|
img{
|
||||||
|
border-radius:3.2rem !important;
|
||||||
|
}
|
||||||
div{
|
div{
|
||||||
min-width:3.2rem !important;
|
min-width:3.2rem !important;
|
||||||
}
|
}
|
||||||
|
@@ -1,20 +1,21 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
import { RecipeProps } from 'src/utils/types.utils'
|
||||||
import { ProductCardProps } from '../ProductCard/ProductCard'
|
import { ProductCardProps } from '../ProductCard/ProductCard'
|
||||||
import RecipeDetailInfo from './components/RecipeDetailInfo/RecipeDetailInfo'
|
import RecipeDetailInfo from './components/RecipeDetailInfo/RecipeDetailInfo'
|
||||||
import RecipeIngredient from './components/RecipeIngredient/RecipeIngredient'
|
import RecipeIngredient from './components/RecipeIngredient/RecipeIngredient'
|
||||||
import s from './RecipeDetail.module.scss'
|
import s from './RecipeDetail.module.scss'
|
||||||
|
|
||||||
|
|
||||||
interface Props {
|
interface Props extends RecipeProps {
|
||||||
className?: string
|
className?: string
|
||||||
children?: any,
|
children?: any,
|
||||||
ingredients: ProductCardProps[],
|
ingredients: ProductCardProps[]
|
||||||
}
|
}
|
||||||
|
|
||||||
const RecipeDetail = ({ ingredients }: Props) => {
|
const RecipeDetail = ({ ingredients,...rest }: Props) => {
|
||||||
return (
|
return (
|
||||||
<section className={s.recipeDetail}>
|
<section className={s.recipeDetail}>
|
||||||
<RecipeDetailInfo />
|
<RecipeDetailInfo {...rest} />
|
||||||
<RecipeIngredient data={ingredients} />
|
<RecipeIngredient data={ingredients} />
|
||||||
</section >
|
</section >
|
||||||
)
|
)
|
||||||
|
@@ -1,24 +1,26 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { ImgWithLink } from 'src/components/common'
|
import { ImgWithLink } from 'src/components/common'
|
||||||
|
import { RecipeProps } from 'src/utils/types.utils'
|
||||||
import RecipeBriefInfo from '../RecipeBriefInfo/RecipeBriefInfo'
|
import RecipeBriefInfo from '../RecipeBriefInfo/RecipeBriefInfo'
|
||||||
import s from './RecipeDetailInfo.module.scss'
|
import s from './RecipeDetailInfo.module.scss'
|
||||||
|
|
||||||
|
|
||||||
interface Props {
|
interface Prop extends RecipeProps {
|
||||||
className?: string
|
className?: string
|
||||||
children?: any
|
children?: any
|
||||||
}
|
}
|
||||||
|
|
||||||
const RecipeDetailInfo = ({ }: Props) => {
|
const RecipeDetailInfo = ({ ...rest}: Prop) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className={s.recipeDetailInfo}>
|
<section className={s.recipeDetailInfo}>
|
||||||
<div className={s.img}>
|
<div className={s.img}>
|
||||||
<ImgWithLink src="https://user-images.githubusercontent.com/76729908/131634880-8ae1437b-d3f8-421e-a546-d5a4f9a28e5f.png" alt="Recipe" />
|
<ImgWithLink src= {rest.imageSrc ?? ''} alt={rest.title} />
|
||||||
</div>
|
</div>
|
||||||
<div className={s.recipeInfo}>
|
<div className={s.recipeInfo}>
|
||||||
<div className={s.top}>
|
<div className={s.top}>
|
||||||
<h1 className={s.name}>
|
<h1 className={s.name}>
|
||||||
Crispy Fried Calamari
|
{rest.title}
|
||||||
</h1>
|
</h1>
|
||||||
<RecipeBriefInfo />
|
<RecipeBriefInfo />
|
||||||
</div>
|
</div>
|
||||||
|
@@ -30,10 +30,10 @@ const RESPONSIVE: ResponsiveType = {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
interface Props {
|
interface Props {
|
||||||
data: RecipeCardProps[],
|
data?: RecipeCardProps[],
|
||||||
}
|
}
|
||||||
|
|
||||||
const RecommendedRecipes = ({ data }: Props) => {
|
const RecommendedRecipes = ({ data=[] }: Props) => {
|
||||||
return (
|
return (
|
||||||
<div className={s.recommendedRecipes}>
|
<div className={s.recommendedRecipes}>
|
||||||
<div className={s.infoProducts}>
|
<div className={s.infoProducts}>
|
||||||
|
@@ -14,40 +14,7 @@ interface RelevantProps {
|
|||||||
bgcolor?: "default" | "cream"
|
bgcolor?: "default" | "cream"
|
||||||
}
|
}
|
||||||
|
|
||||||
const recipe:BlogCardProps[] = [
|
const RelevantBlogPosts = ({ data , itemKey="detail-relevant", title="Relevant Blog Posts", bgcolor = "default" }: RelevantProps) => {
|
||||||
{
|
|
||||||
title: "Want to Lose Weight? Here are 10 DEBM Diet Guidelines for Beginners",
|
|
||||||
slug: 'have-a-nice-lunch',
|
|
||||||
description:"The DEBM diet stands for "+'"Delicious Happy Fun Diet"'+". This diet was popularized by Robert...",
|
|
||||||
imageSrc: "https://user-images.githubusercontent.com/46085455/133185783-8100ef4e-7a72-4dc1-bb12-2ca46b56b393.png",
|
|
||||||
},{
|
|
||||||
title: "9 Ways to Make an Aloe Vera Mask at Home",
|
|
||||||
slug: 'have-a-nice-lunch',
|
|
||||||
description:"Aloe vera or aloe vera is a green plant, has thorns on the side of the skin with yellowish patches and...",
|
|
||||||
imageSrc: "https://user-images.githubusercontent.com/46085455/133185911-df505d10-fdcd-4312-add3-7c62ad8af71e.png",
|
|
||||||
},{
|
|
||||||
title: "Don't Buy Wrong, Here Are 7 Ways to Choose a Ripe Dragon Fruit",
|
|
||||||
slug: 'have-a-nice-lunch',
|
|
||||||
description:"Dragon fruit is a type of fruit that is a favorite for many people because of its delicious and fresh...",
|
|
||||||
imageSrc: "https://user-images.githubusercontent.com/46085455/133185959-7ad75580-ca6d-4684-83d9-3f64500bbc97.png",
|
|
||||||
},{
|
|
||||||
title: "Want to Lose Weight? Here are 10 DEBM Diet Guidelines for Beginners",
|
|
||||||
slug: 'have-a-nice-lunch',
|
|
||||||
description:"The DEBM diet stands for "+'"Delicious Happy Fun Diet"'+". This diet was popularized by Robert...",
|
|
||||||
imageSrc: "https://user-images.githubusercontent.com/46085455/133185783-8100ef4e-7a72-4dc1-bb12-2ca46b56b393.png",
|
|
||||||
},{
|
|
||||||
title: "9 Ways to Make an Aloe Vera Mask at Home",
|
|
||||||
slug: 'have-a-nice-lunch',
|
|
||||||
description:"Aloe vera or aloe vera is a green plant, has thorns on the side of the skin with yellowish patches and...",
|
|
||||||
imageSrc: "https://user-images.githubusercontent.com/46085455/133185911-df505d10-fdcd-4312-add3-7c62ad8af71e.png",
|
|
||||||
},{
|
|
||||||
title: "Don't Buy Wrong, Here Are 7 Ways to Choose a Ripe Dragon Fruit",
|
|
||||||
slug: 'have-a-nice-lunch',
|
|
||||||
description:"Dragon fruit is a type of fruit that is a favorite for many people because of its delicious and fresh...",
|
|
||||||
imageSrc: "https://user-images.githubusercontent.com/46085455/133185959-7ad75580-ca6d-4684-83d9-3f64500bbc97.png",
|
|
||||||
}]
|
|
||||||
|
|
||||||
const RelevantBlogPosts = ({ data = recipe, itemKey="detail-relevant", title="Relevant Blog Posts", bgcolor = "default" }: RelevantProps) => {
|
|
||||||
return (
|
return (
|
||||||
<div className={classNames({
|
<div className={classNames({
|
||||||
[s.blogPostWarpper] : true,
|
[s.blogPostWarpper] : true,
|
||||||
@@ -63,7 +30,7 @@ const recipe:BlogCardProps[] = [
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className={s.bot}>
|
<div className={s.bot}>
|
||||||
<BlogPostCarousel data={data} itemKey={itemKey} />
|
<BlogPostCarousel data={data} itemKey={itemKey} />}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
1
src/components/hooks/recipe/index.ts
Normal file
1
src/components/hooks/recipe/index.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export {default as useGetRecipeList } from "./useGetRecipeList"
|
18
src/components/hooks/recipe/useGetRecipeList.tsx
Normal file
18
src/components/hooks/recipe/useGetRecipeList.tsx
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import { GetAllRecipesQuery,QueryRecipes, RecipeList } from '@framework/schema'
|
||||||
|
import { normalizeRecipeList } from '@framework/utils/normalize'
|
||||||
|
import { getAllBlogsQuery } from '@framework/utils/queries/get-all-blog-query'
|
||||||
|
import gglFetcher from 'src/utils/gglFetcher'
|
||||||
|
import useSWR from 'swr'
|
||||||
|
|
||||||
|
const useGetRecipeList = (options?: QueryRecipes) => {
|
||||||
|
const { data, isValidating, ...rest } = useSWR<GetAllRecipesQuery>([getAllBlogsQuery, options], gglFetcher)
|
||||||
|
|
||||||
|
return {
|
||||||
|
reicpes: data?.blogs?.items?.map((recipe:RecipeList)=>normalizeRecipeList(recipe)),
|
||||||
|
totalItems: data?.blogs?.totalItems || null,
|
||||||
|
loading: isValidating,
|
||||||
|
...rest
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default useGetRecipeList
|
@@ -9,57 +9,24 @@ import Link from 'next/link';
|
|||||||
interface BlogContentProps {
|
interface BlogContentProps {
|
||||||
className?: string
|
className?: string
|
||||||
children?: any,
|
children?: any,
|
||||||
|
title?: string,
|
||||||
|
content?: string,
|
||||||
|
imgAuthor?: string,
|
||||||
|
date?: string,
|
||||||
|
authorName?: string,
|
||||||
}
|
}
|
||||||
const BlogContent = ({}:BlogContentProps) => {
|
const BlogContent = ({title,date='',content,imgAuthor='',authorName='' }:BlogContentProps) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className={s.blogContentWrapper}>
|
<div className={s.blogContentWrapper}>
|
||||||
<DateTime date="APRIL 30, 2021"/>
|
<DateTime date={date}/>
|
||||||
<h1>The Best Sesame Soy Broccoli Salad</h1>
|
<h1>{title}</h1>
|
||||||
<div className={s.author}>
|
<div className={s.author}>
|
||||||
<Author image={imageAuthor.src} name="Alessandro Del Piero" />
|
<Author image={imgAuthor} name={authorName} />
|
||||||
</div>
|
</div>
|
||||||
<section className={s.content}>
|
<section className={s.content}>
|
||||||
|
{content}
|
||||||
<p> When you’re trying to eat healthier but want something more substantial than a leafy green salad, broccoli salad is there for you. I love the crunch and heft of broccoli, especially when it’s cut up into bite size spoonable pieces.
|
|
||||||
<br/>
|
|
||||||
<br/>
|
|
||||||
|
|
||||||
Some people aren’t into raw broccoli, but I love it! I always go for the raw broccoli on those vegetable platters that seem to be at every potluck/party you go to.
|
|
||||||
<br/>
|
|
||||||
<br/>
|
|
||||||
This is a simple broccoli salad: you have the bulk of it, raw broccoli; crunchy red onions for a bit of acidity and raw crunch, craisins for sweetness, almonds for a nutty counter point; and a sweet and tangy soy-rice vinegar-sesame dressing.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<br/>
|
|
||||||
<br/>
|
|
||||||
|
|
||||||
<h2 className={s.heading2}>What is broccoli salad</h2>
|
|
||||||
<br/>
|
|
||||||
<p> When you’re trying to eat healthier but want something more substantial than a leafy green salad, broccoli salad is there for you. I love the crunch and heft of broccoli, especially when it’s cut up into bite size spoonable pieces.
|
|
||||||
<br/>
|
|
||||||
<br/>
|
|
||||||
|
|
||||||
Some people aren’t into raw broccoli, but I love it! I always go for the raw broccoli on those vegetable platters that seem to be at every potluck/party you go to.
|
|
||||||
<br/>
|
|
||||||
<br/>
|
|
||||||
This is a simple broccoli salad: you have the bulk of it, raw broccoli; crunchy red onions for a bit of acidity and raw crunch, craisins for sweetness, almonds for a nutty counter point; and a sweet and tangy soy-rice vinegar-sesame dressing.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<br/>
|
|
||||||
<br/>
|
|
||||||
|
|
||||||
<h2 className={s.heading2}>What about broccoli stems?</h2>
|
|
||||||
<br/>
|
|
||||||
<p>
|
|
||||||
You can eat broccoli stems. In fact, they are delicious. Just use a peeler to peel off the outsides and then trim the stalks into small 1/4”-1/2” cubes.
|
|
||||||
</p>
|
|
||||||
<br/>
|
|
||||||
|
|
||||||
<figure>
|
|
||||||
<ImgWithLink src="https://user-images.githubusercontent.com/89437339/133046625-bdf9cc0d-6f22-43e5-a49d-d4d34df19cf2.jpg" alt="blog-detail" />
|
|
||||||
</figure>
|
|
||||||
|
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<div className={s.boxShare}>
|
<div className={s.boxShare}>
|
||||||
|
@@ -5,7 +5,8 @@ import BreadcrumbCommon from 'src/components/common/BreadcrumbCommon/BreadcrumbC
|
|||||||
import s from './BlogDetailImg.module.scss';
|
import s from './BlogDetailImg.module.scss';
|
||||||
interface Props {
|
interface Props {
|
||||||
className?: string
|
className?: string
|
||||||
children?: any
|
children?: any,
|
||||||
|
imgSrc?:string
|
||||||
}
|
}
|
||||||
|
|
||||||
const CRUMBS =[
|
const CRUMBS =[
|
||||||
@@ -14,14 +15,14 @@ const CRUMBS =[
|
|||||||
link:"/blog"
|
link:"/blog"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
const BlogDetailImg = ({}:Props ) => {
|
const BlogDetailImg = ({imgSrc = ''}:Props ) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className={s.beadcrumb}>
|
<div className={s.beadcrumb}>
|
||||||
<BreadcrumbCommon crumbs={CRUMBS} />
|
<BreadcrumbCommon crumbs={CRUMBS} />
|
||||||
</div>
|
</div>
|
||||||
<div className={s.image}>
|
<div className={s.image}>
|
||||||
<ImgWithLink src="https://user-images.githubusercontent.com/89437339/133044532-8b5f9442-841b-4187-84b4-d6cc66676b52.png" alt="Ảnh đại diện"/>
|
<ImgWithLink src={imgSrc} alt="avatar"/>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
@@ -92,5 +92,3 @@ const BlogsList = ({ blogList,total,idFeatured }:BlogsListProps) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default BlogsList
|
export default BlogsList
|
||||||
|
|
||||||
|
|
||||||
|
@@ -8,7 +8,7 @@ import { useLocalStorage } from 'src/components/hooks/useLocalStorage';
|
|||||||
interface Props {
|
interface Props {
|
||||||
data: ProductCardProps[]
|
data: ProductCardProps[]
|
||||||
}
|
}
|
||||||
const ViewedProducts = ({data}:Props) => {
|
const ViewedProducts = ({data = []}:Props) => {
|
||||||
if (data.length===0){
|
if (data.length===0){
|
||||||
return <div></div>
|
return <div></div>
|
||||||
}
|
}
|
||||||
|
@@ -1,224 +1,303 @@
|
|||||||
import React from 'react';
|
import React, { useEffect, useState,useRef, useMemo } from 'react'
|
||||||
import { SelectCommon } from 'src/components/common';
|
import { SelectCommon } from 'src/components/common'
|
||||||
import BreadcrumbCommon from 'src/components/common/BreadcrumbCommon/BreadcrumbCommon';
|
import BreadcrumbCommon from 'src/components/common/BreadcrumbCommon/BreadcrumbCommon'
|
||||||
import MenuNavigation from 'src/components/common/MenuNavigation/MenuNavigation';
|
import MenuNavigation from 'src/components/common/MenuNavigation/MenuNavigation'
|
||||||
import PaginationCommon from 'src/components/common/PaginationCommon/PaginationCommon';
|
import PaginationCommon from 'src/components/common/PaginationCommon/PaginationCommon'
|
||||||
import { RecipeCardProps } from 'src/components/common/RecipeCard/RecipeCard';
|
import { RecipeCardProps } from 'src/components/common/RecipeCard/RecipeCard'
|
||||||
import { OPTION_ALL, QUERY_KEY, ROUTE } from 'src/utils/constanst.utils';
|
import { OPTION_ALL, QUERY_KEY, ROUTE } from 'src/utils/constanst.utils'
|
||||||
import HeadingCommon from "../../../common/HeadingCommon/HeadingCommon";
|
import HeadingCommon from '../../../common/HeadingCommon/HeadingCommon'
|
||||||
import { RecipeCard } from 'src/components/common'
|
import { RecipeCard } from 'src/components/common'
|
||||||
|
import { DEFAULT_BLOG_PAGE_SIZE } from 'src/utils/constanst.utils'
|
||||||
|
import s from './RecipesList.module.scss'
|
||||||
|
import { useRouter } from 'next/router'
|
||||||
|
import { QueryRecipes } from '@framework/schema'
|
||||||
|
import { useGetRecipeList } from 'src/components/hooks/recipe'
|
||||||
|
import { getPageFromQuery } from 'src/utils/funtion.utils'
|
||||||
|
import { ListBlogCardSkeleton } from 'src/components/common'
|
||||||
|
|
||||||
import s from './RecipesList.module.scss';
|
const recipe: RecipeCardProps[] = [
|
||||||
|
{
|
||||||
|
title: 'Special Recipe of Vietnamese Phở',
|
||||||
|
description:
|
||||||
|
'Alright, before we get to the actual recipe, let’s chat for a sec about the ingredients. To make this pho soup recipe, you will need:',
|
||||||
|
imageSrc:
|
||||||
|
'https://user-images.githubusercontent.com/76729908/132159257-f92574c7-d00d-4142-8ea7-0ca9515fb737.png',
|
||||||
|
slug: 'special-recipe-of-vietnamese-pho',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Original Recipe of Curry',
|
||||||
|
description:
|
||||||
|
'Chicken curry is common to several countries including India, countries in Asia and the Caribbean. My favorite of them though is this aromatic Indian...',
|
||||||
|
imageSrc:
|
||||||
|
'https://user-images.githubusercontent.com/76729908/132159259-ae4c986d-ab53-4758-9137-d06bafdd15d0.png',
|
||||||
|
slug: 'original-recipe-of-curry',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'The Best Recipe of Beef Noodle Soup',
|
||||||
|
description:
|
||||||
|
'The broth for Bun Bo Hue is prepared by slowly simmering various types of beef and pork bones (ox tail, beef shank, pork neck bones, pork feet,...',
|
||||||
|
imageSrc:
|
||||||
|
'https://user-images.githubusercontent.com/76729908/132159262-f28a9fb9-4852-47e6-80b5-d600521b548a.png',
|
||||||
|
slug: 'the-best-recipe-of-beef-noodle-soup',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Special Recipe of Vietnamese Phở',
|
||||||
|
description:
|
||||||
|
'Alright, before we get to the actual recipe, let’s chat for a sec about the ingredients. To make this pho soup recipe, you will need:',
|
||||||
|
imageSrc:
|
||||||
|
'https://user-images.githubusercontent.com/76729908/132159257-f92574c7-d00d-4142-8ea7-0ca9515fb737.png',
|
||||||
|
slug: 'special-recipe-of-vietnamese-pho',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Original Recipe of Curry',
|
||||||
|
description:
|
||||||
|
'Chicken curry is common to several countries including India, countries in Asia and the Caribbean. My favorite of them though is this aromatic Indian...',
|
||||||
|
imageSrc:
|
||||||
|
'https://user-images.githubusercontent.com/76729908/132159259-ae4c986d-ab53-4758-9137-d06bafdd15d0.png',
|
||||||
|
slug: 'original-recipe-of-curry',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'The Best Recipe of Beef Noodle Soup',
|
||||||
|
description:
|
||||||
|
'The broth for Bun Bo Hue is prepared by slowly simmering various types of beef and pork bones (ox tail, beef shank, pork neck bones, pork feet,...',
|
||||||
|
imageSrc:
|
||||||
|
'https://user-images.githubusercontent.com/76729908/132159262-f28a9fb9-4852-47e6-80b5-d600521b548a.png',
|
||||||
|
slug: 'the-best-recipe-of-beef-noodle-soup',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
const recipe:RecipeCardProps[] = [
|
const DEFAULT_PAGESIZE_RECIPELIST = 6
|
||||||
{
|
|
||||||
title: "Special Recipe of Vietnamese Phở",
|
|
||||||
description: "Alright, before we get to the actual recipe, let’s chat for a sec about the ingredients. To make this pho soup recipe, you will need:",
|
|
||||||
imageSrc: 'https://user-images.githubusercontent.com/76729908/132159257-f92574c7-d00d-4142-8ea7-0ca9515fb737.png',
|
|
||||||
slug: "special-recipe-of-vietnamese-pho"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Original Recipe of Curry",
|
|
||||||
description: "Chicken curry is common to several countries including India, countries in Asia and the Caribbean. My favorite of them though is this aromatic Indian...",
|
|
||||||
imageSrc: 'https://user-images.githubusercontent.com/76729908/132159259-ae4c986d-ab53-4758-9137-d06bafdd15d0.png',
|
|
||||||
slug:"original-recipe-of-curry"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "The Best Recipe of Beef Noodle Soup",
|
|
||||||
description: "The broth for Bun Bo Hue is prepared by slowly simmering various types of beef and pork bones (ox tail, beef shank, pork neck bones, pork feet,...",
|
|
||||||
imageSrc: 'https://user-images.githubusercontent.com/76729908/132159262-f28a9fb9-4852-47e6-80b5-d600521b548a.png',
|
|
||||||
slug:"the-best-recipe-of-beef-noodle-soup"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Special Recipe of Vietnamese Phở",
|
|
||||||
description: "Alright, before we get to the actual recipe, let’s chat for a sec about the ingredients. To make this pho soup recipe, you will need:",
|
|
||||||
imageSrc: 'https://user-images.githubusercontent.com/76729908/132159257-f92574c7-d00d-4142-8ea7-0ca9515fb737.png',
|
|
||||||
slug: "special-recipe-of-vietnamese-pho"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Original Recipe of Curry",
|
|
||||||
description: "Chicken curry is common to several countries including India, countries in Asia and the Caribbean. My favorite of them though is this aromatic Indian...",
|
|
||||||
imageSrc: 'https://user-images.githubusercontent.com/76729908/132159259-ae4c986d-ab53-4758-9137-d06bafdd15d0.png',
|
|
||||||
slug:"original-recipe-of-curry"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "The Best Recipe of Beef Noodle Soup",
|
|
||||||
description: "The broth for Bun Bo Hue is prepared by slowly simmering various types of beef and pork bones (ox tail, beef shank, pork neck bones, pork feet,...",
|
|
||||||
imageSrc: 'https://user-images.githubusercontent.com/76729908/132159262-f28a9fb9-4852-47e6-80b5-d600521b548a.png',
|
|
||||||
slug:"the-best-recipe-of-beef-noodle-soup"
|
|
||||||
},];
|
|
||||||
|
|
||||||
const DEFAULT_PAGESIZE_RECIPELIST = 6;
|
|
||||||
|
|
||||||
const BREADCRUMB = [
|
const BREADCRUMB = [
|
||||||
{
|
{
|
||||||
name: 'Special Recipes',
|
name: 'Special Recipes',
|
||||||
link: `#`,
|
link: `#`,
|
||||||
},
|
},
|
||||||
];
|
]
|
||||||
|
|
||||||
const CATEGORY = [
|
const CATEGORY = [
|
||||||
{
|
{
|
||||||
name: 'All',
|
name: 'All',
|
||||||
link: `${ROUTE.RECIPES}/?${QUERY_KEY.RECIPES}=${OPTION_ALL}`,
|
link: `${ROUTE.RECIPES}/?${QUERY_KEY.RECIPES}=${OPTION_ALL}`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Malaysian',
|
name: 'Malaysian',
|
||||||
link: `${ROUTE.RECIPES}/?${QUERY_KEY.RECIPES}=malaysia`,
|
link: `${ROUTE.RECIPES}/?${QUERY_KEY.RECIPES}=malaysia`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Vietnamese',
|
name: 'Vietnamese',
|
||||||
link: `${ROUTE.RECIPES}/?${QUERY_KEY.RECIPES}=vietnamese`,
|
link: `${ROUTE.RECIPES}/?${QUERY_KEY.RECIPES}=vietnamese`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Thailand',
|
name: 'Thailand',
|
||||||
link: `${ROUTE.RECIPES}/?${QUERY_KEY.RECIPES}=thailand`,
|
link: `${ROUTE.RECIPES}/?${QUERY_KEY.RECIPES}=thailand`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Indian',
|
name: 'Indian',
|
||||||
link: `${ROUTE.RECIPES}/?${QUERY_KEY.RECIPES}=indian`,
|
link: `${ROUTE.RECIPES}/?${QUERY_KEY.RECIPES}=indian`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Lao',
|
name: 'Lao',
|
||||||
link: `${ROUTE.RECIPES}/?${QUERY_KEY.RECIPES}=lao`,
|
link: `${ROUTE.RECIPES}/?${QUERY_KEY.RECIPES}=lao`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Chinese',
|
name: 'Chinese',
|
||||||
link: `${ROUTE.RECIPES}/?${QUERY_KEY.RECIPES}=chinese`,
|
link: `${ROUTE.RECIPES}/?${QUERY_KEY.RECIPES}=chinese`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Korean',
|
name: 'Korean',
|
||||||
link: `${ROUTE.RECIPES}/?${QUERY_KEY.RECIPES}=korean`,
|
link: `${ROUTE.RECIPES}/?${QUERY_KEY.RECIPES}=korean`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Japanese',
|
name: 'Japanese',
|
||||||
link: `${ROUTE.RECIPES}/?${QUERY_KEY.RECIPES}=japanese`,
|
link: `${ROUTE.RECIPES}/?${QUERY_KEY.RECIPES}=japanese`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Western',
|
name: 'Western',
|
||||||
link: `${ROUTE.RECIPES}/?${QUERY_KEY.RECIPES}=western`,
|
link: `${ROUTE.RECIPES}/?${QUERY_KEY.RECIPES}=western`,
|
||||||
},
|
},
|
||||||
];
|
]
|
||||||
|
|
||||||
const CATEGORYSELECT = [
|
const CATEGORYSELECT = [
|
||||||
{
|
{
|
||||||
name: 'All',
|
name: 'All',
|
||||||
value: `${ROUTE.RECIPES}/?${QUERY_KEY.RECIPES}=${OPTION_ALL}`,
|
value: `${ROUTE.RECIPES}/?${QUERY_KEY.RECIPES}=${OPTION_ALL}`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Malaysian',
|
name: 'Malaysian',
|
||||||
value: `${ROUTE.RECIPES}/?${QUERY_KEY.RECIPES}=malaysia`,
|
value: `${ROUTE.RECIPES}/?${QUERY_KEY.RECIPES}=malaysia`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Vietnamese',
|
name: 'Vietnamese',
|
||||||
value: `${ROUTE.RECIPES}/?${QUERY_KEY.RECIPES}=vietnamese`,
|
value: `${ROUTE.RECIPES}/?${QUERY_KEY.RECIPES}=vietnamese`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Thailand',
|
name: 'Thailand',
|
||||||
value: `${ROUTE.RECIPES}/?${QUERY_KEY.RECIPES}=thailand`,
|
value: `${ROUTE.RECIPES}/?${QUERY_KEY.RECIPES}=thailand`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Indian',
|
name: 'Indian',
|
||||||
value: `${ROUTE.RECIPES}/?${QUERY_KEY.RECIPES}=indian`,
|
value: `${ROUTE.RECIPES}/?${QUERY_KEY.RECIPES}=indian`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Lao',
|
name: 'Lao',
|
||||||
value: `${ROUTE.RECIPES}/?${QUERY_KEY.RECIPES}=lao`,
|
value: `${ROUTE.RECIPES}/?${QUERY_KEY.RECIPES}=lao`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Chinese',
|
name: 'Chinese',
|
||||||
value: `${ROUTE.RECIPES}/?${QUERY_KEY.RECIPES}=chinese`,
|
value: `${ROUTE.RECIPES}/?${QUERY_KEY.RECIPES}=chinese`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Korean',
|
name: 'Korean',
|
||||||
value: `${ROUTE.RECIPES}/?${QUERY_KEY.RECIPES}=korean`,
|
value: `${ROUTE.RECIPES}/?${QUERY_KEY.RECIPES}=korean`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Japanese',
|
name: 'Japanese',
|
||||||
value: `${ROUTE.RECIPES}/?${QUERY_KEY.RECIPES}=japanese`,
|
value: `${ROUTE.RECIPES}/?${QUERY_KEY.RECIPES}=japanese`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Western',
|
name: 'Western',
|
||||||
value: `${ROUTE.RECIPES}/?${QUERY_KEY.RECIPES}=western`,
|
value: `${ROUTE.RECIPES}/?${QUERY_KEY.RECIPES}=western`,
|
||||||
},
|
},
|
||||||
];
|
]
|
||||||
|
|
||||||
const OPTIONSLECT=[
|
|
||||||
{
|
|
||||||
name:"Most Viewed",
|
|
||||||
value:"most-viewed"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name:"Lastest Blogs",
|
|
||||||
value:"lastest-blogs"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name:"Recent Blogs",
|
|
||||||
value:"recent-blogs"
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
interface Props{
|
const OPTIONSLECT = [
|
||||||
data?: RecipeCardProps[],
|
{
|
||||||
recipes?:{
|
name: 'Most Viewed',
|
||||||
title:string,
|
value: 'most-viewed',
|
||||||
imageSrc:string,
|
},
|
||||||
description:string,
|
{
|
||||||
slug:string
|
name: 'Lastest Blogs',
|
||||||
}[],
|
value: 'lastest-blogs',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Recent Blogs',
|
||||||
|
value: 'recent-blogs',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
recipeList?: RecipeCardProps[]
|
||||||
|
total: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const RecipesList = ({ recipeList, total }: Props) => {
|
||||||
|
const DEFAULT_BLOGS_ARGS = useMemo(
|
||||||
|
() => ({
|
||||||
|
excludeBlogIds: [],
|
||||||
|
options:{
|
||||||
|
take: DEFAULT_BLOG_PAGE_SIZE,
|
||||||
|
sort: {
|
||||||
|
id: 'DESC',
|
||||||
|
},
|
||||||
|
filter:{
|
||||||
|
isPublish: {
|
||||||
|
eq:true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
[]
|
||||||
|
)
|
||||||
|
const router = useRouter()
|
||||||
|
const [initialQueryFlag, setInitialQueryFlag] = useState<boolean>(true)
|
||||||
|
const [optionQueryBlog, setOptionQueryBlog] = useState<QueryRecipes>(DEFAULT_BLOGS_ARGS)
|
||||||
|
const { reicpes, totalItems, loading } = useGetRecipeList(optionQueryBlog)
|
||||||
|
|
||||||
|
|
||||||
const RecipesList = ({ data =recipe}:Props) => {
|
const onPageChange = (page: number) => {
|
||||||
return (
|
router.push(
|
||||||
<>
|
{
|
||||||
<div className={s.recipesListWrapper}>
|
pathname: ROUTE.RECIPES,
|
||||||
<div className={s.breadcrumb}>
|
query: {
|
||||||
<BreadcrumbCommon crumbs={BREADCRUMB} />
|
...router.query,
|
||||||
</div>
|
[QUERY_KEY.PAGE]: page,
|
||||||
<div className={s.recipesListPageMain}>
|
},
|
||||||
|
},
|
||||||
<div className={s.categories}>
|
undefined,
|
||||||
<MenuNavigation categories={CATEGORY} heading="Categories"/>
|
{ shallow: true }
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={s.recipesList}>
|
|
||||||
<HeadingCommon align='left'>SPECIAL RECIPES</HeadingCommon>
|
|
||||||
|
|
||||||
<div className={s.boxSelect}>
|
|
||||||
<div className={s.categorySelectCate}>
|
|
||||||
<label htmlFor="">Categories</label>
|
|
||||||
<div className={s.select}>
|
|
||||||
<SelectCommon options={CATEGORYSELECT} placeholder="Categories"/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className={s.categorySelectSort}>
|
|
||||||
<label htmlFor="" >Sort By</label>
|
|
||||||
<div className={s.select}>
|
|
||||||
<SelectCommon options={OPTIONSLECT} placeholder="Sort By" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={s.inner}>
|
|
||||||
<div className={s.boxItem}>
|
|
||||||
{data?.map((item,index) => (
|
|
||||||
<div key={index} className={s.item}>
|
|
||||||
<RecipeCard slug={item.slug} imageSrc={item.imageSrc} title={item.title} description={item.description}/>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className={s.recipesPagination}>
|
|
||||||
<PaginationCommon pageSize={DEFAULT_PAGESIZE_RECIPELIST} total={data?.length}/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// skip
|
||||||
|
const firstRender = useRef(true);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
firstRender.current = false
|
||||||
|
const query = { ...DEFAULT_BLOGS_ARGS } as QueryRecipes
|
||||||
|
const page = getPageFromQuery(router.query[QUERY_KEY.PAGE] as string)
|
||||||
|
query.options.skip = page * DEFAULT_BLOG_PAGE_SIZE
|
||||||
|
setOptionQueryBlog(query)
|
||||||
|
setInitialQueryFlag(false)
|
||||||
|
}, [router.query])
|
||||||
|
|
||||||
|
|
||||||
|
let data;
|
||||||
|
if(initialQueryFlag == true){
|
||||||
|
data = recipeList;
|
||||||
|
}else{
|
||||||
|
data = reicpes
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className={s.recipesListWrapper}>
|
||||||
|
<div className={s.breadcrumb}>
|
||||||
|
<BreadcrumbCommon crumbs={BREADCRUMB} />
|
||||||
|
</div>
|
||||||
|
<div className={s.recipesListPageMain}>
|
||||||
|
<div className={s.categories}>
|
||||||
|
<MenuNavigation categories={CATEGORY} heading="Categories" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={s.recipesList}>
|
||||||
|
<HeadingCommon align="left">SPECIAL RECIPES</HeadingCommon>
|
||||||
|
|
||||||
|
<div className={s.boxSelect}>
|
||||||
|
<div className={s.categorySelectCate}>
|
||||||
|
<label htmlFor="">Categories</label>
|
||||||
|
<div className={s.select}>
|
||||||
|
<SelectCommon
|
||||||
|
options={CATEGORYSELECT}
|
||||||
|
placeholder="Categories"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={s.categorySelectSort}>
|
||||||
|
<label htmlFor="">Sort By</label>
|
||||||
|
<div className={s.select}>
|
||||||
|
<SelectCommon options={OPTIONSLECT} placeholder="Sort By" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={s.inner}>
|
||||||
|
<div className={s.boxItem}>
|
||||||
|
{(!initialQueryFlag && loading && !data) && <ListBlogCardSkeleton count={DEFAULT_PAGESIZE_RECIPELIST} isWrap />}
|
||||||
|
{data?.map((item, index) => (
|
||||||
|
<div key={index} className={s.item}>
|
||||||
|
<RecipeCard
|
||||||
|
slug={item.slug}
|
||||||
|
imageSrc={item.imageSrc}
|
||||||
|
title={item.title}
|
||||||
|
description={item.description}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={s.recipesPagination}>
|
||||||
|
<PaginationCommon
|
||||||
|
pageSize={DEFAULT_PAGESIZE_RECIPELIST}
|
||||||
|
total={totalItems !== undefined ? totalItems : total}
|
||||||
|
onChange={onPageChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default RecipesList
|
export default RecipesList
|
||||||
|
@@ -24,9 +24,14 @@ export interface RecipeProps {
|
|||||||
slug: string
|
slug: string
|
||||||
description: string
|
description: string
|
||||||
imageSrc: string
|
imageSrc: string
|
||||||
|
content?: string,
|
||||||
|
imgAuthor?: string,
|
||||||
|
date?: string,
|
||||||
|
authorName?: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BlogProps {
|
export interface BlogProps {
|
||||||
|
id:string,
|
||||||
title: string
|
title: string
|
||||||
slug: string
|
slug: string
|
||||||
description: string
|
description: string
|
||||||
|
Reference in New Issue
Block a user