This commit is contained in:
Quangnhankie
2021-10-18 22:54:55 +07:00
parent 111e831d3d
commit dd31beb260
18 changed files with 236 additions and 54 deletions

View File

@@ -10,7 +10,8 @@ import type {
GetProductOperation,
} from '../types/product'
import type {
GetAllBlogsOperation
GetAllBlogsOperation,
GetFeaturedOperation
} from '../types/blogs'
import type { APIProvider, CommerceAPI } from '.'
import { GetAllCollectionsOperation } from '@commerce/types/collection';
@@ -30,7 +31,8 @@ export const OPERATIONS = [
'getProduct',
'getAllFacets',
'getAllCollections',
'getAllBlogs'
'getAllBlogs',
'getFeaturedBlog'
] as const
export const defaultOperations = OPERATIONS.reduce((ops, k) => {
@@ -149,6 +151,22 @@ export type Operations<P extends APIProvider> = {
getAllBlogs: {
<T extends GetFeaturedOperation>(opts: {
variables?: T['variables']
config?: P['config']
preview?: boolean
}): Promise<T['data']>
<T extends GetFeaturedOperation>(
opts: {
variables?: T['variables']
config?: P['config']
preview?: boolean
} & OperationOptions
): Promise<T['data']>
}
getFeaturedBlog: {
<T extends GetAllBlogsOperation>(opts: {
variables?: T['variables']
config?: P['config']
@@ -165,6 +183,7 @@ export type Operations<P extends APIProvider> = {
}
getProduct: {
<T extends GetProductOperation>(opts: {
variables: T['variables']

View File

@@ -19,8 +19,14 @@ export type GetAllBlogsOperation<T extends BlogsType = BlogsType> = {
variables: {
take?: number
skip?: number
sort?: SearchResultSortParameter
}
}
}
export type GetFeaturedOperation<T extends BlogsType = BlogsType> = {
data: { items: T['items'][] }
variables: {
take?: number
skip?: number
}
}

View File

@@ -12,6 +12,7 @@ import getSiteInfo from './operations/get-site-info'
import login from './operations/login'
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 {}
@@ -44,7 +45,8 @@ const operations = {
getProduct,
getAllFacets,
getAllCollections,
getAllBlogs
getAllBlogs,
getFeaturedBlog
}
export const provider = { config, operations }

View File

@@ -3,7 +3,11 @@ import { Provider, VendureConfig } from '..'
import { GetAllBlogsQuery,BlogList } from '../../schema'
import { getAllBlogsQuery } from '../../utils/queries/get-all-blog-query'
export type BlogVariables = { take?: number,skip?:number }
export type BlogVariables = {
excludeBlogIds?: string[],
take?: number,
skip?:number
}
export default function getAllBlogsOperation({
commerce,
@@ -24,8 +28,10 @@ export default function getAllBlogsOperation({
config?: Partial<VendureConfig>
preview?: boolean
} = {}): Promise<{ blogs: GetAllBlogsQuery | any[] ,totalItems?:number }> {
console.log(vars.excludeBlogIds)
const config = commerce.getConfig(cfg)
const variables = {
excludeBlogIds: vars.excludeBlogIds,
options: {
take: vars.take,
skip: vars.skip,
@@ -34,7 +40,6 @@ export default function getAllBlogsOperation({
const { data } = await config.fetch<GetAllBlogsQuery>(query, {
variables,
})
return {
blogs: data?.blogs?.items?.map((val:BlogList)=>({
id: val.id,
@@ -42,7 +47,11 @@ export default function getAllBlogsOperation({
imageSrc: val.featuredAsset?.preview ?? null,
slug: val.translations[0]?.slug,
description: val.translations[0]?.description,
isHidden: val.isHidden
isPublish: val.isPublish,
isFeatured: val.isFeatured,
authorName: val.authorName,
authorAvatarAsset : val.authorAvatarAsset?.preview,
createdAt: val.createdAt
})),
totalItems: data?.blogs?.totalItems || null
}

View File

@@ -0,0 +1,56 @@
import { OperationContext } from '@commerce/api/operations'
import { Provider, VendureConfig } from '..'
import { GetFeaturedBlogQuery,BlogList } from '../../schema'
import { getFeatuedBlogQuery } from '../../utils/queries/get-featued-query'
export type BlogVariables = {
take?: number,
skip?:number
}
export default function getFeaturedBlogOperation({
commerce,
}: OperationContext<Provider>) {
async function getFeaturedBlog(opts?: {
variables?: BlogVariables
config?: Partial<VendureConfig>
preview?: boolean
}): Promise<{ featuredBlogs: GetFeaturedBlogQuery,totalItems:number }>
async function getFeaturedBlog({
query = getFeatuedBlogQuery,
variables: { ...vars } = {},
config: cfg,
}: {
query?: string
variables?: BlogVariables
config?: Partial<VendureConfig>
preview?: boolean
} = {}): Promise<{ featuredBlogs: GetFeaturedBlogQuery | any[] ,totalItems?:number }> {
const config = commerce.getConfig(cfg)
const variables = {
options: {
take: vars.take,
},
}
const { data } = await config.fetch<GetFeaturedBlogQuery>(query, {
variables,
})
return {
featuredBlogs: data?.featuredBlogs?.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 getFeaturedBlog
}

View File

@@ -2317,11 +2317,12 @@ export type BlogList = Node &{
createdAt: DateTime!
updatedAt: DateTime!
featuredAsset?: Maybe<Asset>
isHidden:Boolean
isPublish:Boolean
translations: Array<BlogTranslation>
authorName: Scalars['String']
authorAvatarAsset:Array<Asset>
authorAvatarAsset:Asset
relevantProducts: Product
isFeatured: Boolean
}
export type BlogTranslation = {
@@ -2342,8 +2343,15 @@ export type GetAllBlogsQuery = PaginatedList & {
'totalItems'
}
}
export type GetFeaturedBlogQuery = PaginatedList & {
featuredBlogs: { __typename?: 'BlogList' } & {
items: Array<{ __typename?: 'Blog' } & BlogList!>,
'totalItems'
}
}
export type QueryBlogs = {
excludeBlogIds:Array,
options: BlogListOptions
}

View File

@@ -1,20 +1,26 @@
export const getAllBlogsQuery = /* GraphQL */ `
query GetBlogs ($options: BlogListOptions){
blogs(options: $options){
totalItems
items {
id
isHidden
featuredAsset {
preview
}
translations {
title
slug
description
content
}
}
query GetBlogs($excludeBlogIds: [ID]!, $options: BlogListOptions) {
blogs(excludeBlogIds: $excludeBlogIds, options: $options) {
totalItems
items {
id
isPublish
isFeatured
authorName
createdAt
authorAvatarAsset{
preview
}
featuredAsset {
preview
}
translations {
title
slug
description
content
}
}
}
}
`

View File

@@ -0,0 +1,25 @@
export const getFeatuedBlogQuery = /* GraphQL */ `
query GetFeaturedBlog($options: BlogListOptions) {
featuredBlogs( options: $options){
items {
id
isPublish
isFeatured
authorName
createdAt
authorAvatarAsset{
preview
}
featuredAsset {
preview
}
translations {
title
slug
description
content
}
}
}
}
`

View File

@@ -3,26 +3,33 @@ import { GetStaticPropsContext } from 'next';
import { Layout } from 'src/components/common';
import { BlogCardProps } from 'src/components/common/CardBlog/CardBlog';
import { BlogBreadCrumb, BlogHeading, BlogsList, FeaturedCardBlog } from 'src/components/modules/blogs';
import { DEFAULT_BLOG_PAGE_SIZE } from "src/utils/constanst.utils";
import { DEFAULT_BLOG_PAGE_SIZE,DEFAULT_FEATURED_BLOG_PAGE_SIZE } from "src/utils/constanst.utils";
import { getAllPromies } from 'src/utils/funtion.utils';
import { PromiseWithKey } from 'src/utils/types.utils';
import { getIdFeaturedBlog } from 'src/utils/funtion.utils';
interface Props {
blogsResult: { blogs: BlogCardProps[] },
blogsResult: { blogs?: BlogCardProps[],featuredBlogs?: BlogCardProps[] },
totalItems: number
}
export default function BlogsPage({blogsResult,totalItems}:Props) {
// let date = new Date(blogsResult?.featuredBlogs[0]?.createdAt ?? '' );
// let fullDate = date.toLocaleString('en-us', { month: 'long' }) + " " + date.getDate()+","+date.getFullYear();
return(
<>
<BlogBreadCrumb />
<BlogHeading />
<FeaturedCardBlog
title={blogsResult.blogs[0].title}
imgSrc={blogsResult.blogs[0].imageSrc ?? ''}
content={blogsResult.blogs[0].description}
/>
{/* <FeaturedCardBlog
title={blogsResult?.featuredBlogs[0]?.title}
imgSrc={blogsResult?.featuredBlogs[0]?.imageSrc ?? ''}
content={blogsResult?.featuredBlogs[0]?.description}
imgAuthor={blogsResult?.featuredBlogs[0]?.authorAvatarAsset}
authorName={blogsResult?.featuredBlogs[0]?.authorName}
date={fullDate}
/> */}
<BlogsList blogList={blogsResult.blogs} total={totalItems} />
</>
)
@@ -39,16 +46,32 @@ export async function getStaticProps({
let props = {} as any;
const {featuredBlogs} = await commerce.getFeaturedBlog({
variables: {
take: DEFAULT_BLOG_PAGE_SIZE
},
config,
preview,
})
// console.log(featuredBlogs[0].id);
// promisesWithKey.push({ key: 'blogsResult', promise: FeaturedBlogPromise })
// Blogs
const idBlog = featuredBlogs[0].id;
const blogsPromise = commerce.getAllBlogs({
variables: {
take: DEFAULT_BLOG_PAGE_SIZE
excludeBlogIds: [idBlog],
take: DEFAULT_BLOG_PAGE_SIZE
},
config,
preview,
})
promisesWithKey.push({ key: 'blogsResult', promise: blogsPromise })
try {
const promises = getAllPromies(promisesWithKey)
@@ -58,7 +81,8 @@ export async function getStaticProps({
props[item.key] = item.keyResult ? rs[index][item.keyResult] : rs[index]
return null
})
props['blogsResult']['featuredBlog'] = featuredBlogs;
return {
props,
revalidate: 60

View File

@@ -56,7 +56,7 @@ export async function getStaticProps({
preview,
})
props.featuredAndDiscountFacetsValue = getAllFacetValuesForFeatuedProducts(facets)
// fresh products
const freshProductvariables: ProductVariables = {}
const freshFacetId = getFreshFacetId(facets)

View File

@@ -6,8 +6,11 @@ import { ImgWithLink } from '..'
import s from './CardBlog.module.scss'
export interface BlogCardProps extends BlogProps {
// todo: edit when intergrate API
isHidden:Boolean
isPublish?:Boolean,
isFeatured?:Boolean,
authorAvatarAsset?:string,
authorName?:string,
createdAt?:string
}
const CardBlog = ({ imageSrc, title, description, slug }: BlogCardProps) => {

View File

@@ -9,4 +9,11 @@
margin-bottom: 1.6rem;
}
}
&.isBlog{
width: 90%;
justify-content: space-between;
div{
min-width: 32rem;
}
}
}

View File

@@ -4,14 +4,15 @@ import s from './ListProductCardSkeleton.module.scss'
type Props = {
count?: number
isWrap?: boolean
isWrap?: boolean,
isBlog?:boolean
}
const ListProductCardSkeleton = ({ count = 3, isWrap }: Props) => {
const ListProductCardSkeleton = ({ count = 3, isWrap,isBlog=false }: Props) => {
return (
<div className={classNames(s.listProductCardSkeleton, { [s.wrap]: isWrap })}>
<div className={classNames(s.listProductCardSkeleton, { [s.wrap]: isWrap }, { [s.isBlog]: isBlog })}>
{
Array.from(Array(count).keys()).map(item => <ProductCardSkeleton key={item} />)
Array.from(Array(count).keys()).map(item => <ProductCardSkeleton key={item} isBlog={isBlog} />)
}
</div>

View File

@@ -1,14 +1,16 @@
import SkeletonImage from "../SkeletonCommon/SkeletonImage/SkeletonImage"
import SkeletonParagraph from "../SkeletonCommon/SkeletonParagraph/SkeletonParagraph"
import s from './ProductCardSkeleton.module.scss'
const ProductCardSkeleton = ({ }) => {
type Props = {
isBlog?:boolean
}
const ProductCardSkeleton = ({isBlog=false }) => {
return (
<div className={s.productCardSkeleton}>
<SkeletonImage />
<div className={s.content}>
<SkeletonParagraph rows={3} />
<SkeletonParagraph rows={isBlog ? 2 : 3} />
</div>
</div>
)

View File

@@ -5,7 +5,7 @@ import useSWR from 'swr'
const useGetBlogList = (options?: QueryBlogs) => {
const { data, isValidating, ...rest } = useSWR<GetAllBlogsQuery>([getAllBlogsQuery, options], gglFetcher)
console.log(isValidating);
return {
blogs: data?.blogs?.items?.map((val:BlogList)=>({
id: val.id,
@@ -13,7 +13,11 @@ const useGetBlogList = (options?: QueryBlogs) => {
imageSrc: val.featuredAsset?.preview ?? null,
slug: val.translations[0]?.slug,
description: val.translations[0]?.description,
isHidden: val.isHidden
isPublish: val.isPublish,
isFeatured:val.isFeatured,
authorName: val.authorName,
authorAvatarAsset : val.authorAvatarAsset?.preview,
createdAt: val.createdAt
})),
totalItems: data?.blogs?.totalItems || null,
loading: isValidating,

View File

@@ -15,19 +15,20 @@ interface BlogsListProps {
}
const DEFAULT_BLOGS_ARGS = {
excludeBlogIds: ["28"],
options:{
skip: 1, take: DEFAULT_BLOG_PAGE_SIZE
}
}
const BlogsList = ({ blogList,total }:BlogsListProps) => {
const router = useRouter();
const [initialQueryFlag, setInitialQueryFlag] = useState<boolean>(true)
const [optionQueryBlog, setOptionQueryBlog] = useState<QueryBlogs>(DEFAULT_BLOGS_ARGS)
const { blogs, totalItems, loading } = useGetBlogList(optionQueryBlog);
// console.log(blogs);
const onPageChange = (page:number) => {
@@ -49,7 +50,7 @@ const BlogsList = ({ blogList,total }:BlogsListProps) => {
query.options.skip = page * DEFAULT_BLOG_PAGE_SIZE;
setOptionQueryBlog(query);
setInitialQueryFlag(false);
console.log(query)
},[router.query])
@@ -59,18 +60,19 @@ const BlogsList = ({ blogList,total }:BlogsListProps) => {
}else{
data = blogs
}
console.log(blogList);
return (
<section>
<div className={s.wrapper}>
{(!initialQueryFlag && loading && !blogs) && <ListProductCardSkeleton count={DEFAULT_BLOG_PAGE_SIZE} isWrap />}
{(!initialQueryFlag && loading && !blogs) && <ListProductCardSkeleton count={DEFAULT_BLOG_PAGE_SIZE} isWrap isBlog={true} />}
<div className={s.list}>
{
data?.map((product,index)=> {
return(
<div className={s.card} key={`${product.title}-${index}`}>
{!product.isHidden && <CardBlog {...product} /> }
{product.isPublish && <CardBlog {...product} /> }
</div>
)
})

View File

@@ -171,6 +171,8 @@ export const FEATURED = [
export const DEFAULT_BLOG_PAGE_SIZE = 6;
export const DEFAULT_FEATURED_BLOG_PAGE_SIZE = 1;
export const FILTER_PAGE = [ROUTE.HOME, ROUTE.PRODUCTS]
export const STATE_OPTIONS = [

View File

@@ -1,3 +1,4 @@
import { BlogList } from '@framework/schema';
import { Facet } from "@commerce/types/facet";
import { Collection, FacetValue, SearchResultSortParameter } from './../../framework/vendure/schema.d';
import { CODE_FACET_DISCOUNT, CODE_FACET_FEATURED, CODE_FACET_FEATURED_VARIANT, PRODUCT_SORT_OPTION_VALUE } from "./constanst.utils";
@@ -127,4 +128,9 @@ export const getCategoryNameFromCollectionId = (colelctions: Collection[], colle
export function getAllPromies(promies: PromiseWithKey[]) {
return promies.map(item => item.promise)
}
}
export function getIdFeaturedBlog(blog: BlogList) {
return blog?.id
}