From d7cbb9cfa5e64e7da3d5354900ba3ac915c3423a Mon Sep 17 00:00:00 2001 From: Franco Arza Date: Sat, 17 Oct 2020 22:32:08 -0300 Subject: [PATCH 01/15] square searchbox, remove border and replace grayscale with new palette --- assets/global.css | 40 +++++++++---------- .../core/Searchbar/Searchbar.module.css | 2 +- components/core/Searchbar/Searchbar.tsx | 2 +- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/assets/global.css b/assets/global.css index 3d102a643..bde37971d 100644 --- a/assets/global.css +++ b/assets/global.css @@ -22,16 +22,16 @@ --violet: #7928ca; --blue: #0070f3; - --accents-0: #fff; - --accents-1: #fafafa; - --accents-2: #eaeaea; - --accents-3: #999999; - --accents-4: #888888; - --accents-5: #666666; - --accents-6: #444444; - --accents-7: #333333; - --accents-8: #111111; - --accents-9: #000; + --accents-0: #f8f9fa; + --accents-1: #f1f3f5; + --accents-2: #e9ecef; + --accents-3: #dee2e6; + --accents-4: #ced4da; + --accents-5: #adb5bd; + --accents-6: #868e96; + --accents-7: #495057; + --accents-8: #343a40; + --accents-9: #212529; } [data-theme='dark'] { @@ -46,16 +46,16 @@ --text-primary: white; --text-secondary: black; - --accents-0: #000; - --accents-1: #111111; - --accents-2: #333333; - --accents-3: #444444; - --accents-4: #666666; - --accents-5: #888888; - --accents-6: #999999; - --accents-7: #eaeaea; - --accents-8: #fafafa; - --accents-9: #fff; + --accents-0: #212529; + --accents-1: #343a40; + --accents-2: #495057; + --accents-3: #868e96; + --accents-4: #adb5bd; + --accents-5: #ced4da; + --accents-6: #dee2e6; + --accents-7: #e9ecef; + --accents-8: #f1f3f5; + --accents-9: #f8f9fa; } .fit { diff --git a/components/core/Searchbar/Searchbar.module.css b/components/core/Searchbar/Searchbar.module.css index 41fedd0f8..0d2265650 100644 --- a/components/core/Searchbar/Searchbar.module.css +++ b/components/core/Searchbar/Searchbar.module.css @@ -1,5 +1,5 @@ .input { - @apply bg-transparent px-3 py-2 appearance-none w-full transition duration-150 ease-in-out rounded-lg placeholder-accents-4 pr-10; + @apply bg-transparent px-3 py-2 appearance-none w-full transition duration-150 ease-in-out placeholder-accents-5 pr-10; min-width: 300px; } diff --git a/components/core/Searchbar/Searchbar.tsx b/components/core/Searchbar/Searchbar.tsx index aa754d564..a2fe85f18 100644 --- a/components/core/Searchbar/Searchbar.tsx +++ b/components/core/Searchbar/Searchbar.tsx @@ -17,7 +17,7 @@ const Searchbar: FC = ({ className }) => { return (
From c2bc6eb1cc6dfb5361d886480d303c4e507405d2 Mon Sep 17 00:00:00 2001 From: Franco Arza Date: Sat, 17 Oct 2020 23:00:09 -0300 Subject: [PATCH 02/15] make secondary grid use gray bg, made sidemenu sticky --- .../ProductCard/ProductCard.module.css | 10 +++-- .../product/ProductCard/ProductCard.tsx | 8 ++-- pages/index.tsx | 42 ++++++++++--------- 3 files changed, 33 insertions(+), 27 deletions(-) diff --git a/components/product/ProductCard/ProductCard.module.css b/components/product/ProductCard/ProductCard.module.css index 1c9b2a75f..7846da50e 100644 --- a/components/product/ProductCard/ProductCard.module.css +++ b/components/product/ProductCard/ProductCard.module.css @@ -55,7 +55,7 @@ } .squareBg, -.productTitle, +.productTitle > span, .productPrice, .wishlistButton { @apply transition ease-in-out duration-300; @@ -65,9 +65,13 @@ @apply transform absolute inset-0 z-0 bg-secondary; } +.squareBg.gray { + @apply bg-gray-300 !important; +} + .productTitle { - line-height: 51px; - width: 200px; + line-height: 40px; + width: 18vw; & span { @apply inline text-2xl leading-6 p-4 bg-primary text-primary font-bold; diff --git a/components/product/ProductCard/ProductCard.tsx b/components/product/ProductCard/ProductCard.tsx index 847cea12e..0c2ad6e19 100644 --- a/components/product/ProductCard/ProductCard.tsx +++ b/components/product/ProductCard/ProductCard.tsx @@ -8,7 +8,7 @@ interface Props { className?: string children?: ReactNode[] | Component[] | any[] node: ProductData - variant?: 'slim' + variant?: 'slim' | 'simple' } interface ProductData { @@ -44,12 +44,12 @@ const ProductCard: FC = ({ className, node: p, variant }) => { src={p.images.edges[0].node.urlXL} />
-
+
-
+

{p.name} -

+

${p.prices.price.value}
diff --git a/pages/index.tsx b/pages/index.tsx index 04b3e9ef5..a300ce948 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -54,32 +54,34 @@ export default function Home({ ))}
-
-
    -
  • - All Categories -
  • - {categories.map((cat) => ( -
  • - {cat.name} +
    +
    +
      +
    • + All Categories
    • - ))} -
    -
      -
    • - All Designers -
    • - {brands.flatMap(({ node }) => ( -
    • - {node.name} + {categories.map((cat) => ( +
    • + {cat.name} +
    • + ))} +
    +
      +
    • + All Designers
    • - ))} -
    + {brands.flatMap(({ node }) => ( +
  • + {node.name} +
  • + ))} +
+
{products.map((p: any) => ( - + ))}
From 4bb7fa33fe95a1646635899b26f378a5f83846d7 Mon Sep 17 00:00:00 2001 From: Franco Arza Date: Sat, 17 Oct 2020 23:09:05 -0300 Subject: [PATCH 03/15] make marquees larger --- components/product/ProductCard/ProductCard.tsx | 2 +- components/ui/Marquee/Marquee.module.css | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/product/ProductCard/ProductCard.tsx b/components/product/ProductCard/ProductCard.tsx index 847cea12e..a4e75c8f4 100644 --- a/components/product/ProductCard/ProductCard.tsx +++ b/components/product/ProductCard/ProductCard.tsx @@ -23,7 +23,7 @@ const ProductCard: FC = ({ className, node: p, variant }) => { return (
diff --git a/components/ui/Marquee/Marquee.module.css b/components/ui/Marquee/Marquee.module.css index 06786b036..32601a54e 100644 --- a/components/ui/Marquee/Marquee.module.css +++ b/components/ui/Marquee/Marquee.module.css @@ -8,7 +8,7 @@ & > * { @apply flex-1 px-16 py-4; - width: 400px; + width: 430px; } } From 42cb7120e55acaf2ee8b69b7b1e95052dae8802b Mon Sep 17 00:00:00 2001 From: Luis Alvarez Date: Sun, 18 Oct 2020 15:23:17 -0500 Subject: [PATCH 04/15] Added more info about the products --- lib/bigcommerce/api/fragments/product.ts | 26 +++++- .../api/operations/get-all-products.ts | 82 +++++++++++++++---- lib/bigcommerce/schema.d.ts | 69 ++++++++++++++++ 3 files changed, 158 insertions(+), 19 deletions(-) diff --git a/lib/bigcommerce/api/fragments/product.ts b/lib/bigcommerce/api/fragments/product.ts index d047e147a..7c81e0b2e 100644 --- a/lib/bigcommerce/api/fragments/product.ts +++ b/lib/bigcommerce/api/fragments/product.ts @@ -9,12 +9,15 @@ export const responsiveImageFragment = /* GraphQL */ ` isDefault } ` -export const multipleChoiceFragment = /* GraphQL */ ` + +export const swatchOptionFragment = /* GraphQL */ ` fragment swatchOption on SwatchOptionValue { isDefault hexColors } +` +export const multipleChoiceOptionFragment = /* GraphQL */ ` fragment multipleChoiceOption on MultipleChoiceOption { entityId values { @@ -26,6 +29,8 @@ export const multipleChoiceFragment = /* GraphQL */ ` } } } + + ${swatchOptionFragment} ` export const productInfoFragment = /* GraphQL */ ` @@ -76,5 +81,22 @@ export const productInfoFragment = /* GraphQL */ ` } ${responsiveImageFragment} - ${multipleChoiceFragment} + ${multipleChoiceOptionFragment} +` + +export const productConnectionFragment = /* GraphQL */ ` + fragment productConnnection on ProductConnection { + pageInfo { + startCursor + endCursor + } + edges { + cursor + node { + ...productInfo + } + } + } + + ${productInfoFragment} ` diff --git a/lib/bigcommerce/api/operations/get-all-products.ts b/lib/bigcommerce/api/operations/get-all-products.ts index e1b094cac..e83eb7464 100644 --- a/lib/bigcommerce/api/operations/get-all-products.ts +++ b/lib/bigcommerce/api/operations/get-all-products.ts @@ -4,7 +4,7 @@ import type { } from 'lib/bigcommerce/schema' import type { RecursivePartial, RecursiveRequired } from '../utils/types' import filterEdges from '../utils/filter-edges' -import { productInfoFragment } from '../fragments/product' +import { productConnectionFragment } from '../fragments/product' import { BigcommerceConfig, getConfig, Images, ProductImageVariables } from '..' export const getAllProductsQuery = /* GraphQL */ ` @@ -19,24 +19,33 @@ export const getAllProductsQuery = /* GraphQL */ ` $imgLargeHeight: Int $imgXLWidth: Int = 1280 $imgXLHeight: Int + $featuredProducts: Boolean = false + $featuredProducts__first: Int = 10 + $bestSellingProducts: Boolean = false + $bestSellingProducts__first: Int = 10 + $newestProducts: Boolean = false + $newestProducts__first: Int = 10 ) { site { products(first: $first, entityIds: $entityIds) { - pageInfo { - startCursor - endCursor - } - edges { - cursor - node { - ...productInfo - } - } + ...productConnnection + } + featuredProducts(first: $featuredProducts__first) + @include(if: $featuredProducts) { + ...productConnnection + } + bestSellingProducts(first: $bestSellingProducts__first) + @include(if: $bestSellingProducts) { + ...productConnnection + } + newestProducts(first: $newestProducts__first) + @include(if: $newestProducts) { + ...productConnnection } } } - ${productInfoFragment} + ${productConnectionFragment} ` export type Product = NonNullable< @@ -46,10 +55,19 @@ export type Product = NonNullable< export type Products = Product[] export type GetAllProductsResult< - T extends { products: any[] } = { products: Products } + T extends Record = { + products: Products + featuredProducts: Products + bestSellingProducts: Products + newestProducts: Products + } > = T -export type ProductVariables = Images & +export type ProductVariables = { + featured?: boolean | { first?: number } + bestSelling?: boolean | { first?: number } + newest?: boolean | { first?: number } +} & Images & Omit async function getAllProducts(opts?: { @@ -57,7 +75,10 @@ async function getAllProducts(opts?: { config?: BigcommerceConfig }): Promise -async function getAllProducts(opts: { +async function getAllProducts< + T extends Record, + V = any +>(opts: { query: string variables?: V config?: BigcommerceConfig @@ -65,7 +86,7 @@ async function getAllProducts(opts: { async function getAllProducts({ query = getAllProductsQuery, - variables: vars, + variables: { featured, bestSelling, newest, ...vars } = {}, config, }: { query?: string @@ -77,6 +98,26 @@ async function getAllProducts({ ...config.imageVariables, ...vars, } + + if (bestSelling) { + variables.bestSellingProducts = true + if (typeof bestSelling === 'object' && bestSelling.first) { + variables.bestSellingProducts__first = bestSelling.first + } + } + if (featured) { + variables.featuredProducts = true + if (typeof featured === 'object' && featured.first) { + variables.featuredProducts__first = featured.first + } + } + if (newest) { + variables.newestProducts = true + if (typeof newest === 'object' && newest.first) { + variables.newestProducts__first = newest.first + } + } + // RecursivePartial forces the method to check for every prop in the data, which is // required in case there's a custom `query` const data = await config.fetch>( @@ -85,8 +126,15 @@ async function getAllProducts({ ) const products = data.site?.products?.edges + type P = RecursiveRequired + return { - products: filterEdges(products as RecursiveRequired), + products: filterEdges(products as P), + featuredProducts: filterEdges(data.site?.featuredProducts?.edges as P), + bestSellingProducts: filterEdges( + data.site?.bestSellingProducts?.edges as P + ), + newestProducts: filterEdges(data.site?.newestProducts?.edges as P), } } diff --git a/lib/bigcommerce/schema.d.ts b/lib/bigcommerce/schema.d.ts index 6bd4ee8e0..4d13e92d3 100644 --- a/lib/bigcommerce/schema.d.ts +++ b/lib/bigcommerce/schema.d.ts @@ -1785,6 +1785,24 @@ export type ProductInfoFragment = { __typename?: 'Product' } & Pick< } } +export type ProductConnnectionFragment = { + __typename?: 'ProductConnection' +} & { + pageInfo: { __typename?: 'PageInfo' } & Pick< + PageInfo, + 'startCursor' | 'endCursor' + > + edges?: Maybe< + Array< + Maybe< + { __typename?: 'ProductEdge' } & Pick & { + node: { __typename?: 'Product' } & ProductInfoFragment + } + > + > + > +} + export type GetAllProductPathsQueryVariables = Exact<{ [key: string]: never }> export type GetAllProductPathsQuery = { __typename?: 'Query' } & { @@ -1814,6 +1832,12 @@ export type GetAllProductsQueryVariables = Exact<{ imgLargeHeight?: Maybe imgXLWidth?: Maybe imgXLHeight?: Maybe + featuredProducts?: Maybe + featuredProducts__first?: Maybe + bestSellingProducts?: Maybe + bestSellingProducts__first?: Maybe + newestProducts?: Maybe + newestProducts__first?: Maybe }> export type GetAllProductsQuery = { __typename?: 'Query' } & { @@ -1833,6 +1857,51 @@ export type GetAllProductsQuery = { __typename?: 'Query' } & { > > } + featuredProducts: { __typename?: 'ProductConnection' } & { + pageInfo: { __typename?: 'PageInfo' } & Pick< + PageInfo, + 'startCursor' | 'endCursor' + > + edges?: Maybe< + Array< + Maybe< + { __typename?: 'ProductEdge' } & Pick & { + node: { __typename?: 'Product' } & ProductInfoFragment + } + > + > + > + } + bestSellingProducts: { __typename?: 'ProductConnection' } & { + pageInfo: { __typename?: 'PageInfo' } & Pick< + PageInfo, + 'startCursor' | 'endCursor' + > + edges?: Maybe< + Array< + Maybe< + { __typename?: 'ProductEdge' } & Pick & { + node: { __typename?: 'Product' } & ProductInfoFragment + } + > + > + > + } + newestProducts: { __typename?: 'ProductConnection' } & { + pageInfo: { __typename?: 'PageInfo' } & Pick< + PageInfo, + 'startCursor' | 'endCursor' + > + edges?: Maybe< + Array< + Maybe< + { __typename?: 'ProductEdge' } & Pick & { + node: { __typename?: 'Product' } & ProductInfoFragment + } + > + > + > + } } } From c92e7658145051cb371a595a75937a8b540c1e4d Mon Sep 17 00:00:00 2001 From: Luis Alvarez Date: Sun, 18 Oct 2020 17:52:07 -0500 Subject: [PATCH 05/15] Fetch products separately --- .../api/operations/get-all-products.ts | 80 +++++++------------ lib/bigcommerce/schema.d.ts | 74 +++-------------- pages/index.tsx | 3 + 3 files changed, 45 insertions(+), 112 deletions(-) diff --git a/lib/bigcommerce/api/operations/get-all-products.ts b/lib/bigcommerce/api/operations/get-all-products.ts index e83eb7464..796c10585 100644 --- a/lib/bigcommerce/api/operations/get-all-products.ts +++ b/lib/bigcommerce/api/operations/get-all-products.ts @@ -19,27 +19,22 @@ export const getAllProductsQuery = /* GraphQL */ ` $imgLargeHeight: Int $imgXLWidth: Int = 1280 $imgXLHeight: Int + $products: Boolean = false $featuredProducts: Boolean = false - $featuredProducts__first: Int = 10 $bestSellingProducts: Boolean = false - $bestSellingProducts__first: Int = 10 $newestProducts: Boolean = false - $newestProducts__first: Int = 10 ) { site { - products(first: $first, entityIds: $entityIds) { + products(first: $first, entityIds: $entityIds) @include(if: $products) { ...productConnnection } - featuredProducts(first: $featuredProducts__first) - @include(if: $featuredProducts) { + featuredProducts(first: $first) @include(if: $featuredProducts) { ...productConnnection } - bestSellingProducts(first: $bestSellingProducts__first) - @include(if: $bestSellingProducts) { + bestSellingProducts(first: $first) @include(if: $bestSellingProducts) { ...productConnnection } - newestProducts(first: $newestProducts__first) - @include(if: $newestProducts) { + newestProducts(first: $first) @include(if: $newestProducts) { ...productConnnection } } @@ -55,20 +50,17 @@ export type Product = NonNullable< export type Products = Product[] export type GetAllProductsResult< - T extends Record = { - products: Products - featuredProducts: Products - bestSellingProducts: Products - newestProducts: Products - } + T extends Record = { products: Products } > = T -export type ProductVariables = { - featured?: boolean | { first?: number } - bestSelling?: boolean | { first?: number } - newest?: boolean | { first?: number } -} & Images & - Omit +export type ProductTypes = + | 'products' + | 'featuredProducts' + | 'bestSellingProducts' + | 'newestProducts' + +export type ProductVariables = { field?: ProductTypes } & Images & + Omit async function getAllProducts(opts?: { variables?: ProductVariables @@ -86,7 +78,7 @@ async function getAllProducts< async function getAllProducts({ query = getAllProductsQuery, - variables: { featured, bestSelling, newest, ...vars } = {}, + variables: { field = 'products', ...vars } = {}, config, }: { query?: string @@ -94,28 +86,25 @@ async function getAllProducts({ config?: BigcommerceConfig } = {}): Promise { config = getConfig(config) + const variables: GetAllProductsQueryVariables = { ...config.imageVariables, ...vars, } - if (bestSelling) { - variables.bestSellingProducts = true - if (typeof bestSelling === 'object' && bestSelling.first) { - variables.bestSellingProducts__first = bestSelling.first - } - } - if (featured) { - variables.featuredProducts = true - if (typeof featured === 'object' && featured.first) { - variables.featuredProducts__first = featured.first - } - } - if (newest) { - variables.newestProducts = true - if (typeof newest === 'object' && newest.first) { - variables.newestProducts__first = newest.first - } + switch (field) { + case 'products': + variables.products = true + break + case 'featuredProducts': + variables.featuredProducts = true + break + case 'bestSellingProducts': + variables.bestSellingProducts = true + break + case 'newestProducts': + variables.newestProducts = true + break } // RecursivePartial forces the method to check for every prop in the data, which is @@ -124,17 +113,10 @@ async function getAllProducts({ query, { variables } ) - const products = data.site?.products?.edges - - type P = RecursiveRequired + const products = data.site?.[field]?.edges return { - products: filterEdges(products as P), - featuredProducts: filterEdges(data.site?.featuredProducts?.edges as P), - bestSellingProducts: filterEdges( - data.site?.bestSellingProducts?.edges as P - ), - newestProducts: filterEdges(data.site?.newestProducts?.edges as P), + products: filterEdges(products as RecursiveRequired), } } diff --git a/lib/bigcommerce/schema.d.ts b/lib/bigcommerce/schema.d.ts index 4d13e92d3..e9141337b 100644 --- a/lib/bigcommerce/schema.d.ts +++ b/lib/bigcommerce/schema.d.ts @@ -1832,76 +1832,24 @@ export type GetAllProductsQueryVariables = Exact<{ imgLargeHeight?: Maybe imgXLWidth?: Maybe imgXLHeight?: Maybe + products?: Maybe featuredProducts?: Maybe - featuredProducts__first?: Maybe bestSellingProducts?: Maybe - bestSellingProducts__first?: Maybe newestProducts?: Maybe - newestProducts__first?: Maybe }> export type GetAllProductsQuery = { __typename?: 'Query' } & { site: { __typename?: 'Site' } & { - products: { __typename?: 'ProductConnection' } & { - pageInfo: { __typename?: 'PageInfo' } & Pick< - PageInfo, - 'startCursor' | 'endCursor' - > - edges?: Maybe< - Array< - Maybe< - { __typename?: 'ProductEdge' } & Pick & { - node: { __typename?: 'Product' } & ProductInfoFragment - } - > - > - > - } - featuredProducts: { __typename?: 'ProductConnection' } & { - pageInfo: { __typename?: 'PageInfo' } & Pick< - PageInfo, - 'startCursor' | 'endCursor' - > - edges?: Maybe< - Array< - Maybe< - { __typename?: 'ProductEdge' } & Pick & { - node: { __typename?: 'Product' } & ProductInfoFragment - } - > - > - > - } - bestSellingProducts: { __typename?: 'ProductConnection' } & { - pageInfo: { __typename?: 'PageInfo' } & Pick< - PageInfo, - 'startCursor' | 'endCursor' - > - edges?: Maybe< - Array< - Maybe< - { __typename?: 'ProductEdge' } & Pick & { - node: { __typename?: 'Product' } & ProductInfoFragment - } - > - > - > - } - newestProducts: { __typename?: 'ProductConnection' } & { - pageInfo: { __typename?: 'PageInfo' } & Pick< - PageInfo, - 'startCursor' | 'endCursor' - > - edges?: Maybe< - Array< - Maybe< - { __typename?: 'ProductEdge' } & Pick & { - node: { __typename?: 'Product' } & ProductInfoFragment - } - > - > - > - } + products: { __typename?: 'ProductConnection' } & ProductConnnectionFragment + featuredProducts: { + __typename?: 'ProductConnection' + } & ProductConnnectionFragment + bestSellingProducts: { + __typename?: 'ProductConnection' + } & ProductConnnectionFragment + newestProducts: { + __typename?: 'ProductConnection' + } & ProductConnnectionFragment } } diff --git a/pages/index.tsx b/pages/index.tsx index 04b3e9ef5..d0b0be8c7 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -9,6 +9,9 @@ import getAllPages from '@lib/bigcommerce/api/operations/get-all-pages' export async function getStaticProps({ preview }: GetStaticPropsContext) { const { pages } = await getAllPages() const { products } = await getAllProducts() + // const { products: featuredProducts } = await getAllProducts({ + // variables: { field: 'featuredProducts' }, + // }) const { categories, brands } = await getSiteInfo() return { From ecafee83106fbbce2e27e088bf968c231ac95abd Mon Sep 17 00:00:00 2001 From: Jing Wang Date: Mon, 19 Oct 2020 09:10:45 -0400 Subject: [PATCH 06/15] add in initial wishlist api functions and hooks --- lib/bigcommerce/api/catalog/products.ts | 4 +- .../api/wishlist/handlers/add-item.ts | 30 ++++ .../api/wishlist/handlers/add-wishlist.ts | 25 +++ .../wishlist/handlers/get-all-wishlists.ts | 22 +++ .../api/wishlist/handlers/get-wishlist.ts | 21 +++ .../api/wishlist/handlers/remove-item.ts | 25 +++ .../api/wishlist/handlers/remove-wishlist.ts | 25 +++ .../api/wishlist/handlers/update-wishlist.ts | 27 ++++ lib/bigcommerce/api/wishlist/index.ts | 152 ++++++++++++++++++ lib/bigcommerce/wishlist/use-add-item.tsx | 46 ++++++ lib/bigcommerce/wishlist/use-remove-item.tsx | 51 ++++++ .../wishlist/use-wishlist-actions.tsx | 11 ++ lib/bigcommerce/wishlist/use-wishlist.tsx | 41 +++++ 13 files changed, 478 insertions(+), 2 deletions(-) create mode 100644 lib/bigcommerce/api/wishlist/handlers/add-item.ts create mode 100644 lib/bigcommerce/api/wishlist/handlers/add-wishlist.ts create mode 100644 lib/bigcommerce/api/wishlist/handlers/get-all-wishlists.ts create mode 100644 lib/bigcommerce/api/wishlist/handlers/get-wishlist.ts create mode 100644 lib/bigcommerce/api/wishlist/handlers/remove-item.ts create mode 100644 lib/bigcommerce/api/wishlist/handlers/remove-wishlist.ts create mode 100644 lib/bigcommerce/api/wishlist/handlers/update-wishlist.ts create mode 100644 lib/bigcommerce/api/wishlist/index.ts create mode 100644 lib/bigcommerce/wishlist/use-add-item.tsx create mode 100644 lib/bigcommerce/wishlist/use-remove-item.tsx create mode 100644 lib/bigcommerce/wishlist/use-wishlist-actions.tsx create mode 100644 lib/bigcommerce/wishlist/use-wishlist.tsx diff --git a/lib/bigcommerce/api/catalog/products.ts b/lib/bigcommerce/api/catalog/products.ts index f3c01d934..0af21149e 100644 --- a/lib/bigcommerce/api/catalog/products.ts +++ b/lib/bigcommerce/api/catalog/products.ts @@ -22,7 +22,7 @@ export type ProductsHandlers = { const METHODS = ['GET'] // TODO: a complete implementation should have schema validation for `req.body` -const cartApi: BigcommerceApiHandler< +const productApi: BigcommerceApiHandler< SearchProductsData, ProductsHandlers > = async (req, res, config, handlers) => { @@ -45,4 +45,4 @@ const cartApi: BigcommerceApiHandler< export const handlers = { getProducts } -export default createApiHandler(cartApi, handlers, {}) +export default createApiHandler(productApi, handlers, {}) diff --git a/lib/bigcommerce/api/wishlist/handlers/add-item.ts b/lib/bigcommerce/api/wishlist/handlers/add-item.ts new file mode 100644 index 000000000..d6678031f --- /dev/null +++ b/lib/bigcommerce/api/wishlist/handlers/add-item.ts @@ -0,0 +1,30 @@ +import type { WishlistHandlers } from '..' + +// Return current wishlist info +const addItem: WishlistHandlers['addItem'] = async ({ + res, + body: { wishlistId, item }, + config, +}) => { + if (!item) { + return res.status(400).json({ + data: null, + errors: [{ message: 'Missing item' }], + }) + } + + const options = { + method: 'POST', + body: JSON.stringify({ + items: [item], + }), + } + const { data } = await config.storeApiFetch( + `/v3/wishlists/${wishlistId}/items`, + options + ) + + res.status(200).json({ data }) +} + +export default addItem diff --git a/lib/bigcommerce/api/wishlist/handlers/add-wishlist.ts b/lib/bigcommerce/api/wishlist/handlers/add-wishlist.ts new file mode 100644 index 000000000..b4090adaa --- /dev/null +++ b/lib/bigcommerce/api/wishlist/handlers/add-wishlist.ts @@ -0,0 +1,25 @@ +import type { WishlistHandlers } from '..' + +// Return current wishlist info +const addWishlist: WishlistHandlers['addWishlist'] = async ({ + res, + body: { wishlist }, + config, +}) => { + if (!wishlist) { + return res.status(400).json({ + data: null, + errors: [{ message: 'Missing wishlist data' }], + }) + } + + const options = { + method: 'POST', + body: JSON.stringify(wishlist), + } + const { data } = await config.storeApiFetch(`/v3/wishlists/`, options) + + res.status(200).json({ data }) +} + +export default addWishlist diff --git a/lib/bigcommerce/api/wishlist/handlers/get-all-wishlists.ts b/lib/bigcommerce/api/wishlist/handlers/get-all-wishlists.ts new file mode 100644 index 000000000..310c7f41d --- /dev/null +++ b/lib/bigcommerce/api/wishlist/handlers/get-all-wishlists.ts @@ -0,0 +1,22 @@ +import { BigcommerceApiError } from '../../utils/errors' +import type { WishlistList, WishlistHandlers } from '..' + +// Return all wishlists +const getAllWishlists: WishlistHandlers['getAllWishlists'] = async ({ + res, + body: { customerId }, + config, +}) => { + let result: { data?: WishlistList } = {} + + try { + result = await config.storeApiFetch(`/v3/wishlists/customer_id=${customerId}`) + } catch (error) { + throw error + } + + const data = (result.data ?? []) as any + res.status(200).json({ data }) +} + +export default getAllWishlists diff --git a/lib/bigcommerce/api/wishlist/handlers/get-wishlist.ts b/lib/bigcommerce/api/wishlist/handlers/get-wishlist.ts new file mode 100644 index 000000000..1fcbeaed8 --- /dev/null +++ b/lib/bigcommerce/api/wishlist/handlers/get-wishlist.ts @@ -0,0 +1,21 @@ +import { BigcommerceApiError } from '../../utils/errors' +import type { Wishlist, WishlistHandlers } from '..' + +// Return wishlist info +const getWishlist: WishlistHandlers['getWishlist'] = async ({ + res, + body: { wishlistId }, + config, +}) => { + let result: { data?: Wishlist } = {} + + try { + result = await config.storeApiFetch(`/v3/wishlists/${wishlistId}`) + } catch (error) { + throw error + } + + res.status(200).json({ data: result.data ?? null }) +} + +export default getWishlist diff --git a/lib/bigcommerce/api/wishlist/handlers/remove-item.ts b/lib/bigcommerce/api/wishlist/handlers/remove-item.ts new file mode 100644 index 000000000..9be970f11 --- /dev/null +++ b/lib/bigcommerce/api/wishlist/handlers/remove-item.ts @@ -0,0 +1,25 @@ +import type { WishlistHandlers } from '..' + +// Return current wishlist info +const removeItem: WishlistHandlers['removeItem'] = async ({ + res, + body: { wishlistId, itemId }, + config, +}) => { + if (!wishlistId || !itemId) { + return res.status(400).json({ + data: null, + errors: [{ message: 'Invalid request' }], + }) + } + + const result = await config.storeApiFetch<{ data: any } | null>( + `/v3/wishlists/${wishlistId}/items/${itemId}`, + { method: 'DELETE' } + ) + const data = result?.data ?? null + + res.status(200).json({ data }) +} + +export default removeItem diff --git a/lib/bigcommerce/api/wishlist/handlers/remove-wishlist.ts b/lib/bigcommerce/api/wishlist/handlers/remove-wishlist.ts new file mode 100644 index 000000000..41b210024 --- /dev/null +++ b/lib/bigcommerce/api/wishlist/handlers/remove-wishlist.ts @@ -0,0 +1,25 @@ +import type { WishlistHandlers } from '..' + +// Return current wishlist info +const removeWishlist: WishlistHandlers['removeWishlist'] = async ({ + res, + body: { wishlistId }, + config, +}) => { + if (!wishlistId) { + return res.status(400).json({ + data: null, + errors: [{ message: 'Invalid request' }], + }) + } + + const result = await config.storeApiFetch<{ data: any } | null>( + `/v3/wishlists/${wishlistId}/`, + { method: 'DELETE' } + ) + const data = result?.data ?? null + + res.status(200).json({ data }) +} + +export default removeWishlist diff --git a/lib/bigcommerce/api/wishlist/handlers/update-wishlist.ts b/lib/bigcommerce/api/wishlist/handlers/update-wishlist.ts new file mode 100644 index 000000000..ea1753b65 --- /dev/null +++ b/lib/bigcommerce/api/wishlist/handlers/update-wishlist.ts @@ -0,0 +1,27 @@ +import type { WishlistHandlers } from '..' + +// Update wish info +const updateWishlist: WishlistHandlers['updateWishlist'] = async ({ + res, + body: { wishlistId, wishlist }, + config, +}) => { + if (!wishlistId || !wishlist) { + return res.status(400).json({ + data: null, + errors: [{ message: 'Invalid request' }], + }) + } + + const { data } = await config.storeApiFetch( + `/v3/wishlists/${wishlistId}/`, + { + method: 'PUT', + body: JSON.stringify(wishlist), + } + ) + + res.status(200).json({ data }) +} + +export default updateWishlist diff --git a/lib/bigcommerce/api/wishlist/index.ts b/lib/bigcommerce/api/wishlist/index.ts new file mode 100644 index 000000000..912d59491 --- /dev/null +++ b/lib/bigcommerce/api/wishlist/index.ts @@ -0,0 +1,152 @@ +import isAllowedMethod from '../utils/is-allowed-method' +import createApiHandler, { + BigcommerceApiHandler, + BigcommerceHandler, +} from '../utils/create-api-handler' +import { BigcommerceApiError } from '../utils/errors' +import getWishlist from './handlers/get-wishlist' +import getAllWishlists from './handlers/get-all-wishlists' +import addItem from './handlers/add-item' +import removeItem from './handlers/remove-item' +import updateWishlist from './handlers/update-wishlist' +import removeWishlist from './handlers/remove-wishlist' +import addWishlist from './handlers/add-wishlist' + +type Body = Partial | undefined + +export type ItemBody = { + product_id: number + variant_id: number +} + +export type AddItemBody = { wishlistId: string; item: ItemBody } + +export type RemoveItemBody = { wishlistId: string; itemId: string } + +export type WishlistBody = { + customer_id: number + is_public: number + name: string + items: any[] +} + +export type AddWishlistBody = { wishlist: WishlistBody } + +// TODO: this type should match: +// https://developer.bigcommerce.com/api-reference/store-management/wishlists/wishlists/wishlistsbyidget +export type Wishlist = { + id: string + customer_id: number + name: string + is_public: boolean + token: string + items: any[] + // TODO: add missing fields +} + +export type WishlistList = Wishlist[] + +export type WishlistHandlers = { + getAllWishlists: BigcommerceHandler + getWishlist: BigcommerceHandler + addWishlist: BigcommerceHandler< + Wishlist, + { wishlistId: string } & Body + > + updateWishlist: BigcommerceHandler< + Wishlist, + { wishlistId: string } & Body + > + addItem: BigcommerceHandler> + removeItem: BigcommerceHandler< + Wishlist, + { wishlistId: string } & Body + > + removeWishlist: BigcommerceHandler +} + +const METHODS = ['GET', 'POST', 'PUT', 'DELETE'] + +// TODO: a complete implementation should have schema validation for `req.body` +const wishlistApi: BigcommerceApiHandler = async ( + req, + res, + config, + handlers +) => { + if (!isAllowedMethod(req, res, METHODS)) return + + try { + const { wishlistId, itemId, customerId } = req.body + // Return current wishlist info + if (req.method === 'GET' && wishlistId) { + const body = { wishlistId: wishlistId as string } + return await handlers['getWishlist']({ req, res, config, body }) + } + + // Add an item to the wishlist + if (req.method === 'POST' && wishlistId) { + const body = { wishlistId, ...req.body } + return await handlers['addItem']({ req, res, config, body }) + } + + // Update a wishlist + if (req.method === 'PUT' && wishlistId) { + const body = { wishlistId, ...req.body } + return await handlers['updateWishlist']({ req, res, config, body }) + } + + // Remove an item from the wishlist + if (req.method === 'DELETE' && wishlistId && itemId) { + const body = { + wishlistId: wishlistId as string, + itemId: itemId as string, + } + return await handlers['removeItem']({ req, res, config, body }) + } + + // Remove the wishlist + if (req.method === 'DELETE' && wishlistId && !itemId) { + const body = { wishlistId: wishlistId as string } + return await handlers['removeWishlist']({ req, res, config, body }) + } + + // Get all the wishlists + if (req.method === 'GET' && !wishlistId) { + const body = { customerId: customerId as string } + return await handlers['getAllWishlists']({ + req, + res: res as any, + config, + body, + }) + } + + // Create a wishlist + if (req.method === 'POST' && !wishlistId) { + const { body } = req + return await handlers['addWishlist']({ req, res, config, body }) + } + } catch (error) { + console.error(error) + + const message = + error instanceof BigcommerceApiError + ? 'An unexpected error ocurred with the Bigcommerce API' + : 'An unexpected error ocurred' + + res.status(500).json({ data: null, errors: [{ message }] }) + } +} + +export const handlers = { + getWishlist, + addItem, + updateWishlist, + removeItem, + removeWishlist, + getAllWishlists, + addWishlist, +} + +export default createApiHandler(wishlistApi, handlers, {}) diff --git a/lib/bigcommerce/wishlist/use-add-item.tsx b/lib/bigcommerce/wishlist/use-add-item.tsx new file mode 100644 index 000000000..862041bbd --- /dev/null +++ b/lib/bigcommerce/wishlist/use-add-item.tsx @@ -0,0 +1,46 @@ +import { useCallback } from 'react' +import { HookFetcher } from '@lib/commerce/utils/types' +import useAction from '@lib/commerce/utils/use-action' +import type { ItemBody, AddItemBody } from '../api/wishlist' +import useWishlist, { Wishlist } from './use-wishlist' + +const defaultOpts = { + url: '/api/bigcommerce/wishlist', + method: 'POST', +} + +export type AddItemInput = ItemBody + +export const fetcher: HookFetcher = ( + options, + { wishlistId, item }, + fetch +) => { + return fetch({ + url: options?.url ?? defaultOpts.url, + method: options?.method ?? defaultOpts.method, + body: { wishlistId, item }, + }) +} + +export function extendHook(customFetcher: typeof fetcher) { + const useAddItem = (wishlistId: string) => { + const { mutate } = useWishlist(wishlistId) + const fn = useAction(defaultOpts, customFetcher) + + return useCallback( + async function addItem(input: AddItemInput) { + const data = await fn({ wishlistId, item: input }) + await mutate(data, false) + return data + }, + [fn, mutate] + ) + } + + useAddItem.extend = extendHook + + return useAddItem +} + +export default extendHook(fetcher) diff --git a/lib/bigcommerce/wishlist/use-remove-item.tsx b/lib/bigcommerce/wishlist/use-remove-item.tsx new file mode 100644 index 000000000..ca9648d35 --- /dev/null +++ b/lib/bigcommerce/wishlist/use-remove-item.tsx @@ -0,0 +1,51 @@ +import { useCallback } from 'react' +import { HookFetcher } from '@lib/commerce/utils/types' +import useAction from '@lib/commerce/utils/use-action' +import type { RemoveItemBody } from '../api/wishlist' +import useWishlist, { Wishlist } from './use-wishlist' + +const defaultOpts = { + url: '/api/bigcommerce/wishlists', + method: 'DELETE', +} + +export type RemoveItemInput = { + id: string +} + +export const fetcher: HookFetcher = ( + options, + { wishlistId, itemId }, + fetch +) => { + return fetch({ + url: options?.url ?? defaultOpts.url, + method: options?.method ?? defaultOpts.method, + body: { wishlistId, itemId }, + }) +} + +export function extendHook(customFetcher: typeof fetcher) { + const useRemoveItem = (wishlistId: string, item?: any) => { + const { mutate } = useWishlist(wishlistId) + const fn = useAction( + defaultOpts, + customFetcher + ) + + return useCallback( + async function removeItem(input: RemoveItemInput) { + const data = await fn({ wishlistId, itemId: input.id ?? item?.id }) + await mutate(data, false) + return data + }, + [fn, mutate] + ) + } + + useRemoveItem.extend = extendHook + + return useRemoveItem +} + +export default extendHook(fetcher) diff --git a/lib/bigcommerce/wishlist/use-wishlist-actions.tsx b/lib/bigcommerce/wishlist/use-wishlist-actions.tsx new file mode 100644 index 000000000..7301994b0 --- /dev/null +++ b/lib/bigcommerce/wishlist/use-wishlist-actions.tsx @@ -0,0 +1,11 @@ +import useAddItem from './use-add-item' +import useRemoveItem from './use-remove-item' + +// This hook is probably not going to be used, but it's here +// to show how a commerce should be structuring it +export default function useWishlistActions(wishlistId: string) { + const addItem = useAddItem(wishlistId) + const removeItem = useRemoveItem(wishlistId) + + return { addItem, removeItem } +} diff --git a/lib/bigcommerce/wishlist/use-wishlist.tsx b/lib/bigcommerce/wishlist/use-wishlist.tsx new file mode 100644 index 000000000..1d93609f0 --- /dev/null +++ b/lib/bigcommerce/wishlist/use-wishlist.tsx @@ -0,0 +1,41 @@ +import { HookFetcher } from '@lib/commerce/utils/types' +import useData from '@lib/commerce/utils/use-data' +import type { Wishlist } from '../api/wishlist' + +const defaultOpts = { + url: '/api/bigcommerce/wishlists', +} + +export type { Wishlist } + +export type WishlistInput = { + wishlistId: string | undefined +} + +export const fetcher: HookFetcher = ( + options, + { wishlistId }, + fetch +) => { + return fetch({ + url: options?.url, + body: { wishlistId }, + }) +} + +export function extendHook(customFetcher: typeof fetcher) { + const useWishlists = (wishlistId: string) => { + const fetchFn: typeof fetcher = (options, input, fetch) => { + return customFetcher(options, input, fetch) + } + const response = useData(defaultOpts, [['wishlistId', wishlistId]], fetchFn) + + return response + } + + useWishlists.extend = extendHook + + return useWishlists +} + +export default extendHook(fetcher) From 453b7b54e8c080e68f7e2c59d1f4581a0977acc6 Mon Sep 17 00:00:00 2001 From: Belen Curcio Date: Mon, 19 Oct 2020 11:23:10 -0300 Subject: [PATCH 07/15] Changes to search UI --- pages/search.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/search.tsx b/pages/search.tsx index 24238768c..7d0721f3f 100644 --- a/pages/search.tsx +++ b/pages/search.tsx @@ -149,7 +149,7 @@ export default function Search({ ))} ) : ( - + {range(12).map(() => ( Date: Mon, 19 Oct 2020 11:23:53 -0300 Subject: [PATCH 08/15] Changes to hook --- lib/commerce/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/commerce/index.tsx b/lib/commerce/index.tsx index adb0fc37a..3627e3774 100644 --- a/lib/commerce/index.tsx +++ b/lib/commerce/index.tsx @@ -8,7 +8,7 @@ import { } from 'react' import { Fetcher } from './utils/types' -const Commerce = createContext(null) +const Commerce = createContext({}) export type CommerceProps = { children?: ReactNode From ab51207548af314788be745ba6b96c1fd42b1099 Mon Sep 17 00:00:00 2001 From: Belen Curcio Date: Mon, 19 Oct 2020 12:02:17 -0300 Subject: [PATCH 09/15] Active Product Page back to working again --- .../product/ProductView/ProductView.tsx | 25 +++++++------------ components/product/Swatch/Swatch.tsx | 3 ++- lib/logger.ts | 15 ++++++++++- package.json | 2 ++ yarn.lock | 12 +++++++++ 5 files changed, 39 insertions(+), 18 deletions(-) diff --git a/components/product/ProductView/ProductView.tsx b/components/product/ProductView/ProductView.tsx index e8f91c99b..71d874a25 100644 --- a/components/product/ProductView/ProductView.tsx +++ b/components/product/ProductView/ProductView.tsx @@ -15,19 +15,12 @@ interface Props { product: Product } -interface Choices { - size?: string | null - color?: string | null -} - const ProductView: FC = ({ product, className }) => { - const options = getProductOptions(product) - // console.log(options) - const addItem = useAddItem() const { openSidebar } = useUI() + const options = getProductOptions(product) - const [choices, setChoices] = useState({ + const [choices, setChoices] = useState>({ size: null, color: null, }) @@ -48,9 +41,6 @@ const ProductView: FC = ({ product, className }) => { } } - const activeSize = choices.size - const activeColor = choices.color - return ( = ({ product, className }) => { {/** TODO: Change with Image Component */} {product.images.edges?.map((image, i) => ( = ({ product, className }) => {
{options?.map((opt: any) => ( -
+

{opt.displayName}

{opt.values.map((v: any) => { + const active = choices[opt.displayName] + return ( + onClick={() => { setChoices((choices) => { return { ...choices, [opt.displayName]: v.label, } }) - } + }} /> ) })} diff --git a/components/product/Swatch/Swatch.tsx b/components/product/Swatch/Swatch.tsx index 3085e6e0a..6d8a7dfb2 100644 --- a/components/product/Swatch/Swatch.tsx +++ b/components/product/Swatch/Swatch.tsx @@ -24,7 +24,7 @@ const Swatch: FC = ({ }) => { variant = variant?.toLowerCase() label = label?.toLowerCase() - // console.log(variant) + const rootClassName = cn( s.root, { @@ -38,6 +38,7 @@ const Swatch: FC = ({ + + Don't have an account? + {` `} + + Sign Up + + +
+
+ +
+ ) +} + +Login.Layout = Layout From 707f814244b7c78dbaa7b4a073449f1e91faab79 Mon Sep 17 00:00:00 2001 From: Belen Curcio Date: Mon, 19 Oct 2020 16:28:05 -0300 Subject: [PATCH 14/15] Utilities to handle Colors --- components/icon/ArrowLeft.tsx | 12 +++---- components/icon/Check.tsx | 6 ++-- components/icon/Minus.tsx | 6 ++-- components/icon/Plus.tsx | 12 +++---- .../product/ProductView/ProductView.tsx | 1 + components/product/Swatch/Swatch.module.css | 2 +- components/product/Swatch/Swatch.tsx | 7 ++-- lib/colors.ts | 33 +++++++++++++++++++ 8 files changed, 56 insertions(+), 23 deletions(-) diff --git a/components/icon/ArrowLeft.tsx b/components/icon/ArrowLeft.tsx index ed80ca7a7..8cc1e1294 100644 --- a/components/icon/ArrowLeft.tsx +++ b/components/icon/ArrowLeft.tsx @@ -10,15 +10,15 @@ const ArrowLeft = ({ ...props }) => { > ) diff --git a/components/icon/Check.tsx b/components/icon/Check.tsx index ce37027f4..89c91a1e3 100644 --- a/components/icon/Check.tsx +++ b/components/icon/Check.tsx @@ -10,9 +10,9 @@ const Check = ({ ...props }) => { > ) diff --git a/components/icon/Minus.tsx b/components/icon/Minus.tsx index f41aa3cf0..1e9411dda 100644 --- a/components/icon/Minus.tsx +++ b/components/icon/Minus.tsx @@ -4,9 +4,9 @@ const Minus = ({ ...props }) => { ) diff --git a/components/icon/Plus.tsx b/components/icon/Plus.tsx index 1fca1ac9d..ad030b92e 100644 --- a/components/icon/Plus.tsx +++ b/components/icon/Plus.tsx @@ -4,16 +4,16 @@ const Plus = ({ ...props }) => { ) diff --git a/components/product/ProductView/ProductView.tsx b/components/product/ProductView/ProductView.tsx index 71d874a25..a0016365f 100644 --- a/components/product/ProductView/ProductView.tsx +++ b/components/product/ProductView/ProductView.tsx @@ -110,6 +110,7 @@ const ProductView: FC = ({ product, className }) => { label={v.label} onClick={() => { setChoices((choices) => { + console.log(choices) return { ...choices, [opt.displayName]: v.label, diff --git a/components/product/Swatch/Swatch.module.css b/components/product/Swatch/Swatch.module.css index cb35c0b71..137f23749 100644 --- a/components/product/Swatch/Swatch.module.css +++ b/components/product/Swatch/Swatch.module.css @@ -1,7 +1,7 @@ .root { @apply h-12 w-12 bg-primary text-primary rounded-full mr-3 inline-flex items-center justify-center cursor-pointer transition duration-100 ease-in-out - p-0 shadow-none border-gray-200 border box-border; + p-0 shadow-none border-gray-200 border box-border text-black; } .active.size { diff --git a/components/product/Swatch/Swatch.tsx b/components/product/Swatch/Swatch.tsx index 6d8a7dfb2..49befcd28 100644 --- a/components/product/Swatch/Swatch.tsx +++ b/components/product/Swatch/Swatch.tsx @@ -1,10 +1,9 @@ import cn from 'classnames' import { FC } from 'react' import s from './Swatch.module.css' -import { Colors } from '@components/ui/types' import { Check } from '@components/icon' import Button, { ButtonProps } from '@components/ui/Button' - +import { isDark } from '@lib/colors' interface Props { active?: boolean children?: any @@ -24,6 +23,7 @@ const Swatch: FC = ({ }) => { variant = variant?.toLowerCase() label = label?.toLowerCase() + const isDarkBg = isDark(color) const rootClassName = cn( s.root, @@ -43,8 +43,7 @@ const Swatch: FC = ({ {variant === 'color' && active && ( diff --git a/lib/colors.ts b/lib/colors.ts index 2d4ca14cc..fbd1443ea 100644 --- a/lib/colors.ts +++ b/lib/colors.ts @@ -14,3 +14,36 @@ export function getRandomPairOfColors() { // Returns a pair of colors return [colors[idx], colors[idx2]] } + +function hexToRgb(hex: string = '') { + const match = hex.toString(16).match(/[a-f0-9]{6}|[a-f0-9]{3}/i) + + if (!match) { + return [0, 0, 0] + } + + let colorString = match[0] + + if (match[0].length === 3) { + colorString = colorString + .split('') + .map((char: string) => { + return char + char + }) + .join('') + } + + const integer = parseInt(colorString, 16) + const r = (integer >> 16) & 0xff + const g = (integer >> 8) & 0xff + const b = integer & 0xff + + return [r, g, b] +} + +export function isDark(color = '') { + // Equation from http://24ways.org/2010/calculating-color-contrast + const rgb = hexToRgb(color) + const res = (rgb[0] * 299 + rgb[1] * 587 + rgb[2] * 114) / 1000 + return res < 128 +} From e2dd854f10e839321a0e379edf764b44e4508bca Mon Sep 17 00:00:00 2001 From: Belen Curcio Date: Mon, 19 Oct 2020 16:53:02 -0300 Subject: [PATCH 15/15] Utilities to handle Colors --- components/product/ProductView/ProductView.tsx | 1 - lib/colors.ts | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/components/product/ProductView/ProductView.tsx b/components/product/ProductView/ProductView.tsx index a0016365f..444ab4e42 100644 --- a/components/product/ProductView/ProductView.tsx +++ b/components/product/ProductView/ProductView.tsx @@ -1,7 +1,6 @@ import { NextSeo } from 'next-seo' import { FC, useState } from 'react' import s from './ProductView.module.css' -import { Colors } from '@components/ui/types' import { useUI } from '@components/ui/context' import { Button, Container } from '@components/ui' import { Swatch, ProductSlider } from '@components/product' diff --git a/lib/colors.ts b/lib/colors.ts index fbd1443ea..2ee56b150 100644 --- a/lib/colors.ts +++ b/lib/colors.ts @@ -16,6 +16,7 @@ export function getRandomPairOfColors() { } function hexToRgb(hex: string = '') { + // @ts-ignore const match = hex.toString(16).match(/[a-f0-9]{6}|[a-f0-9]{3}/i) if (!match) {