mirror of
https://github.com/vercel/commerce.git
synced 2025-07-22 20:26:49 +00:00
67
framework/vendure/utils/array-to-tree.ts
Normal file
67
framework/vendure/utils/array-to-tree.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
export type HasParent = { id: string; parent?: { id: string } | null }
|
||||
export type TreeNode<T extends HasParent> = T & {
|
||||
children: Array<TreeNode<T>>
|
||||
expanded: boolean
|
||||
}
|
||||
export type RootNode<T extends HasParent> = {
|
||||
id?: string
|
||||
children: Array<TreeNode<T>>
|
||||
}
|
||||
|
||||
export function arrayToTree<T extends HasParent>(
|
||||
nodes: T[],
|
||||
currentState?: RootNode<T>
|
||||
): RootNode<T> {
|
||||
const topLevelNodes: Array<TreeNode<T>> = []
|
||||
const mappedArr: { [id: string]: TreeNode<T> } = {}
|
||||
const currentStateMap = treeToMap(currentState)
|
||||
|
||||
// First map the nodes of the array to an object -> create a hash table.
|
||||
for (const node of nodes) {
|
||||
mappedArr[node.id] = { ...(node as any), children: [] }
|
||||
}
|
||||
|
||||
for (const id of nodes.map((n) => n.id)) {
|
||||
if (mappedArr.hasOwnProperty(id)) {
|
||||
const mappedElem = mappedArr[id]
|
||||
mappedElem.expanded = currentStateMap.get(id)?.expanded ?? false
|
||||
const parent = mappedElem.parent
|
||||
if (!parent) {
|
||||
continue
|
||||
}
|
||||
// If the element is not at the root level, add it to its parent array of children.
|
||||
const parentIsRoot = !mappedArr[parent.id]
|
||||
if (!parentIsRoot) {
|
||||
if (mappedArr[parent.id]) {
|
||||
mappedArr[parent.id].children.push(mappedElem)
|
||||
} else {
|
||||
mappedArr[parent.id] = { children: [mappedElem] } as any
|
||||
}
|
||||
} else {
|
||||
topLevelNodes.push(mappedElem)
|
||||
}
|
||||
}
|
||||
}
|
||||
// tslint:disable-next-line:no-non-null-assertion
|
||||
const rootId = topLevelNodes.length ? topLevelNodes[0].parent!.id : undefined
|
||||
return { id: rootId, children: topLevelNodes }
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an existing tree (as generated by the arrayToTree function) into a flat
|
||||
* Map. This is used to persist certain states (e.g. `expanded`) when re-building the
|
||||
* tree.
|
||||
*/
|
||||
function treeToMap<T extends HasParent>(
|
||||
tree?: RootNode<T>
|
||||
): Map<string, TreeNode<T>> {
|
||||
const nodeMap = new Map<string, TreeNode<T>>()
|
||||
function visit(node: TreeNode<T>) {
|
||||
nodeMap.set(node.id, node)
|
||||
node.children.forEach(visit)
|
||||
}
|
||||
if (tree) {
|
||||
visit(tree as TreeNode<T>)
|
||||
}
|
||||
return nodeMap
|
||||
}
|
44
framework/vendure/utils/fragments/cart-fragment.ts
Normal file
44
framework/vendure/utils/fragments/cart-fragment.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
export const cartFragment = /* GraphQL */ `
|
||||
fragment Cart on Order {
|
||||
id
|
||||
code
|
||||
createdAt
|
||||
totalQuantity
|
||||
subTotal
|
||||
subTotalWithTax
|
||||
total
|
||||
totalWithTax
|
||||
currencyCode
|
||||
customer {
|
||||
id
|
||||
}
|
||||
lines {
|
||||
id
|
||||
quantity
|
||||
linePriceWithTax
|
||||
discountedLinePriceWithTax
|
||||
unitPriceWithTax
|
||||
discountedUnitPriceWithTax
|
||||
featuredAsset {
|
||||
id
|
||||
preview
|
||||
}
|
||||
discounts {
|
||||
description
|
||||
amount
|
||||
}
|
||||
productVariant {
|
||||
id
|
||||
name
|
||||
sku
|
||||
price
|
||||
priceWithTax
|
||||
stockLevel
|
||||
product {
|
||||
slug
|
||||
}
|
||||
productId
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
24
framework/vendure/utils/fragments/search-result-fragment.ts
Normal file
24
framework/vendure/utils/fragments/search-result-fragment.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
export const searchResultFragment = /* GraphQL */ `
|
||||
fragment SearchResult on SearchResult {
|
||||
productId
|
||||
productName
|
||||
description
|
||||
description
|
||||
slug
|
||||
sku
|
||||
currencyCode
|
||||
productAsset {
|
||||
id
|
||||
preview
|
||||
}
|
||||
priceWithTax {
|
||||
... on SinglePrice {
|
||||
value
|
||||
}
|
||||
... on PriceRange {
|
||||
min
|
||||
max
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
@@ -0,0 +1,15 @@
|
||||
import { cartFragment } from '../fragments/cart-fragment'
|
||||
|
||||
export const addItemToOrderMutation = /* GraphQL */ `
|
||||
mutation addItemToOrder($variantId: ID!, $quantity: Int!) {
|
||||
addItemToOrder(productVariantId: $variantId, quantity: $quantity) {
|
||||
__typename
|
||||
...Cart
|
||||
... on ErrorResult {
|
||||
errorCode
|
||||
message
|
||||
}
|
||||
}
|
||||
}
|
||||
${cartFragment}
|
||||
`
|
@@ -0,0 +1,15 @@
|
||||
import { cartFragment } from '../fragments/cart-fragment'
|
||||
|
||||
export const adjustOrderLineMutation = /* GraphQL */ `
|
||||
mutation adjustOrderLine($orderLineId: ID!, $quantity: Int!) {
|
||||
adjustOrderLine(orderLineId: $orderLineId, quantity: $quantity) {
|
||||
__typename
|
||||
...Cart
|
||||
... on ErrorResult {
|
||||
errorCode
|
||||
message
|
||||
}
|
||||
}
|
||||
}
|
||||
${cartFragment}
|
||||
`
|
14
framework/vendure/utils/mutations/log-in-mutation.ts
Normal file
14
framework/vendure/utils/mutations/log-in-mutation.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
export const loginMutation = /* GraphQL */ `
|
||||
mutation login($username: String!, $password: String!) {
|
||||
login(username: $username, password: $password) {
|
||||
__typename
|
||||
... on CurrentUser {
|
||||
id
|
||||
}
|
||||
... on ErrorResult {
|
||||
errorCode
|
||||
message
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
7
framework/vendure/utils/mutations/log-out-mutation.ts
Normal file
7
framework/vendure/utils/mutations/log-out-mutation.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
export const logoutMutation = /* GraphQL */ `
|
||||
mutation logout {
|
||||
logout {
|
||||
success
|
||||
}
|
||||
}
|
||||
`
|
@@ -0,0 +1,15 @@
|
||||
import { cartFragment } from '../fragments/cart-fragment'
|
||||
|
||||
export const removeOrderLineMutation = /* GraphQL */ `
|
||||
mutation removeOrderLine($orderLineId: ID!) {
|
||||
removeOrderLine(orderLineId: $orderLineId) {
|
||||
__typename
|
||||
...Cart
|
||||
... on ErrorResult {
|
||||
errorCode
|
||||
message
|
||||
}
|
||||
}
|
||||
}
|
||||
${cartFragment}
|
||||
`
|
14
framework/vendure/utils/mutations/sign-up-mutation.ts
Normal file
14
framework/vendure/utils/mutations/sign-up-mutation.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
export const signupMutation = /* GraphQL */ `
|
||||
mutation signup($input: RegisterCustomerInput!) {
|
||||
registerCustomerAccount(input: $input) {
|
||||
__typename
|
||||
... on Success {
|
||||
success
|
||||
}
|
||||
... on ErrorResult {
|
||||
errorCode
|
||||
message
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
56
framework/vendure/utils/normalize.ts
Normal file
56
framework/vendure/utils/normalize.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
import { Product } from '@commerce/types/product'
|
||||
import { Cart } from '@commerce/types/cart'
|
||||
import { CartFragment, SearchResultFragment } from '../schema'
|
||||
|
||||
export function normalizeSearchResult(item: SearchResultFragment): Product {
|
||||
return {
|
||||
id: item.productId,
|
||||
name: item.productName,
|
||||
description: item.description,
|
||||
slug: item.slug,
|
||||
path: item.slug,
|
||||
images: [{ url: item.productAsset?.preview + '?w=800&mode=crop' || '' }],
|
||||
variants: [],
|
||||
price: {
|
||||
value: (item.priceWithTax as any).min / 100,
|
||||
currencyCode: item.currencyCode,
|
||||
},
|
||||
options: [],
|
||||
sku: item.sku,
|
||||
}
|
||||
}
|
||||
|
||||
export function normalizeCart(order: CartFragment): Cart {
|
||||
return {
|
||||
id: order.id.toString(),
|
||||
createdAt: order.createdAt,
|
||||
taxesIncluded: true,
|
||||
lineItemsSubtotalPrice: order.subTotalWithTax / 100,
|
||||
currency: { code: order.currencyCode },
|
||||
subtotalPrice: order.subTotalWithTax / 100,
|
||||
totalPrice: order.totalWithTax / 100,
|
||||
customerId: order.customer?.id,
|
||||
lineItems: order.lines?.map((l) => ({
|
||||
id: l.id,
|
||||
name: l.productVariant.name,
|
||||
quantity: l.quantity,
|
||||
url: l.productVariant.product.slug,
|
||||
variantId: l.productVariant.id,
|
||||
productId: l.productVariant.productId,
|
||||
images: [{ url: l.featuredAsset?.preview + '?preset=thumb' || '' }],
|
||||
discounts: l.discounts.map((d) => ({ value: d.amount / 100 })),
|
||||
path: '',
|
||||
variant: {
|
||||
id: l.productVariant.id,
|
||||
name: l.productVariant.name,
|
||||
sku: l.productVariant.sku,
|
||||
price: l.discountedUnitPriceWithTax / 100,
|
||||
listPrice: l.unitPriceWithTax / 100,
|
||||
image: {
|
||||
url: l.featuredAsset?.preview + '?preset=thumb' || '',
|
||||
},
|
||||
requiresShipping: true,
|
||||
},
|
||||
})),
|
||||
}
|
||||
}
|
10
framework/vendure/utils/queries/active-customer-query.ts
Normal file
10
framework/vendure/utils/queries/active-customer-query.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
export const activeCustomerQuery = /* GraphQL */ `
|
||||
query activeCustomer {
|
||||
activeCustomer {
|
||||
id
|
||||
firstName
|
||||
lastName
|
||||
emailAddress
|
||||
}
|
||||
}
|
||||
`
|
@@ -0,0 +1,9 @@
|
||||
export const getAllProductPathsQuery = /* GraphQL */ `
|
||||
query getAllProductPaths($first: Int = 100) {
|
||||
products(options: { take: $first }) {
|
||||
items {
|
||||
slug
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
12
framework/vendure/utils/queries/get-all-products-query.ts
Normal file
12
framework/vendure/utils/queries/get-all-products-query.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { searchResultFragment } from '../fragments/search-result-fragment'
|
||||
|
||||
export const getAllProductsQuery = /* GraphQL */ `
|
||||
query getAllProducts($input: SearchInput!) {
|
||||
search(input: $input) {
|
||||
items {
|
||||
...SearchResult
|
||||
}
|
||||
}
|
||||
}
|
||||
${searchResultFragment}
|
||||
`
|
10
framework/vendure/utils/queries/get-cart-query.ts
Normal file
10
framework/vendure/utils/queries/get-cart-query.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { cartFragment } from '../fragments/cart-fragment'
|
||||
|
||||
export const getCartQuery = /* GraphQL */ `
|
||||
query activeOrder {
|
||||
activeOrder {
|
||||
...Cart
|
||||
}
|
||||
}
|
||||
${cartFragment}
|
||||
`
|
21
framework/vendure/utils/queries/get-collections-query.ts
Normal file
21
framework/vendure/utils/queries/get-collections-query.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
export const getCollectionsQuery = /* GraphQL */ `
|
||||
query getCollections {
|
||||
collections {
|
||||
items {
|
||||
id
|
||||
name
|
||||
description
|
||||
slug
|
||||
productVariants {
|
||||
totalItems
|
||||
}
|
||||
parent {
|
||||
id
|
||||
}
|
||||
children {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
41
framework/vendure/utils/queries/get-product-query.ts
Normal file
41
framework/vendure/utils/queries/get-product-query.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
export const getProductQuery = /* GraphQL */ `
|
||||
query getProduct($slug: String!) {
|
||||
product(slug: $slug) {
|
||||
id
|
||||
name
|
||||
slug
|
||||
description
|
||||
assets {
|
||||
id
|
||||
preview
|
||||
name
|
||||
}
|
||||
variants {
|
||||
id
|
||||
priceWithTax
|
||||
currencyCode
|
||||
options {
|
||||
id
|
||||
name
|
||||
code
|
||||
groupId
|
||||
group {
|
||||
id
|
||||
options {
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
optionGroups {
|
||||
id
|
||||
code
|
||||
name
|
||||
options {
|
||||
id
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
13
framework/vendure/utils/queries/search-query.ts
Normal file
13
framework/vendure/utils/queries/search-query.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { searchResultFragment } from '../fragments/search-result-fragment'
|
||||
|
||||
export const searchQuery = /* GraphQL */ `
|
||||
query search($input: SearchInput!) {
|
||||
search(input: $input) {
|
||||
items {
|
||||
...SearchResult
|
||||
}
|
||||
totalItems
|
||||
}
|
||||
}
|
||||
${searchResultFragment}
|
||||
`
|
Reference in New Issue
Block a user