mirror of
https://github.com/vercel/commerce.git
synced 2025-05-16 14:36:59 +00:00
Static content done
This commit is contained in:
parent
a8e49ee3f4
commit
8fc54664da
@ -4,11 +4,14 @@ documents: 'lib/**/*.graphql'
|
||||
generates:
|
||||
lib/saleor/generated/:
|
||||
preset: 'client'
|
||||
presetConfig:
|
||||
fragmentMasking: false
|
||||
config:
|
||||
defaultScalarType: 'unknown'
|
||||
useTypeImports: true
|
||||
dedupeFragments: true
|
||||
skipTypename: true
|
||||
documentMode: 'string'
|
||||
scalars:
|
||||
_Any: 'unknown'
|
||||
Date: 'string'
|
||||
|
78
lib/saleor/editorjs.ts
Normal file
78
lib/saleor/editorjs.ts
Normal file
@ -0,0 +1,78 @@
|
||||
import { invariant } from './utils';
|
||||
|
||||
type EditorJsHeaderBlock = {
|
||||
type: 'header';
|
||||
data: { text: string; level: 1 | 2 | 3 | 4 | 5 | 6 };
|
||||
};
|
||||
type EditorJsParagraphBlock = { type: 'paragraph'; data: { text: string } };
|
||||
type EditorJsListBlock = {
|
||||
type: 'list';
|
||||
data: { style: 'unordered' | 'ordered'; items: string[] };
|
||||
};
|
||||
|
||||
type EditorJsBlockCommon = { id: string };
|
||||
type EditorJsBlocks = EditorJsHeaderBlock | EditorJsParagraphBlock | EditorJsListBlock;
|
||||
|
||||
type EditorJsBlock = EditorJsBlocks & EditorJsBlockCommon;
|
||||
|
||||
interface EditorJsResponse {
|
||||
blocks: readonly EditorJsBlock[];
|
||||
time: number;
|
||||
version: string;
|
||||
}
|
||||
|
||||
const parseEditorJson = (content: string): EditorJsResponse | null => {
|
||||
try {
|
||||
const data: EditorJsResponse = JSON.parse(content);
|
||||
// manually validate it has more or less proper shape
|
||||
invariant(data && 'blocks' in data, `Invalid shape`);
|
||||
invariant(Array.isArray(data.blocks), `Invalid shape`);
|
||||
invariant(
|
||||
data.blocks.every((item) => 'type' in item && 'data' in item),
|
||||
`Invalid shape`
|
||||
);
|
||||
return data;
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
export const parseEditorJsToHtml = (content: string) => {
|
||||
const data = parseEditorJson(content);
|
||||
if (!data) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const html = data.blocks
|
||||
.map((block) => {
|
||||
switch (block.type) {
|
||||
case 'header':
|
||||
return header(block.data);
|
||||
case 'list':
|
||||
return list(block.data);
|
||||
case 'paragraph':
|
||||
return paragraph(block.data);
|
||||
default:
|
||||
console.warn(`Unknown block type: ${JSON.stringify(block)}`);
|
||||
return '';
|
||||
}
|
||||
})
|
||||
.join('');
|
||||
|
||||
return html;
|
||||
};
|
||||
|
||||
function list(data: EditorJsListBlock['data']): string {
|
||||
const el = data.style === 'ordered' ? 'ul' : 'ol';
|
||||
const items = data.items.map((item) => `<li>${item}</li>`).join('');
|
||||
return `<${el}>${items}</${el}>`;
|
||||
}
|
||||
|
||||
function paragraph({ text }: EditorJsParagraphBlock['data']): string {
|
||||
return `<p>${text}</p>`;
|
||||
}
|
||||
|
||||
function header({ level, text }: EditorJsHeaderBlock['data']): string {
|
||||
return `<h${level}>${text}</h${level}>`;
|
||||
}
|
@ -1,6 +1,5 @@
|
||||
/* eslint-disable */
|
||||
import * as types from './graphql';
|
||||
import type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core';
|
||||
|
||||
/**
|
||||
* Map of all GraphQL operations in the project.
|
||||
@ -15,6 +14,10 @@ import type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-
|
||||
const documents = {
|
||||
'fragment FeaturedProduct on Product {\n id\n slug\n name\n isAvailableForPurchase\n description\n seoTitle\n seoDescription\n pricing {\n priceRange {\n start {\n gross {\n currency\n amount\n }\n }\n stop {\n gross {\n currency\n amount\n }\n }\n }\n }\n media {\n url(size: 2160)\n type\n alt\n }\n collections {\n name\n }\n updatedAt\n variants {\n id\n name\n pricing {\n price {\n gross {\n currency\n amount\n }\n }\n }\n }\n}':
|
||||
types.FeaturedProductFragmentDoc,
|
||||
'query GetCategoryBySlug($slug: String!) {\n category(slug: $slug) {\n id\n name\n slug\n description\n seoTitle\n seoDescription\n }\n}':
|
||||
types.GetCategoryBySlugDocument,
|
||||
'query GetCategoryProductsBySlug($slug: String!) {\n category(slug: $slug) {\n products(channel: "default-channel", first: 100) {\n edges {\n node {\n id\n slug\n name\n isAvailableForPurchase\n description\n seoTitle\n seoDescription\n pricing {\n priceRange {\n start {\n gross {\n currency\n amount\n }\n }\n stop {\n gross {\n currency\n amount\n }\n }\n }\n }\n media {\n url(size: 2160)\n type\n alt\n }\n collections {\n name\n }\n updatedAt\n variants {\n id\n name\n pricing {\n price {\n gross {\n currency\n amount\n }\n }\n }\n }\n }\n }\n }\n }\n}':
|
||||
types.GetCategoryProductsBySlugDocument,
|
||||
'query GetCollectionBySlug($slug: String!) {\n collection(channel: "default-channel", slug: $slug) {\n id\n name\n slug\n description\n seoTitle\n seoDescription\n }\n}':
|
||||
types.GetCollectionBySlugDocument,
|
||||
'query GetCollectionProductsBySlug($slug: String!) {\n collection(channel: "default-channel", slug: $slug) {\n products(first: 100) {\n edges {\n node {\n id\n slug\n name\n isAvailableForPurchase\n description\n seoTitle\n seoDescription\n pricing {\n priceRange {\n start {\n gross {\n currency\n amount\n }\n }\n stop {\n gross {\n currency\n amount\n }\n }\n }\n }\n media {\n url(size: 2160)\n type\n alt\n }\n collections {\n name\n }\n updatedAt\n variants {\n id\n name\n pricing {\n price {\n gross {\n currency\n amount\n }\n }\n }\n }\n }\n }\n }\n }\n}':
|
||||
@ -23,11 +26,13 @@ const documents = {
|
||||
types.GetCollectionsDocument,
|
||||
'query GetFeaturedProducts($first: Int!) {\n products(first: $first, channel: "default-channel") {\n edges {\n node {\n ...FeaturedProduct\n }\n }\n }\n}':
|
||||
types.GetFeaturedProductsDocument,
|
||||
'query GetMenuBySlug($slug: String!) {\n menu(slug: $slug, channel: "default-channel") {\n id\n slug\n name\n items {\n id\n name\n url\n collection {\n slug\n }\n children {\n id\n collection {\n slug\n }\n }\n }\n }\n}':
|
||||
types.GetMenuBySlugDocument,
|
||||
'fragment MenuItem on MenuItem {\n id\n name\n url\n collection {\n slug\n }\n category {\n slug\n }\n page {\n slug\n }\n}\n\nquery GetMenuBySlug($slug: String!) {\n menu(slug: $slug, channel: "default-channel") {\n id\n slug\n name\n items {\n ...MenuItem\n children {\n ...MenuItem\n children {\n ...MenuItem\n children {\n ...MenuItem\n }\n }\n }\n }\n }\n}':
|
||||
types.MenuItemFragmentDoc,
|
||||
'query GetPageBySlug($slug: String!) {\n page(slug: $slug) {\n id\n title\n slug\n content\n seoTitle\n seoDescription\n created\n }\n}':
|
||||
types.GetPageBySlugDocument,
|
||||
'query GetProductBySlug($slug: String!) {\n product(slug: $slug) {\n id\n slug\n name\n isAvailableForPurchase\n description\n seoTitle\n seoDescription\n pricing {\n priceRange {\n start {\n gross {\n currency\n amount\n }\n }\n stop {\n gross {\n currency\n amount\n }\n }\n }\n }\n media {\n url(size: 2160)\n type\n alt\n }\n collections {\n name\n }\n updatedAt\n variants {\n id\n name\n pricing {\n price {\n gross {\n currency\n amount\n }\n }\n }\n }\n }\n}':
|
||||
'query GetPages {\n pages(first: 10) {\n edges {\n node {\n id\n title\n slug\n content\n seoTitle\n seoDescription\n created\n }\n }\n }\n}':
|
||||
types.GetPagesDocument,
|
||||
'query GetProductBySlug($slug: String!) {\n product(channel: "default-channel", slug: $slug) {\n id\n slug\n name\n isAvailableForPurchase\n description\n seoTitle\n seoDescription\n pricing {\n priceRange {\n start {\n gross {\n currency\n amount\n }\n }\n stop {\n gross {\n currency\n amount\n }\n }\n }\n }\n media {\n url(size: 2160)\n type\n alt\n }\n collections {\n name\n }\n updatedAt\n variants {\n id\n name\n pricing {\n price {\n gross {\n currency\n amount\n }\n }\n }\n }\n }\n}':
|
||||
types.GetProductBySlugDocument,
|
||||
'query SearchProducts($search: String!, $sortBy: ProductOrderField!, $sortDirection: OrderDirection!) {\n products(\n first: 100\n channel: "default-channel"\n sortBy: {field: $sortBy, direction: $sortDirection}\n filter: {search: $search}\n ) {\n edges {\n node {\n id\n slug\n name\n isAvailableForPurchase\n description\n seoTitle\n seoDescription\n pricing {\n priceRange {\n start {\n gross {\n currency\n amount\n }\n }\n stop {\n gross {\n currency\n amount\n }\n }\n }\n }\n media {\n url(size: 2160)\n type\n alt\n }\n collections {\n name\n }\n updatedAt\n variants {\n id\n name\n pricing {\n price {\n gross {\n currency\n amount\n }\n }\n }\n }\n }\n }\n }\n}':
|
||||
types.SearchProductsDocument,
|
||||
@ -37,82 +42,83 @@ const documents = {
|
||||
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* const query = graphql(`query GetUser($id: ID!) { user(id: $id) { name } }`);
|
||||
* ```
|
||||
*
|
||||
* The query argument is unknown!
|
||||
* Please regenerate the types.
|
||||
*/
|
||||
export function graphql(source: string): unknown;
|
||||
|
||||
export function graphql(
|
||||
source: 'fragment FeaturedProduct on Product {\n id\n slug\n name\n isAvailableForPurchase\n description\n seoTitle\n seoDescription\n pricing {\n priceRange {\n start {\n gross {\n currency\n amount\n }\n }\n stop {\n gross {\n currency\n amount\n }\n }\n }\n }\n media {\n url(size: 2160)\n type\n alt\n }\n collections {\n name\n }\n updatedAt\n variants {\n id\n name\n pricing {\n price {\n gross {\n currency\n amount\n }\n }\n }\n }\n}'
|
||||
): typeof import('./graphql').FeaturedProductFragmentDoc;
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(
|
||||
source: 'fragment FeaturedProduct on Product {\n id\n slug\n name\n isAvailableForPurchase\n description\n seoTitle\n seoDescription\n pricing {\n priceRange {\n start {\n gross {\n currency\n amount\n }\n }\n stop {\n gross {\n currency\n amount\n }\n }\n }\n }\n media {\n url(size: 2160)\n type\n alt\n }\n collections {\n name\n }\n updatedAt\n variants {\n id\n name\n pricing {\n price {\n gross {\n currency\n amount\n }\n }\n }\n }\n}'
|
||||
): (typeof documents)['fragment FeaturedProduct on Product {\n id\n slug\n name\n isAvailableForPurchase\n description\n seoTitle\n seoDescription\n pricing {\n priceRange {\n start {\n gross {\n currency\n amount\n }\n }\n stop {\n gross {\n currency\n amount\n }\n }\n }\n }\n media {\n url(size: 2160)\n type\n alt\n }\n collections {\n name\n }\n updatedAt\n variants {\n id\n name\n pricing {\n price {\n gross {\n currency\n amount\n }\n }\n }\n }\n}'];
|
||||
source: 'query GetCategoryBySlug($slug: String!) {\n category(slug: $slug) {\n id\n name\n slug\n description\n seoTitle\n seoDescription\n }\n}'
|
||||
): typeof import('./graphql').GetCategoryBySlugDocument;
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(
|
||||
source: 'query GetCategoryProductsBySlug($slug: String!) {\n category(slug: $slug) {\n products(channel: "default-channel", first: 100) {\n edges {\n node {\n id\n slug\n name\n isAvailableForPurchase\n description\n seoTitle\n seoDescription\n pricing {\n priceRange {\n start {\n gross {\n currency\n amount\n }\n }\n stop {\n gross {\n currency\n amount\n }\n }\n }\n }\n media {\n url(size: 2160)\n type\n alt\n }\n collections {\n name\n }\n updatedAt\n variants {\n id\n name\n pricing {\n price {\n gross {\n currency\n amount\n }\n }\n }\n }\n }\n }\n }\n }\n}'
|
||||
): typeof import('./graphql').GetCategoryProductsBySlugDocument;
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(
|
||||
source: 'query GetCollectionBySlug($slug: String!) {\n collection(channel: "default-channel", slug: $slug) {\n id\n name\n slug\n description\n seoTitle\n seoDescription\n }\n}'
|
||||
): (typeof documents)['query GetCollectionBySlug($slug: String!) {\n collection(channel: "default-channel", slug: $slug) {\n id\n name\n slug\n description\n seoTitle\n seoDescription\n }\n}'];
|
||||
): typeof import('./graphql').GetCollectionBySlugDocument;
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(
|
||||
source: 'query GetCollectionProductsBySlug($slug: String!) {\n collection(channel: "default-channel", slug: $slug) {\n products(first: 100) {\n edges {\n node {\n id\n slug\n name\n isAvailableForPurchase\n description\n seoTitle\n seoDescription\n pricing {\n priceRange {\n start {\n gross {\n currency\n amount\n }\n }\n stop {\n gross {\n currency\n amount\n }\n }\n }\n }\n media {\n url(size: 2160)\n type\n alt\n }\n collections {\n name\n }\n updatedAt\n variants {\n id\n name\n pricing {\n price {\n gross {\n currency\n amount\n }\n }\n }\n }\n }\n }\n }\n }\n}'
|
||||
): (typeof documents)['query GetCollectionProductsBySlug($slug: String!) {\n collection(channel: "default-channel", slug: $slug) {\n products(first: 100) {\n edges {\n node {\n id\n slug\n name\n isAvailableForPurchase\n description\n seoTitle\n seoDescription\n pricing {\n priceRange {\n start {\n gross {\n currency\n amount\n }\n }\n stop {\n gross {\n currency\n amount\n }\n }\n }\n }\n media {\n url(size: 2160)\n type\n alt\n }\n collections {\n name\n }\n updatedAt\n variants {\n id\n name\n pricing {\n price {\n gross {\n currency\n amount\n }\n }\n }\n }\n }\n }\n }\n }\n}'];
|
||||
): typeof import('./graphql').GetCollectionProductsBySlugDocument;
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(
|
||||
source: 'query GetCollections {\n collections(channel: "default-channel", first: 100) {\n edges {\n node {\n id\n name\n slug\n description\n seoTitle\n seoDescription\n }\n }\n }\n}'
|
||||
): (typeof documents)['query GetCollections {\n collections(channel: "default-channel", first: 100) {\n edges {\n node {\n id\n name\n slug\n description\n seoTitle\n seoDescription\n }\n }\n }\n}'];
|
||||
): typeof import('./graphql').GetCollectionsDocument;
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(
|
||||
source: 'query GetFeaturedProducts($first: Int!) {\n products(first: $first, channel: "default-channel") {\n edges {\n node {\n ...FeaturedProduct\n }\n }\n }\n}'
|
||||
): (typeof documents)['query GetFeaturedProducts($first: Int!) {\n products(first: $first, channel: "default-channel") {\n edges {\n node {\n ...FeaturedProduct\n }\n }\n }\n}'];
|
||||
): typeof import('./graphql').GetFeaturedProductsDocument;
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(
|
||||
source: 'query GetMenuBySlug($slug: String!) {\n menu(slug: $slug, channel: "default-channel") {\n id\n slug\n name\n items {\n id\n name\n url\n collection {\n slug\n }\n children {\n id\n collection {\n slug\n }\n }\n }\n }\n}'
|
||||
): (typeof documents)['query GetMenuBySlug($slug: String!) {\n menu(slug: $slug, channel: "default-channel") {\n id\n slug\n name\n items {\n id\n name\n url\n collection {\n slug\n }\n children {\n id\n collection {\n slug\n }\n }\n }\n }\n}'];
|
||||
source: 'fragment MenuItem on MenuItem {\n id\n name\n url\n collection {\n slug\n }\n category {\n slug\n }\n page {\n slug\n }\n}\n\nquery GetMenuBySlug($slug: String!) {\n menu(slug: $slug, channel: "default-channel") {\n id\n slug\n name\n items {\n ...MenuItem\n children {\n ...MenuItem\n children {\n ...MenuItem\n children {\n ...MenuItem\n }\n }\n }\n }\n }\n}'
|
||||
): typeof import('./graphql').MenuItemFragmentDoc;
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(
|
||||
source: 'query GetPageBySlug($slug: String!) {\n page(slug: $slug) {\n id\n title\n slug\n content\n seoTitle\n seoDescription\n created\n }\n}'
|
||||
): (typeof documents)['query GetPageBySlug($slug: String!) {\n page(slug: $slug) {\n id\n title\n slug\n content\n seoTitle\n seoDescription\n created\n }\n}'];
|
||||
): typeof import('./graphql').GetPageBySlugDocument;
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(
|
||||
source: 'query GetProductBySlug($slug: String!) {\n product(slug: $slug) {\n id\n slug\n name\n isAvailableForPurchase\n description\n seoTitle\n seoDescription\n pricing {\n priceRange {\n start {\n gross {\n currency\n amount\n }\n }\n stop {\n gross {\n currency\n amount\n }\n }\n }\n }\n media {\n url(size: 2160)\n type\n alt\n }\n collections {\n name\n }\n updatedAt\n variants {\n id\n name\n pricing {\n price {\n gross {\n currency\n amount\n }\n }\n }\n }\n }\n}'
|
||||
): (typeof documents)['query GetProductBySlug($slug: String!) {\n product(slug: $slug) {\n id\n slug\n name\n isAvailableForPurchase\n description\n seoTitle\n seoDescription\n pricing {\n priceRange {\n start {\n gross {\n currency\n amount\n }\n }\n stop {\n gross {\n currency\n amount\n }\n }\n }\n }\n media {\n url(size: 2160)\n type\n alt\n }\n collections {\n name\n }\n updatedAt\n variants {\n id\n name\n pricing {\n price {\n gross {\n currency\n amount\n }\n }\n }\n }\n }\n}'];
|
||||
source: 'query GetPages {\n pages(first: 10) {\n edges {\n node {\n id\n title\n slug\n content\n seoTitle\n seoDescription\n created\n }\n }\n }\n}'
|
||||
): typeof import('./graphql').GetPagesDocument;
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(
|
||||
source: 'query GetProductBySlug($slug: String!) {\n product(channel: "default-channel", slug: $slug) {\n id\n slug\n name\n isAvailableForPurchase\n description\n seoTitle\n seoDescription\n pricing {\n priceRange {\n start {\n gross {\n currency\n amount\n }\n }\n stop {\n gross {\n currency\n amount\n }\n }\n }\n }\n media {\n url(size: 2160)\n type\n alt\n }\n collections {\n name\n }\n updatedAt\n variants {\n id\n name\n pricing {\n price {\n gross {\n currency\n amount\n }\n }\n }\n }\n }\n}'
|
||||
): typeof import('./graphql').GetProductBySlugDocument;
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(
|
||||
source: 'query SearchProducts($search: String!, $sortBy: ProductOrderField!, $sortDirection: OrderDirection!) {\n products(\n first: 100\n channel: "default-channel"\n sortBy: {field: $sortBy, direction: $sortDirection}\n filter: {search: $search}\n ) {\n edges {\n node {\n id\n slug\n name\n isAvailableForPurchase\n description\n seoTitle\n seoDescription\n pricing {\n priceRange {\n start {\n gross {\n currency\n amount\n }\n }\n stop {\n gross {\n currency\n amount\n }\n }\n }\n }\n media {\n url(size: 2160)\n type\n alt\n }\n collections {\n name\n }\n updatedAt\n variants {\n id\n name\n pricing {\n price {\n gross {\n currency\n amount\n }\n }\n }\n }\n }\n }\n }\n}'
|
||||
): (typeof documents)['query SearchProducts($search: String!, $sortBy: ProductOrderField!, $sortDirection: OrderDirection!) {\n products(\n first: 100\n channel: "default-channel"\n sortBy: {field: $sortBy, direction: $sortDirection}\n filter: {search: $search}\n ) {\n edges {\n node {\n id\n slug\n name\n isAvailableForPurchase\n description\n seoTitle\n seoDescription\n pricing {\n priceRange {\n start {\n gross {\n currency\n amount\n }\n }\n stop {\n gross {\n currency\n amount\n }\n }\n }\n }\n media {\n url(size: 2160)\n type\n alt\n }\n collections {\n name\n }\n updatedAt\n variants {\n id\n name\n pricing {\n price {\n gross {\n currency\n amount\n }\n }\n }\n }\n }\n }\n }\n}'];
|
||||
): typeof import('./graphql').SearchProductsDocument;
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(
|
||||
source: 'query GetProducts {\n products(first: 10, channel: "default-channel") {\n edges {\n node {\n name\n }\n }\n }\n}'
|
||||
): (typeof documents)['query GetProducts {\n products(first: 10, channel: "default-channel") {\n edges {\n node {\n name\n }\n }\n }\n}'];
|
||||
): typeof import('./graphql').GetProductsDocument;
|
||||
|
||||
export function graphql(source: string) {
|
||||
return (documents as any)[source] ?? {};
|
||||
}
|
||||
|
||||
export type DocumentType<TDocumentNode extends DocumentNode<any, any>> =
|
||||
TDocumentNode extends DocumentNode<infer TType, any> ? TType : never;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,2 +1 @@
|
||||
export * from './fragment-masking';
|
||||
export * from './gql';
|
||||
|
@ -1,16 +1,20 @@
|
||||
import type { TypedDocumentNode } from '@graphql-typed-document-node/core';
|
||||
import { print } from 'graphql';
|
||||
import { Collection, Menu, Page, Product } from 'lib/types';
|
||||
import { Cart, Collection, Menu, Page, Product } from 'lib/types';
|
||||
import { parseEditorJsToHtml } from './editorjs';
|
||||
import {
|
||||
GetCategoryBySlugDocument,
|
||||
GetCategoryProductsBySlugDocument,
|
||||
GetCollectionBySlugDocument,
|
||||
GetCollectionProductsBySlugDocument,
|
||||
GetCollectionsDocument,
|
||||
GetMenuBySlugDocument,
|
||||
GetPageBySlugDocument,
|
||||
GetPagesDocument,
|
||||
GetProductBySlugDocument,
|
||||
MenuItemFragment,
|
||||
OrderDirection,
|
||||
ProductOrderField,
|
||||
SearchProductsDocument
|
||||
SearchProductsDocument,
|
||||
TypedDocumentString
|
||||
} from './generated/graphql';
|
||||
import { invariant } from './utils';
|
||||
|
||||
@ -28,7 +32,7 @@ export async function saleorFetch<Result, Variables>({
|
||||
headers,
|
||||
cache = 'force-cache'
|
||||
}: {
|
||||
query: TypedDocumentNode<Result, Variables>;
|
||||
query: TypedDocumentString<Result, Variables>;
|
||||
variables: Variables;
|
||||
headers?: HeadersInit;
|
||||
cache?: RequestCache;
|
||||
@ -42,7 +46,7 @@ export async function saleorFetch<Result, Variables>({
|
||||
...headers
|
||||
},
|
||||
body: JSON.stringify({
|
||||
query: print(query),
|
||||
query: query.toString(),
|
||||
...(variables && { variables })
|
||||
}),
|
||||
cache,
|
||||
@ -138,7 +142,9 @@ export async function getProduct(handle: string): Promise<Product | undefined> {
|
||||
availableForSale: saleorProduct.product.isAvailableForPurchase || true,
|
||||
title: saleorProduct.product.name,
|
||||
description: saleorProduct.product.description || '',
|
||||
descriptionHtml: saleorProduct.product.description || '', // @todo
|
||||
descriptionHtml: saleorProduct.product.description
|
||||
? parseEditorJsToHtml(saleorProduct.product.description)
|
||||
: '',
|
||||
options: [], // @todo
|
||||
priceRange: {
|
||||
maxVariantPrice: {
|
||||
@ -174,50 +180,78 @@ export async function getProduct(handle: string): Promise<Product | undefined> {
|
||||
};
|
||||
}
|
||||
|
||||
export async function getCollection(handle: string): Promise<Collection | undefined> {
|
||||
const saleorCollection = await saleorFetch({
|
||||
const _getCollection = async (handle: string) =>
|
||||
(
|
||||
await saleorFetch({
|
||||
query: GetCollectionBySlugDocument,
|
||||
variables: {
|
||||
slug: handle
|
||||
}
|
||||
});
|
||||
})
|
||||
).collection;
|
||||
const _getCategory = async (handle: string) =>
|
||||
(
|
||||
await saleorFetch({
|
||||
query: GetCategoryBySlugDocument,
|
||||
variables: {
|
||||
slug: handle
|
||||
}
|
||||
})
|
||||
).category;
|
||||
|
||||
if (!saleorCollection.collection) {
|
||||
export async function getCollection(handle: string): Promise<Collection | undefined> {
|
||||
const saleorCollection = (await _getCollection(handle)) || (await _getCategory(handle));
|
||||
|
||||
if (!saleorCollection) {
|
||||
throw new Error(`Collection not found: ${handle}`);
|
||||
}
|
||||
|
||||
return {
|
||||
handle: saleorCollection.collection.slug,
|
||||
title: saleorCollection.collection.name,
|
||||
description: saleorCollection.collection.description as string,
|
||||
handle: saleorCollection.slug,
|
||||
title: saleorCollection.name,
|
||||
description: saleorCollection.description as string,
|
||||
seo: {
|
||||
title: saleorCollection.collection.seoTitle || saleorCollection.collection.name,
|
||||
description: saleorCollection.collection.seoDescription || ''
|
||||
title: saleorCollection.seoTitle || saleorCollection.name,
|
||||
description: saleorCollection.seoDescription || ''
|
||||
},
|
||||
updatedAt: '', // @todo ?
|
||||
path: `/search/${saleorCollection.collection.slug}`
|
||||
path: `/search/${saleorCollection.slug}`
|
||||
};
|
||||
}
|
||||
|
||||
export async function getCollectionProducts(handle: string): Promise<Product[]> {
|
||||
const handleToSlug: Record<string, string> = {
|
||||
'hidden-homepage-featured-items': 'featured',
|
||||
'hidden-homepage-carousel': 'all-products'
|
||||
};
|
||||
|
||||
const saleorCollectionProducts = await saleorFetch({
|
||||
const _getCollectionProducts = async (handle: string) =>
|
||||
(
|
||||
await saleorFetch({
|
||||
query: GetCollectionProductsBySlugDocument,
|
||||
variables: {
|
||||
slug: handleToSlug[handle] || handle
|
||||
}
|
||||
});
|
||||
})
|
||||
).collection;
|
||||
const _getCategoryProducts = async (handle: string) =>
|
||||
(
|
||||
await saleorFetch({
|
||||
query: GetCategoryProductsBySlugDocument,
|
||||
variables: {
|
||||
slug: handleToSlug[handle] || handle
|
||||
}
|
||||
})
|
||||
).category;
|
||||
|
||||
if (!saleorCollectionProducts.collection) {
|
||||
export async function getCollectionProducts(handle: string): Promise<Product[]> {
|
||||
const saleorCollectionProducts =
|
||||
(await _getCollectionProducts(handle)) || (await _getCategoryProducts(handle));
|
||||
|
||||
if (!saleorCollectionProducts) {
|
||||
throw new Error(`Collection not found: ${handle}`);
|
||||
}
|
||||
|
||||
return (
|
||||
saleorCollectionProducts.collection.products?.edges.map((product) => {
|
||||
saleorCollectionProducts.products?.edges.map((product) => {
|
||||
const images =
|
||||
product.node.media
|
||||
?.filter((media) => media.type === 'IMAGE')
|
||||
@ -236,7 +270,9 @@ export async function getCollectionProducts(handle: string): Promise<Product[]>
|
||||
availableForSale: product.node.isAvailableForPurchase || true,
|
||||
title: product.node.name,
|
||||
description: product.node.description || '',
|
||||
descriptionHtml: product.node.description || '', // @todo
|
||||
descriptionHtml: product.node.description
|
||||
? parseEditorJsToHtml(product.node.description)
|
||||
: '',
|
||||
options: [], // @todo
|
||||
priceRange: {
|
||||
maxVariantPrice: {
|
||||
@ -291,12 +327,47 @@ export async function getMenu(handle: string): Promise<Menu[]> {
|
||||
throw new Error(`Menu not found: ${handle}`);
|
||||
}
|
||||
|
||||
const result = flattenMenuItems(saleorMenu.menu.items);
|
||||
|
||||
return (
|
||||
saleorMenu.menu.items?.map((item) => {
|
||||
return {
|
||||
path: item.url || '', // @todo handle manus without url
|
||||
title: item.name
|
||||
result
|
||||
.filter(
|
||||
(menu) =>
|
||||
menu.path &&
|
||||
// manually removing empty categories
|
||||
// @todo ?
|
||||
menu.path !== '/search/paints' &&
|
||||
menu.path !== '/search/juices' &&
|
||||
menu.path !== '/search/alcohol' &&
|
||||
menu.path !== '/search/homewares' &&
|
||||
menu.path !== '/search/groceries'
|
||||
)
|
||||
// unique by path
|
||||
.filter((item1, idx, arr) => arr.findIndex((item2) => item2.path === item1.path) === idx)
|
||||
.slice(0, 3)
|
||||
);
|
||||
}
|
||||
|
||||
type MenuItemWithChildren = MenuItemFragment & {
|
||||
children?: null | undefined | MenuItemWithChildren[];
|
||||
};
|
||||
function flattenMenuItems(menuItems: null | undefined | MenuItemWithChildren[]): Menu[] {
|
||||
return (
|
||||
menuItems?.flatMap((item) => {
|
||||
const path =
|
||||
item.url ||
|
||||
(item.collection
|
||||
? `/search/${item.collection.slug}`
|
||||
: item.category
|
||||
? `/search/${item.category.slug}`
|
||||
: '');
|
||||
return [
|
||||
{
|
||||
path: path,
|
||||
title: item.name
|
||||
},
|
||||
...flattenMenuItems(item.children)
|
||||
];
|
||||
}) || []
|
||||
);
|
||||
}
|
||||
@ -339,7 +410,9 @@ export async function getProducts({
|
||||
availableForSale: product.node.isAvailableForPurchase || true,
|
||||
title: product.node.name,
|
||||
description: product.node.description || '',
|
||||
descriptionHtml: product.node.description || '', // @todo
|
||||
descriptionHtml: product.node.description
|
||||
? parseEditorJsToHtml(product.node.description)
|
||||
: '',
|
||||
options: [], // @todo
|
||||
priceRange: {
|
||||
maxVariantPrice: {
|
||||
@ -376,3 +449,41 @@ export async function getProducts({
|
||||
}) || []
|
||||
);
|
||||
}
|
||||
|
||||
export async function getPages(): Promise<Page[]> {
|
||||
const saleorPages = await saleorFetch({
|
||||
query: GetPagesDocument,
|
||||
variables: {}
|
||||
});
|
||||
|
||||
return (
|
||||
saleorPages.pages?.edges.map((page) => {
|
||||
return {
|
||||
id: page.node.id,
|
||||
title: page.node.title,
|
||||
handle: page.node.slug,
|
||||
body: page.node.content || '',
|
||||
bodySummary: page.node.seoDescription || '',
|
||||
seo: {
|
||||
title: page.node.seoTitle || page.node.title,
|
||||
description: page.node.seoDescription || ''
|
||||
},
|
||||
createdAt: page.node.created,
|
||||
updatedAt: page.node.created
|
||||
};
|
||||
}) || []
|
||||
);
|
||||
}
|
||||
|
||||
export async function getCart(cartId: string): Promise<Cart | null> {
|
||||
// @todo
|
||||
return null;
|
||||
}
|
||||
export async function createCart(): Promise<Cart> {
|
||||
// @todo
|
||||
throw new Error(`Not implemented`);
|
||||
}
|
||||
export async function getProductRecommendations(productId: string): Promise<Product[]> {
|
||||
// @todo
|
||||
return [];
|
||||
}
|
||||
|
10
lib/saleor/queries/GetCategoryBySlug.graphql
Normal file
10
lib/saleor/queries/GetCategoryBySlug.graphql
Normal file
@ -0,0 +1,10 @@
|
||||
query GetCategoryBySlug($slug: String!) {
|
||||
category(slug: $slug) {
|
||||
id
|
||||
name
|
||||
slug
|
||||
description
|
||||
seoTitle
|
||||
seoDescription
|
||||
}
|
||||
}
|
54
lib/saleor/queries/GetCategoryProductsBySlug.graphql
Normal file
54
lib/saleor/queries/GetCategoryProductsBySlug.graphql
Normal file
@ -0,0 +1,54 @@
|
||||
query GetCategoryProductsBySlug($slug: String!) {
|
||||
category(slug: $slug) {
|
||||
products(channel: "default-channel", first: 100) {
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
slug
|
||||
name
|
||||
isAvailableForPurchase
|
||||
description
|
||||
seoTitle
|
||||
seoDescription
|
||||
pricing {
|
||||
priceRange {
|
||||
start {
|
||||
gross {
|
||||
currency
|
||||
amount
|
||||
}
|
||||
}
|
||||
stop {
|
||||
gross {
|
||||
currency
|
||||
amount
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
media {
|
||||
url(size: 2160)
|
||||
type
|
||||
alt
|
||||
}
|
||||
collections {
|
||||
name
|
||||
}
|
||||
updatedAt
|
||||
variants {
|
||||
id
|
||||
name
|
||||
pricing {
|
||||
price {
|
||||
gross {
|
||||
currency
|
||||
amount
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,21 +1,34 @@
|
||||
query GetMenuBySlug($slug: String!) {
|
||||
menu(slug: $slug, channel: "default-channel") {
|
||||
id
|
||||
slug
|
||||
name
|
||||
items {
|
||||
fragment MenuItem on MenuItem {
|
||||
id
|
||||
name
|
||||
url
|
||||
collection {
|
||||
slug
|
||||
}
|
||||
children {
|
||||
id
|
||||
collection {
|
||||
category {
|
||||
slug
|
||||
}
|
||||
page {
|
||||
slug
|
||||
}
|
||||
}
|
||||
|
||||
query GetMenuBySlug($slug: String!) {
|
||||
menu(slug: $slug, channel: "default-channel") {
|
||||
id
|
||||
slug
|
||||
name
|
||||
items {
|
||||
...MenuItem
|
||||
children {
|
||||
...MenuItem
|
||||
children {
|
||||
...MenuItem
|
||||
children {
|
||||
...MenuItem
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
15
lib/saleor/queries/GetPages.graphql
Normal file
15
lib/saleor/queries/GetPages.graphql
Normal file
@ -0,0 +1,15 @@
|
||||
query GetPages {
|
||||
pages(first: 10) {
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
title
|
||||
slug
|
||||
content
|
||||
seoTitle
|
||||
seoDescription
|
||||
created
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
query GetProductBySlug($slug: String!) {
|
||||
product(slug: $slug) {
|
||||
product(channel: "default-channel", slug: $slug) {
|
||||
id
|
||||
slug
|
||||
name
|
||||
|
@ -23,12 +23,10 @@
|
||||
"*": "prettier --write --ignore-unknown"
|
||||
},
|
||||
"dependencies": {
|
||||
"@graphql-typed-document-node/core": "3.2.0",
|
||||
"@headlessui/react": "^1.7.10",
|
||||
"@vercel/og": "^0.1.0",
|
||||
"clsx": "^1.2.1",
|
||||
"framer-motion": "^8.4.0",
|
||||
"graphql": "16.6.0",
|
||||
"is-empty-iterable": "^3.0.0",
|
||||
"next": "13.3.1",
|
||||
"react": "18.2.0",
|
||||
|
8
pnpm-lock.yaml
generated
8
pnpm-lock.yaml
generated
@ -1,9 +1,6 @@
|
||||
lockfileVersion: '6.0'
|
||||
|
||||
dependencies:
|
||||
'@graphql-typed-document-node/core':
|
||||
specifier: 3.2.0
|
||||
version: registry.npmjs.org/@graphql-typed-document-node/core@3.2.0(graphql@16.6.0)
|
||||
'@headlessui/react':
|
||||
specifier: ^1.7.10
|
||||
version: 1.7.14(react-dom@18.2.0)(react@18.2.0)
|
||||
@ -16,9 +13,6 @@ dependencies:
|
||||
framer-motion:
|
||||
specifier: ^8.4.0
|
||||
version: 8.5.5(react-dom@18.2.0)(react@18.2.0)
|
||||
graphql:
|
||||
specifier: 16.6.0
|
||||
version: registry.npmjs.org/graphql@16.6.0
|
||||
is-empty-iterable:
|
||||
specifier: ^3.0.0
|
||||
version: 3.0.0
|
||||
@ -4923,6 +4917,7 @@ packages:
|
||||
graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0
|
||||
dependencies:
|
||||
graphql: registry.npmjs.org/graphql@16.6.0
|
||||
dev: true
|
||||
|
||||
registry.npmjs.org/@jridgewell/gen-mapping@0.3.3:
|
||||
resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz}
|
||||
@ -6080,6 +6075,7 @@ packages:
|
||||
name: graphql
|
||||
version: 16.6.0
|
||||
engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0}
|
||||
dev: true
|
||||
|
||||
registry.npmjs.org/has-flag@3.0.0:
|
||||
resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz}
|
||||
|
Loading…
x
Reference in New Issue
Block a user