Add variants to sale view (#1420)
* Update schema and biuld types for sale per variant * Create variant search module and generate types for it * Add listing component for sale view * Create dialog for variant assignment * Expand sale page with vairnats * Add new sale fixtures * Add transaltions for variants on sale view * Update snapshot * Refactor sales dialogs and tables, move styles and ittl to local files * Rework search dialog. Create item/subitem selectable table for variants, update spapshot * Adjust table columns width * Standardize the tables * Unify messages * Drop whole variant object in favor of just ids, simplify filtring functions * Update snapshots Co-authored-by: Jakub Majorek <majorek.jakub@gmail.com>
This commit is contained in:
parent
2407ae6f76
commit
ec230e55c0
50 changed files with 2006 additions and 392 deletions
|
@ -492,17 +492,9 @@
|
||||||
"context": "number of products",
|
"context": "number of products",
|
||||||
"string": "Products ({quantity})"
|
"string": "Products ({quantity})"
|
||||||
},
|
},
|
||||||
"saleDetailsUnassignCategory": {
|
"saleDetailsPageVariantsQuantity": {
|
||||||
"context": "unassign category from sale, button",
|
"context": "number of variants",
|
||||||
"string": "Unassign"
|
"string": "Variants ({quantity})"
|
||||||
},
|
|
||||||
"saleDetailsUnassignCollection": {
|
|
||||||
"context": "unassign collection from sale, button",
|
|
||||||
"string": "Unassign"
|
|
||||||
},
|
|
||||||
"saleDetailsUnassignProduct": {
|
|
||||||
"context": "unassign product from sale, button",
|
|
||||||
"string": "Unassign"
|
|
||||||
},
|
},
|
||||||
"set availability date": {
|
"set availability date": {
|
||||||
"context": "product availability date label",
|
"context": "product availability date label",
|
||||||
|
@ -1889,44 +1881,69 @@
|
||||||
"context": "placeholder",
|
"context": "placeholder",
|
||||||
"string": "Search by value name, etc..."
|
"string": "Search by value name, etc..."
|
||||||
},
|
},
|
||||||
"src_dot_components_dot_AssignCategoryDialog_dot_3125506097": {
|
"src_dot_components_dot_AssignCategoryDialog_dot_assignCategoryDialogHeader": {
|
||||||
"context": "dialog header",
|
"context": "dialog header",
|
||||||
"string": "Assign Category"
|
"string": "Assign Category"
|
||||||
},
|
},
|
||||||
"src_dot_components_dot_AssignCategoryDialog_dot_3690273268": {
|
"src_dot_components_dot_AssignCategoryDialog_dot_assignCategoryDialogLabel": {
|
||||||
"string": "Search by category name, etc..."
|
"context": "dialog header",
|
||||||
},
|
|
||||||
"src_dot_components_dot_AssignCategoryDialog_dot_3841025483": {
|
|
||||||
"string": "Search Category"
|
"string": "Search Category"
|
||||||
},
|
},
|
||||||
"src_dot_components_dot_AssignCollectionDialog_dot_2605414502": {
|
"src_dot_components_dot_AssignCategoryDialog_dot_assignCategoryDialogPlaceholder": {
|
||||||
"string": "Search by collection name, etc..."
|
"context": "dialog search placeholder",
|
||||||
|
"string": "Search by category name, etc..."
|
||||||
},
|
},
|
||||||
"src_dot_components_dot_AssignCollectionDialog_dot_3992923611": {
|
"src_dot_components_dot_AssignCollectionDialog_dot_assignCollectionDialogHeader": {
|
||||||
"context": "dialog header",
|
"context": "dialog header",
|
||||||
"string": "Assign Collection"
|
"string": "Assign Collection"
|
||||||
},
|
},
|
||||||
"src_dot_components_dot_AssignCollectionDialog_dot_4057224233": {
|
"src_dot_components_dot_AssignCollectionDialog_dot_assignCollectionDialogLabel": {
|
||||||
|
"context": "dialog header",
|
||||||
"string": "Search Collection"
|
"string": "Search Collection"
|
||||||
},
|
},
|
||||||
"src_dot_components_dot_AssignContainerDialog_dot_1731102929": {
|
"src_dot_components_dot_AssignCollectionDialog_dot_assignCollectionDialogPlaceholder": {
|
||||||
|
"context": "dialog search placeholder",
|
||||||
|
"string": "Search by collection name, etc..."
|
||||||
|
},
|
||||||
|
"src_dot_components_dot_AssignContainerDialog_dot_assignContainerDialogButton": {
|
||||||
"context": "button",
|
"context": "button",
|
||||||
"string": "Assign"
|
"string": "Assign"
|
||||||
},
|
},
|
||||||
"src_dot_components_dot_AssignProductDialog_dot_2100305525": {
|
"src_dot_components_dot_AssignProductDialog_dot_assignProductDialogButton": {
|
||||||
"context": "button",
|
"context": "button",
|
||||||
"string": "Assign products"
|
"string": "Assign"
|
||||||
},
|
},
|
||||||
"src_dot_components_dot_AssignProductDialog_dot_2336947364": {
|
"src_dot_components_dot_AssignProductDialog_dot_assignProductDialogContent": {
|
||||||
"string": "Search by product name, attribute, product type etc..."
|
|
||||||
},
|
|
||||||
"src_dot_components_dot_AssignProductDialog_dot_2850255786": {
|
|
||||||
"string": "Search Products"
|
"string": "Search Products"
|
||||||
},
|
},
|
||||||
"src_dot_components_dot_AssignProductDialog_dot_649693468": {
|
"src_dot_components_dot_AssignProductDialog_dot_assignProductDialogSearch": {
|
||||||
|
"string": "Search by product name, attribute, product type etc..."
|
||||||
|
},
|
||||||
|
"src_dot_components_dot_AssignProductDialog_dot_assignVariantDialogHeader": {
|
||||||
"context": "dialog header",
|
"context": "dialog header",
|
||||||
"string": "Assign Product"
|
"string": "Assign Product"
|
||||||
},
|
},
|
||||||
|
"src_dot_components_dot_AssignVariantDialog_dot_3284796469": {
|
||||||
|
"string": "No products available in order channel matching given query"
|
||||||
|
},
|
||||||
|
"src_dot_components_dot_AssignVariantDialog_dot_assignVariantDialogButton": {
|
||||||
|
"context": "button",
|
||||||
|
"string": "Assign"
|
||||||
|
},
|
||||||
|
"src_dot_components_dot_AssignVariantDialog_dot_assignVariantDialogContent": {
|
||||||
|
"string": "Search Variants"
|
||||||
|
},
|
||||||
|
"src_dot_components_dot_AssignVariantDialog_dot_assignVariantDialogHeader": {
|
||||||
|
"context": "dialog header",
|
||||||
|
"string": "Assign Variant"
|
||||||
|
},
|
||||||
|
"src_dot_components_dot_AssignVariantDialog_dot_assignVariantDialogSKU": {
|
||||||
|
"context": "variant sku",
|
||||||
|
"string": "SKU {sku}"
|
||||||
|
},
|
||||||
|
"src_dot_components_dot_AssignVariantDialog_dot_assignVariantDialogSearch": {
|
||||||
|
"string": "Search by product name, attribute, product type etc..."
|
||||||
|
},
|
||||||
"src_dot_components_dot_AttributeUnassignDialog_dot_2037985699": {
|
"src_dot_components_dot_AttributeUnassignDialog_dot_2037985699": {
|
||||||
"string": "Are you sure you want to unassign {attributeName} from {itemTypeName}?"
|
"string": "Are you sure you want to unassign {attributeName} from {itemTypeName}?"
|
||||||
},
|
},
|
||||||
|
@ -2835,42 +2852,46 @@
|
||||||
"src_dot_discounts": {
|
"src_dot_discounts": {
|
||||||
"string": "Discounts"
|
"string": "Discounts"
|
||||||
},
|
},
|
||||||
"src_dot_discounts_dot_components_dot_DiscountCategories_dot_1567318211": {
|
"src_dot_discounts_dot_components_dot_DiscountCategories_dot_discountCategoriesButton": {
|
||||||
"string": "Category name"
|
|
||||||
},
|
|
||||||
"src_dot_discounts_dot_components_dot_DiscountCategories_dot_1681512341": {
|
|
||||||
"context": "section header",
|
|
||||||
"string": "Eligible Categories"
|
|
||||||
},
|
|
||||||
"src_dot_discounts_dot_components_dot_DiscountCategories_dot_2054128296": {
|
|
||||||
"string": "No categories found"
|
|
||||||
},
|
|
||||||
"src_dot_discounts_dot_components_dot_DiscountCategories_dot_2968663655": {
|
|
||||||
"context": "number of products",
|
|
||||||
"string": "Products"
|
|
||||||
},
|
|
||||||
"src_dot_discounts_dot_components_dot_DiscountCategories_dot_3973677075": {
|
|
||||||
"context": "button",
|
"context": "button",
|
||||||
"string": "Assign categories"
|
"string": "Assign categories"
|
||||||
},
|
},
|
||||||
"src_dot_discounts_dot_components_dot_DiscountCollections_dot_1035511604": {
|
"src_dot_discounts_dot_components_dot_DiscountCategories_dot_discountCategoriesHeader": {
|
||||||
"context": "button",
|
"context": "section header",
|
||||||
"string": "Assign collections"
|
"string": "Eligible Categories"
|
||||||
},
|
},
|
||||||
"src_dot_discounts_dot_components_dot_DiscountCollections_dot_2137803833": {
|
"src_dot_discounts_dot_components_dot_DiscountCategories_dot_discountCategoriesNotFound": {
|
||||||
"string": "No collections found"
|
"context": "no categories",
|
||||||
|
"string": "No categories found"
|
||||||
},
|
},
|
||||||
"src_dot_discounts_dot_components_dot_DiscountCollections_dot_2968663655": {
|
"src_dot_discounts_dot_components_dot_DiscountCategories_dot_discountCategoriesTableProductHeader": {
|
||||||
|
"context": "table head",
|
||||||
|
"string": "Category Name"
|
||||||
|
},
|
||||||
|
"src_dot_discounts_dot_components_dot_DiscountCategories_dot_discountCategoriesTableProductNumber": {
|
||||||
"context": "number of products",
|
"context": "number of products",
|
||||||
"string": "Products"
|
"string": "Products"
|
||||||
},
|
},
|
||||||
"src_dot_discounts_dot_components_dot_DiscountCollections_dot_3011396316": {
|
"src_dot_discounts_dot_components_dot_DiscountCollections_dot_discountCollectionsButton": {
|
||||||
"string": "Collection name"
|
"context": "button",
|
||||||
|
"string": "Assign collections"
|
||||||
},
|
},
|
||||||
"src_dot_discounts_dot_components_dot_DiscountCollections_dot_452750900": {
|
"src_dot_discounts_dot_components_dot_DiscountCollections_dot_discountCollectionsHeader": {
|
||||||
"context": "section header",
|
"context": "section header",
|
||||||
"string": "Eligible Collections"
|
"string": "Eligible Collections"
|
||||||
},
|
},
|
||||||
|
"src_dot_discounts_dot_components_dot_DiscountCollections_dot_discountCollectionsNotFound": {
|
||||||
|
"context": "no collections",
|
||||||
|
"string": "No collections found"
|
||||||
|
},
|
||||||
|
"src_dot_discounts_dot_components_dot_DiscountCollections_dot_discountCollectionsTableProductHeader": {
|
||||||
|
"context": "table head",
|
||||||
|
"string": "Collection Name"
|
||||||
|
},
|
||||||
|
"src_dot_discounts_dot_components_dot_DiscountCollections_dot_discountCollectionsTableProductNumber": {
|
||||||
|
"context": "number of products",
|
||||||
|
"string": "Products"
|
||||||
|
},
|
||||||
"src_dot_discounts_dot_components_dot_DiscountCountrySelectDialog_dot_1585396479": {
|
"src_dot_discounts_dot_components_dot_DiscountCountrySelectDialog_dot_1585396479": {
|
||||||
"context": "dialog header",
|
"context": "dialog header",
|
||||||
"string": "Assign Countries"
|
"string": "Assign Countries"
|
||||||
|
@ -2902,26 +2923,53 @@
|
||||||
"context": "time during discount is active, header",
|
"context": "time during discount is active, header",
|
||||||
"string": "Active Dates"
|
"string": "Active Dates"
|
||||||
},
|
},
|
||||||
"src_dot_discounts_dot_components_dot_DiscountProducts_dot_1657559629": {
|
"src_dot_discounts_dot_components_dot_DiscountProducts_dot_discountProductsButton": {
|
||||||
"string": "No products found"
|
|
||||||
},
|
|
||||||
"src_dot_discounts_dot_components_dot_DiscountProducts_dot_2100305525": {
|
|
||||||
"context": "button",
|
"context": "button",
|
||||||
"string": "Assign products"
|
"string": "Assign products"
|
||||||
},
|
},
|
||||||
"src_dot_discounts_dot_components_dot_DiscountProducts_dot_2697405188": {
|
"src_dot_discounts_dot_components_dot_DiscountProducts_dot_discountProductsHeader": {
|
||||||
"string": "Product Name"
|
"context": "section header",
|
||||||
|
"string": "Eligible Products"
|
||||||
},
|
},
|
||||||
"src_dot_discounts_dot_components_dot_DiscountProducts_dot_3326160357": {
|
"src_dot_discounts_dot_components_dot_DiscountProducts_dot_discountProductsNotFound": {
|
||||||
|
"context": "no products",
|
||||||
|
"string": "No products found"
|
||||||
|
},
|
||||||
|
"src_dot_discounts_dot_components_dot_DiscountProducts_dot_discountProductsTableAvailabilityHeader": {
|
||||||
"context": "product availability",
|
"context": "product availability",
|
||||||
"string": "Availability"
|
"string": "Availability"
|
||||||
},
|
},
|
||||||
"src_dot_discounts_dot_components_dot_DiscountProducts_dot_4257289053": {
|
"src_dot_discounts_dot_components_dot_DiscountProducts_dot_discountProductsTableProductHeader": {
|
||||||
|
"context": "table head",
|
||||||
|
"string": "Product Name"
|
||||||
|
},
|
||||||
|
"src_dot_discounts_dot_components_dot_DiscountProducts_dot_discountProductsTableTypeHeader": {
|
||||||
|
"context": "product type",
|
||||||
"string": "Product Type"
|
"string": "Product Type"
|
||||||
},
|
},
|
||||||
"src_dot_discounts_dot_components_dot_DiscountProducts_dot_919175218": {
|
"src_dot_discounts_dot_components_dot_DiscountVariants_dot_discountVariantsButton": {
|
||||||
|
"context": "button",
|
||||||
|
"string": "Assign variants"
|
||||||
|
},
|
||||||
|
"src_dot_discounts_dot_components_dot_DiscountVariants_dot_discountVariantsHeader": {
|
||||||
"context": "section header",
|
"context": "section header",
|
||||||
"string": "Eligible Products"
|
"string": "Eligible Variants"
|
||||||
|
},
|
||||||
|
"src_dot_discounts_dot_components_dot_DiscountVariants_dot_discountVariantsNotFound": {
|
||||||
|
"context": "no variants",
|
||||||
|
"string": "No variants found"
|
||||||
|
},
|
||||||
|
"src_dot_discounts_dot_components_dot_DiscountVariants_dot_discountVariantsTableProductHeader": {
|
||||||
|
"context": "table head",
|
||||||
|
"string": "Product Name"
|
||||||
|
},
|
||||||
|
"src_dot_discounts_dot_components_dot_DiscountVariants_dot_discountVariantsTableTypeHeader": {
|
||||||
|
"context": "table head",
|
||||||
|
"string": "Product Type"
|
||||||
|
},
|
||||||
|
"src_dot_discounts_dot_components_dot_DiscountVariants_dot_discountVariantsTableVariantHeader": {
|
||||||
|
"context": "table head",
|
||||||
|
"string": "Variant Name"
|
||||||
},
|
},
|
||||||
"src_dot_discounts_dot_components_dot_SaleCreatePage_dot_3866518732": {
|
"src_dot_discounts_dot_components_dot_SaleCreatePage_dot_3866518732": {
|
||||||
"context": "page header",
|
"context": "page header",
|
||||||
|
@ -3288,44 +3336,74 @@
|
||||||
"src_dot_discounts_dot_views_dot_SaleCreate_dot_480188715": {
|
"src_dot_discounts_dot_views_dot_SaleCreate_dot_480188715": {
|
||||||
"string": "Manage Sales Channel Availability"
|
"string": "Manage Sales Channel Availability"
|
||||||
},
|
},
|
||||||
"src_dot_discounts_dot_views_dot_SaleDetails_dot_1457489953": {
|
"src_dot_discounts_dot_views_dot_SaleDetails_dot_saleDetailsChannelAvailabilityDialogHeader": {
|
||||||
"context": "dialog content",
|
"context": "channel availability dialog header",
|
||||||
"string": "Are you sure you want to delete {saleName}?"
|
|
||||||
},
|
|
||||||
"src_dot_discounts_dot_views_dot_SaleDetails_dot_1827854264": {
|
|
||||||
"context": "dialog header",
|
|
||||||
"string": "Unassign Categories From Sale"
|
|
||||||
},
|
|
||||||
"src_dot_discounts_dot_views_dot_SaleDetails_dot_1952217501": {
|
|
||||||
"context": "dialog header",
|
|
||||||
"string": "Unassign Collections From Sale"
|
|
||||||
},
|
|
||||||
"src_dot_discounts_dot_views_dot_SaleDetails_dot_2353723060": {
|
|
||||||
"context": "dialog content",
|
|
||||||
"string": "{counter,plural,one{Are you sure you want to unassign this category?} other{Are you sure you want to unassign {displayQuantity} categories?}}"
|
|
||||||
},
|
|
||||||
"src_dot_discounts_dot_views_dot_SaleDetails_dot_2534378844": {
|
|
||||||
"string": "Removed sale"
|
|
||||||
},
|
|
||||||
"src_dot_discounts_dot_views_dot_SaleDetails_dot_3215481647": {
|
|
||||||
"context": "dialog content",
|
|
||||||
"string": "{counter,plural,one{Are you sure you want to unassign this product?} other{Are you sure you want to unassign {displayQuantity} products?}}"
|
|
||||||
},
|
|
||||||
"src_dot_discounts_dot_views_dot_SaleDetails_dot_3395246518": {
|
|
||||||
"context": "dialog header",
|
|
||||||
"string": "Unassign Products From Sale"
|
|
||||||
},
|
|
||||||
"src_dot_discounts_dot_views_dot_SaleDetails_dot_3823295269": {
|
|
||||||
"string": "Manage Channel Availability"
|
"string": "Manage Channel Availability"
|
||||||
},
|
},
|
||||||
"src_dot_discounts_dot_views_dot_SaleDetails_dot_506030254": {
|
"src_dot_discounts_dot_views_dot_SaleDetails_dot_saleDetailsSaleDelate": {
|
||||||
|
"context": "sale Details delete button",
|
||||||
|
"string": "Removed sale"
|
||||||
|
},
|
||||||
|
"src_dot_discounts_dot_views_dot_SaleDetails_dot_saleDetailsSaleDeleteDialog": {
|
||||||
|
"context": "dialog content",
|
||||||
|
"string": "Removed sale"
|
||||||
|
},
|
||||||
|
"src_dot_discounts_dot_views_dot_SaleDetails_dot_saleDetailsSaleDeleteDialogHeader": {
|
||||||
"context": "dialog header",
|
"context": "dialog header",
|
||||||
"string": "Delete Sale"
|
"string": "Delete Sale"
|
||||||
},
|
},
|
||||||
"src_dot_discounts_dot_views_dot_SaleDetails_dot_767268203": {
|
"src_dot_discounts_dot_views_dot_SaleDetails_dot_saleDetailsUnassignCategory": {
|
||||||
|
"context": "unassign category from sale, button",
|
||||||
|
"string": "Unassign"
|
||||||
|
},
|
||||||
|
"src_dot_discounts_dot_views_dot_SaleDetails_dot_saleDetailsUnassignCategoryDialog": {
|
||||||
|
"context": "dialog content",
|
||||||
|
"string": "{counter,plural,one{Are you sure you want to unassign this category?} other{Are you sure you want to unassign {displayQuantity} categories?}}"
|
||||||
|
},
|
||||||
|
"src_dot_discounts_dot_views_dot_SaleDetails_dot_saleDetailsUnassignCategoryDialogHeader": {
|
||||||
|
"context": "dialog header",
|
||||||
|
"string": "Unassign Categories From Sale"
|
||||||
|
},
|
||||||
|
"src_dot_discounts_dot_views_dot_SaleDetails_dot_saleDetailsUnassignCollection": {
|
||||||
|
"context": "unassign collection from sale, button",
|
||||||
|
"string": "Unassign"
|
||||||
|
},
|
||||||
|
"src_dot_discounts_dot_views_dot_SaleDetails_dot_saleDetailsUnassignCollectionDialog": {
|
||||||
"context": "dialog content",
|
"context": "dialog content",
|
||||||
"string": "{counter,plural,one{Are you sure you want to unassign this collection?} other{Are you sure you want to unassign {displayQuantity} collections?}}"
|
"string": "{counter,plural,one{Are you sure you want to unassign this collection?} other{Are you sure you want to unassign {displayQuantity} collections?}}"
|
||||||
},
|
},
|
||||||
|
"src_dot_discounts_dot_views_dot_SaleDetails_dot_saleDetailsUnassignCollectionDialogHeader": {
|
||||||
|
"context": "dialog header",
|
||||||
|
"string": "Unassign Collection From Sale"
|
||||||
|
},
|
||||||
|
"src_dot_discounts_dot_views_dot_SaleDetails_dot_saleDetailsUnassignDialogDelete": {
|
||||||
|
"context": "dialog content",
|
||||||
|
"string": "Are you sure you want to delete {saleName}?"
|
||||||
|
},
|
||||||
|
"src_dot_discounts_dot_views_dot_SaleDetails_dot_saleDetailsUnassignProduct": {
|
||||||
|
"context": "unassign product from sale, button",
|
||||||
|
"string": "Unassign"
|
||||||
|
},
|
||||||
|
"src_dot_discounts_dot_views_dot_SaleDetails_dot_saleDetailsUnassignProductDialog": {
|
||||||
|
"context": "dialog content",
|
||||||
|
"string": "{counter,plural,one{Are you sure you want to unassign this product?} other{Are you sure you want to unassign {displayQuantity} products?}}"
|
||||||
|
},
|
||||||
|
"src_dot_discounts_dot_views_dot_SaleDetails_dot_saleDetailsUnassignProductDialogHeader": {
|
||||||
|
"context": "dialog header",
|
||||||
|
"string": "Unassign Product From Sale"
|
||||||
|
},
|
||||||
|
"src_dot_discounts_dot_views_dot_SaleDetails_dot_saleDetailsUnassignVariant": {
|
||||||
|
"context": "unassign variant from sale, button",
|
||||||
|
"string": "Unassign"
|
||||||
|
},
|
||||||
|
"src_dot_discounts_dot_views_dot_SaleDetails_dot_saleDetailsUnassignVariantDialog": {
|
||||||
|
"context": "dialog content",
|
||||||
|
"string": "{counter,plural,one{Are you sure you want to unassign this variant?} other{Are you sure you want to unassign {displayQuantity} variants?}}"
|
||||||
|
},
|
||||||
|
"src_dot_discounts_dot_views_dot_SaleDetails_dot_saleDetailsUnassignVariantDialogHeader": {
|
||||||
|
"context": "dialog header",
|
||||||
|
"string": "Unassign Variant From Sale"
|
||||||
|
},
|
||||||
"src_dot_discounts_dot_views_dot_SaleList_dot_2809303671": {
|
"src_dot_discounts_dot_views_dot_SaleList_dot_2809303671": {
|
||||||
"context": "dialog header",
|
"context": "dialog header",
|
||||||
"string": "Delete Sales"
|
"string": "Delete Sales"
|
||||||
|
|
|
@ -802,6 +802,7 @@ input CatalogueInput {
|
||||||
products: [ID]
|
products: [ID]
|
||||||
categories: [ID]
|
categories: [ID]
|
||||||
collections: [ID]
|
collections: [ID]
|
||||||
|
variants: [ID]
|
||||||
}
|
}
|
||||||
|
|
||||||
type Category implements Node & ObjectWithMetadata {
|
type Category implements Node & ObjectWithMetadata {
|
||||||
|
@ -5905,6 +5906,7 @@ type Sale implements Node & ObjectWithMetadata {
|
||||||
categories(before: String, after: String, first: Int, last: Int): CategoryCountableConnection
|
categories(before: String, after: String, first: Int, last: Int): CategoryCountableConnection
|
||||||
collections(before: String, after: String, first: Int, last: Int): CollectionCountableConnection
|
collections(before: String, after: String, first: Int, last: Int): CollectionCountableConnection
|
||||||
products(before: String, after: String, first: Int, last: Int): ProductCountableConnection
|
products(before: String, after: String, first: Int, last: Int): ProductCountableConnection
|
||||||
|
variants(before: String, after: String, first: Int, last: Int): ProductVariantCountableConnection
|
||||||
translation(languageCode: LanguageCodeEnum!): SaleTranslation
|
translation(languageCode: LanguageCodeEnum!): SaleTranslation
|
||||||
channelListings: [SaleChannelListing!]
|
channelListings: [SaleChannelListing!]
|
||||||
discountValue: Float
|
discountValue: Float
|
||||||
|
@ -5982,6 +5984,7 @@ input SaleInput {
|
||||||
type: DiscountValueTypeEnum
|
type: DiscountValueTypeEnum
|
||||||
value: PositiveDecimal
|
value: PositiveDecimal
|
||||||
products: [ID]
|
products: [ID]
|
||||||
|
variants: [ID]
|
||||||
categories: [ID]
|
categories: [ID]
|
||||||
collections: [ID]
|
collections: [ID]
|
||||||
startDate: DateTime
|
startDate: DateTime
|
||||||
|
@ -7297,4 +7300,4 @@ union _Entity = App | Address | User | Group | ProductVariant | Product | Produc
|
||||||
|
|
||||||
type _Service {
|
type _Service {
|
||||||
sdl: String
|
sdl: String
|
||||||
}
|
}
|
||||||
|
|
|
@ -358,7 +358,7 @@ export const CollectionDetails: React.FC<CollectionDetailsProps> = ({
|
||||||
variables: {
|
variables: {
|
||||||
...paginationState,
|
...paginationState,
|
||||||
collectionId: id,
|
collectionId: id,
|
||||||
productIds: products.map(product => product.id)
|
productIds: products
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { useIntl } from "react-intl";
|
||||||
import AssignContainerDialog, {
|
import AssignContainerDialog, {
|
||||||
AssignContainerDialogProps
|
AssignContainerDialogProps
|
||||||
} from "../AssignContainerDialog";
|
} from "../AssignContainerDialog";
|
||||||
|
import { messages } from "./messages";
|
||||||
|
|
||||||
interface AssignCategoryDialogProps
|
interface AssignCategoryDialogProps
|
||||||
extends Omit<AssignContainerDialogProps, "containers" | "title" | "search"> {
|
extends Omit<AssignContainerDialogProps, "containers" | "title" | "search"> {
|
||||||
|
@ -21,17 +22,12 @@ const AssignCategoryDialog: React.FC<AssignCategoryDialogProps> = ({
|
||||||
<AssignContainerDialog
|
<AssignContainerDialog
|
||||||
containers={categories}
|
containers={categories}
|
||||||
search={{
|
search={{
|
||||||
label: intl.formatMessage({
|
label: intl.formatMessage(messages.assignCategoryDialogLabel),
|
||||||
defaultMessage: "Search Category"
|
placeholder: intl.formatMessage(
|
||||||
}),
|
messages.assignCategoryDialogPlaceholder
|
||||||
placeholder: intl.formatMessage({
|
)
|
||||||
defaultMessage: "Search by category name, etc..."
|
|
||||||
})
|
|
||||||
}}
|
}}
|
||||||
title={intl.formatMessage({
|
title={intl.formatMessage(messages.assignCategoryDialogHeader)}
|
||||||
defaultMessage: "Assign Category",
|
|
||||||
description: "dialog header"
|
|
||||||
})}
|
|
||||||
{...rest}
|
{...rest}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
16
src/components/AssignCategoryDialog/messages.ts
Normal file
16
src/components/AssignCategoryDialog/messages.ts
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
import { defineMessages } from "react-intl";
|
||||||
|
|
||||||
|
export const messages = defineMessages({
|
||||||
|
assignCategoryDialogLabel: {
|
||||||
|
defaultMessage: "Search Category",
|
||||||
|
description: "dialog header"
|
||||||
|
},
|
||||||
|
assignCategoryDialogPlaceholder: {
|
||||||
|
defaultMessage: "Search by category name, etc...",
|
||||||
|
description: "dialog search placeholder"
|
||||||
|
},
|
||||||
|
assignCategoryDialogHeader: {
|
||||||
|
defaultMessage: "Assign Category",
|
||||||
|
description: "dialog header"
|
||||||
|
}
|
||||||
|
});
|
|
@ -5,6 +5,7 @@ import { useIntl } from "react-intl";
|
||||||
import AssignContainerDialog, {
|
import AssignContainerDialog, {
|
||||||
AssignContainerDialogProps
|
AssignContainerDialogProps
|
||||||
} from "../AssignContainerDialog";
|
} from "../AssignContainerDialog";
|
||||||
|
import { messages } from "./messages";
|
||||||
|
|
||||||
interface AssignCollectionDialogProps
|
interface AssignCollectionDialogProps
|
||||||
extends Omit<AssignContainerDialogProps, "containers" | "title" | "search"> {
|
extends Omit<AssignContainerDialogProps, "containers" | "title" | "search"> {
|
||||||
|
@ -21,17 +22,12 @@ const AssignCollectionDialog: React.FC<AssignCollectionDialogProps> = ({
|
||||||
<AssignContainerDialog
|
<AssignContainerDialog
|
||||||
containers={collections}
|
containers={collections}
|
||||||
search={{
|
search={{
|
||||||
label: intl.formatMessage({
|
label: intl.formatMessage(messages.assignCollectionDialogLabel),
|
||||||
defaultMessage: "Search Collection"
|
placeholder: intl.formatMessage(
|
||||||
}),
|
messages.assignCollectionDialogPlaceholder
|
||||||
placeholder: intl.formatMessage({
|
)
|
||||||
defaultMessage: "Search by collection name, etc..."
|
|
||||||
})
|
|
||||||
}}
|
}}
|
||||||
title={intl.formatMessage({
|
title={intl.formatMessage(messages.assignCollectionDialogHeader)}
|
||||||
defaultMessage: "Assign Collection",
|
|
||||||
description: "dialog header"
|
|
||||||
})}
|
|
||||||
{...rest}
|
{...rest}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
16
src/components/AssignCollectionDialog/messages.ts
Normal file
16
src/components/AssignCollectionDialog/messages.ts
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
import { defineMessages } from "react-intl";
|
||||||
|
|
||||||
|
export const messages = defineMessages({
|
||||||
|
assignCollectionDialogLabel: {
|
||||||
|
defaultMessage: "Search Collection",
|
||||||
|
description: "dialog header"
|
||||||
|
},
|
||||||
|
assignCollectionDialogPlaceholder: {
|
||||||
|
defaultMessage: "Search by collection name, etc...",
|
||||||
|
description: "dialog search placeholder"
|
||||||
|
},
|
||||||
|
assignCollectionDialogHeader: {
|
||||||
|
defaultMessage: "Assign Collection",
|
||||||
|
description: "dialog header"
|
||||||
|
}
|
||||||
|
});
|
|
@ -13,49 +13,33 @@ import {
|
||||||
import ResponsiveTable from "@saleor/components/ResponsiveTable";
|
import ResponsiveTable from "@saleor/components/ResponsiveTable";
|
||||||
import useSearchQuery from "@saleor/hooks/useSearchQuery";
|
import useSearchQuery from "@saleor/hooks/useSearchQuery";
|
||||||
import { buttonMessages } from "@saleor/intl";
|
import { buttonMessages } from "@saleor/intl";
|
||||||
import { makeStyles } from "@saleor/macaw-ui";
|
|
||||||
import useScrollableDialogStyle from "@saleor/styles/useScrollableDialogStyle";
|
import useScrollableDialogStyle from "@saleor/styles/useScrollableDialogStyle";
|
||||||
import { FetchMoreProps, Node } from "@saleor/types";
|
import { DialogProps, FetchMoreProps, Node } from "@saleor/types";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import InfiniteScroll from "react-infinite-scroll-component";
|
import InfiniteScroll from "react-infinite-scroll-component";
|
||||||
import { FormattedMessage } from "react-intl";
|
import { FormattedMessage } from "react-intl";
|
||||||
|
|
||||||
import Checkbox from "../Checkbox";
|
import Checkbox from "../Checkbox";
|
||||||
import ConfirmButton, { ConfirmButtonTransitionState } from "../ConfirmButton";
|
import ConfirmButton, { ConfirmButtonTransitionState } from "../ConfirmButton";
|
||||||
|
import { messages } from "./messages";
|
||||||
|
import { useStyles } from "./styles";
|
||||||
|
|
||||||
export interface FormData {
|
export interface AssignContainerDialogFormData {
|
||||||
containers: string[];
|
containers: string[];
|
||||||
query: string;
|
query: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const useStyles = makeStyles(
|
|
||||||
{
|
|
||||||
avatar: {
|
|
||||||
"&:first-child": {
|
|
||||||
paddingLeft: 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
checkboxCell: {
|
|
||||||
paddingLeft: 0
|
|
||||||
},
|
|
||||||
wideCell: {
|
|
||||||
width: "100%"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{ name: "AssignContainerDialog" }
|
|
||||||
);
|
|
||||||
|
|
||||||
interface Container extends Node {
|
interface Container extends Node {
|
||||||
name: string;
|
name: string;
|
||||||
}
|
}
|
||||||
export interface AssignContainerDialogProps extends FetchMoreProps {
|
export interface AssignContainerDialogProps
|
||||||
|
extends FetchMoreProps,
|
||||||
|
DialogProps {
|
||||||
confirmButtonState: ConfirmButtonTransitionState;
|
confirmButtonState: ConfirmButtonTransitionState;
|
||||||
containers: Container[];
|
containers: Container[];
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
open: boolean;
|
|
||||||
search: Record<"label" | "placeholder", string>;
|
search: Record<"label" | "placeholder", string>;
|
||||||
title: string;
|
title: string;
|
||||||
onClose: () => void;
|
|
||||||
onFetch: (value: string) => void;
|
onFetch: (value: string) => void;
|
||||||
onSubmit: (data: string[]) => void;
|
onSubmit: (data: string[]) => void;
|
||||||
}
|
}
|
||||||
|
@ -188,7 +172,7 @@ const AssignContainerDialog: React.FC<AssignContainerDialogProps> = props => {
|
||||||
type="submit"
|
type="submit"
|
||||||
onClick={handleSubmit}
|
onClick={handleSubmit}
|
||||||
>
|
>
|
||||||
<FormattedMessage defaultMessage="Assign" description="button" />
|
<FormattedMessage {...messages.assignContainerDialogButton} />
|
||||||
</ConfirmButton>
|
</ConfirmButton>
|
||||||
</DialogActions>
|
</DialogActions>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
|
8
src/components/AssignContainerDialog/messages.ts
Normal file
8
src/components/AssignContainerDialog/messages.ts
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
import { defineMessages } from "react-intl";
|
||||||
|
|
||||||
|
export const messages = defineMessages({
|
||||||
|
assignContainerDialogButton: {
|
||||||
|
defaultMessage: "Assign",
|
||||||
|
description: "button"
|
||||||
|
}
|
||||||
|
});
|
18
src/components/AssignContainerDialog/styles.ts
Normal file
18
src/components/AssignContainerDialog/styles.ts
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
import { makeStyles } from "@saleor/macaw-ui";
|
||||||
|
|
||||||
|
export const useStyles = makeStyles(
|
||||||
|
{
|
||||||
|
avatar: {
|
||||||
|
"&:first-child": {
|
||||||
|
paddingLeft: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
checkboxCell: {
|
||||||
|
paddingLeft: 0
|
||||||
|
},
|
||||||
|
wideCell: {
|
||||||
|
width: "100%"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ name: "AssignContainerDialog" }
|
||||||
|
);
|
|
@ -17,65 +17,43 @@ import ResponsiveTable from "@saleor/components/ResponsiveTable";
|
||||||
import TableCellAvatar from "@saleor/components/TableCellAvatar";
|
import TableCellAvatar from "@saleor/components/TableCellAvatar";
|
||||||
import useSearchQuery from "@saleor/hooks/useSearchQuery";
|
import useSearchQuery from "@saleor/hooks/useSearchQuery";
|
||||||
import { buttonMessages } from "@saleor/intl";
|
import { buttonMessages } from "@saleor/intl";
|
||||||
import { makeStyles } from "@saleor/macaw-ui";
|
|
||||||
import { maybe } from "@saleor/misc";
|
import { maybe } from "@saleor/misc";
|
||||||
import { SearchProducts_search_edges_node } from "@saleor/searches/types/SearchProducts";
|
import { SearchProducts_search_edges_node } from "@saleor/searches/types/SearchProducts";
|
||||||
import useScrollableDialogStyle from "@saleor/styles/useScrollableDialogStyle";
|
import useScrollableDialogStyle from "@saleor/styles/useScrollableDialogStyle";
|
||||||
import { FetchMoreProps } from "@saleor/types";
|
import { DialogProps, FetchMoreProps } from "@saleor/types";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import InfiniteScroll from "react-infinite-scroll-component";
|
import InfiniteScroll from "react-infinite-scroll-component";
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
|
|
||||||
import Checkbox from "../Checkbox";
|
import Checkbox from "../Checkbox";
|
||||||
|
import { messages } from "./messages";
|
||||||
|
import { useStyles } from "./styles";
|
||||||
|
|
||||||
export interface FormData {
|
export interface AssignProductDialogFormData {
|
||||||
products: SearchProducts_search_edges_node[];
|
products: SearchProducts_search_edges_node[];
|
||||||
query: string;
|
query: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const useStyles = makeStyles(
|
export interface AssignProductDialogProps extends FetchMoreProps, DialogProps {
|
||||||
{
|
|
||||||
avatar: {
|
|
||||||
"&&:first-child": {
|
|
||||||
paddingLeft: 0
|
|
||||||
},
|
|
||||||
width: 72
|
|
||||||
},
|
|
||||||
checkboxCell: {
|
|
||||||
paddingLeft: 0,
|
|
||||||
width: 88
|
|
||||||
},
|
|
||||||
colName: {
|
|
||||||
paddingLeft: 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{ name: "AssignProductDialog" }
|
|
||||||
);
|
|
||||||
|
|
||||||
export interface AssignProductDialogProps extends FetchMoreProps {
|
|
||||||
confirmButtonState: ConfirmButtonTransitionState;
|
confirmButtonState: ConfirmButtonTransitionState;
|
||||||
open: boolean;
|
|
||||||
products: SearchProducts_search_edges_node[];
|
products: SearchProducts_search_edges_node[];
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
onClose: () => void;
|
|
||||||
onFetch: (value: string) => void;
|
onFetch: (value: string) => void;
|
||||||
onSubmit: (data: SearchProducts_search_edges_node[]) => void;
|
onSubmit: (data: string[]) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleProductAssign(
|
function handleProductAssign(
|
||||||
product: SearchProducts_search_edges_node,
|
productID: string,
|
||||||
isSelected: boolean,
|
isSelected: boolean,
|
||||||
selectedProducts: SearchProducts_search_edges_node[],
|
selectedProducts: string[],
|
||||||
setSelectedProducts: (data: SearchProducts_search_edges_node[]) => void
|
setSelectedProducts: (data: string[]) => void
|
||||||
) {
|
) {
|
||||||
if (isSelected) {
|
if (isSelected) {
|
||||||
setSelectedProducts(
|
setSelectedProducts(
|
||||||
selectedProducts.filter(
|
selectedProducts.filter(selectedProduct => selectedProduct !== productID)
|
||||||
selectedProduct => selectedProduct.id !== product.id
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
setSelectedProducts([...selectedProducts, product]);
|
setSelectedProducts([...selectedProducts, productID]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,9 +76,7 @@ const AssignProductDialog: React.FC<AssignProductDialogProps> = props => {
|
||||||
|
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const [query, onQueryChange] = useSearchQuery(onFetch);
|
const [query, onQueryChange] = useSearchQuery(onFetch);
|
||||||
const [selectedProducts, setSelectedProducts] = React.useState<
|
const [selectedProducts, setSelectedProducts] = React.useState<string[]>([]);
|
||||||
SearchProducts_search_edges_node[]
|
|
||||||
>([]);
|
|
||||||
|
|
||||||
const handleSubmit = () => onSubmit(selectedProducts);
|
const handleSubmit = () => onSubmit(selectedProducts);
|
||||||
|
|
||||||
|
@ -113,23 +89,15 @@ const AssignProductDialog: React.FC<AssignProductDialogProps> = props => {
|
||||||
maxWidth="sm"
|
maxWidth="sm"
|
||||||
>
|
>
|
||||||
<DialogTitle>
|
<DialogTitle>
|
||||||
<FormattedMessage
|
<FormattedMessage {...messages.assignVariantDialogHeader} />
|
||||||
defaultMessage="Assign Product"
|
|
||||||
description="dialog header"
|
|
||||||
/>
|
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
<DialogContent className={scrollableDialogClasses.topArea}>
|
<DialogContent className={scrollableDialogClasses.topArea}>
|
||||||
<TextField
|
<TextField
|
||||||
name="query"
|
name="query"
|
||||||
value={query}
|
value={query}
|
||||||
onChange={onQueryChange}
|
onChange={onQueryChange}
|
||||||
label={intl.formatMessage({
|
label={intl.formatMessage(messages.assignProductDialogSearch)}
|
||||||
defaultMessage: "Search Products"
|
placeholder={intl.formatMessage(messages.assignProductDialogContent)}
|
||||||
})}
|
|
||||||
placeholder={intl.formatMessage({
|
|
||||||
defaultMessage:
|
|
||||||
"Search by product name, attribute, product type etc..."
|
|
||||||
})}
|
|
||||||
fullWidth
|
fullWidth
|
||||||
InputProps={{
|
InputProps={{
|
||||||
autoComplete: "off",
|
autoComplete: "off",
|
||||||
|
@ -158,7 +126,7 @@ const AssignProductDialog: React.FC<AssignProductDialogProps> = props => {
|
||||||
{products &&
|
{products &&
|
||||||
products.map(product => {
|
products.map(product => {
|
||||||
const isSelected = selectedProducts.some(
|
const isSelected = selectedProducts.some(
|
||||||
selectedProduct => selectedProduct.id === product.id
|
selectedProduct => selectedProduct === product.id
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -181,7 +149,7 @@ const AssignProductDialog: React.FC<AssignProductDialogProps> = props => {
|
||||||
checked={isSelected}
|
checked={isSelected}
|
||||||
onChange={() =>
|
onChange={() =>
|
||||||
handleProductAssign(
|
handleProductAssign(
|
||||||
product,
|
product.id,
|
||||||
isSelected,
|
isSelected,
|
||||||
selectedProducts,
|
selectedProducts,
|
||||||
setSelectedProducts
|
setSelectedProducts
|
||||||
|
@ -208,10 +176,7 @@ const AssignProductDialog: React.FC<AssignProductDialogProps> = props => {
|
||||||
type="submit"
|
type="submit"
|
||||||
onClick={handleSubmit}
|
onClick={handleSubmit}
|
||||||
>
|
>
|
||||||
<FormattedMessage
|
<FormattedMessage {...messages.assignProductDialogButton} />
|
||||||
defaultMessage="Assign products"
|
|
||||||
description="button"
|
|
||||||
/>
|
|
||||||
</ConfirmButton>
|
</ConfirmButton>
|
||||||
</DialogActions>
|
</DialogActions>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
|
18
src/components/AssignProductDialog/messages.ts
Normal file
18
src/components/AssignProductDialog/messages.ts
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
import { defineMessages } from "react-intl";
|
||||||
|
|
||||||
|
export const messages = defineMessages({
|
||||||
|
assignVariantDialogHeader: {
|
||||||
|
defaultMessage: "Assign Product",
|
||||||
|
description: "dialog header"
|
||||||
|
},
|
||||||
|
assignProductDialogButton: {
|
||||||
|
defaultMessage: "Assign",
|
||||||
|
description: "button"
|
||||||
|
},
|
||||||
|
assignProductDialogContent: {
|
||||||
|
defaultMessage: "Search Products"
|
||||||
|
},
|
||||||
|
assignProductDialogSearch: {
|
||||||
|
defaultMessage: "Search by product name, attribute, product type etc..."
|
||||||
|
}
|
||||||
|
});
|
20
src/components/AssignProductDialog/styles.ts
Normal file
20
src/components/AssignProductDialog/styles.ts
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
import { makeStyles } from "@saleor/macaw-ui";
|
||||||
|
|
||||||
|
export const useStyles = makeStyles(
|
||||||
|
{
|
||||||
|
avatar: {
|
||||||
|
"&&:first-child": {
|
||||||
|
paddingLeft: 0
|
||||||
|
},
|
||||||
|
width: 72
|
||||||
|
},
|
||||||
|
checkboxCell: {
|
||||||
|
paddingLeft: 0,
|
||||||
|
width: 88
|
||||||
|
},
|
||||||
|
colName: {
|
||||||
|
paddingLeft: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ name: "AssignProductDialog" }
|
||||||
|
);
|
298
src/components/AssignVariantDialog/AssignVariantDialog.tsx
Normal file
298
src/components/AssignVariantDialog/AssignVariantDialog.tsx
Normal file
|
@ -0,0 +1,298 @@
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
CircularProgress,
|
||||||
|
Dialog,
|
||||||
|
DialogActions,
|
||||||
|
DialogContent,
|
||||||
|
DialogTitle,
|
||||||
|
TableBody,
|
||||||
|
TableCell,
|
||||||
|
TableRow,
|
||||||
|
TextField
|
||||||
|
} from "@material-ui/core";
|
||||||
|
import ConfirmButton, {
|
||||||
|
ConfirmButtonTransitionState
|
||||||
|
} from "@saleor/components/ConfirmButton";
|
||||||
|
import Money from "@saleor/components/Money";
|
||||||
|
import ResponsiveTable from "@saleor/components/ResponsiveTable";
|
||||||
|
import TableCellAvatar from "@saleor/components/TableCellAvatar";
|
||||||
|
import useSearchQuery from "@saleor/hooks/useSearchQuery";
|
||||||
|
import { buttonMessages } from "@saleor/intl";
|
||||||
|
import { maybe, renderCollection } from "@saleor/misc";
|
||||||
|
import {
|
||||||
|
getById,
|
||||||
|
getByUnmatchingId
|
||||||
|
} from "@saleor/orders/components/OrderReturnPage/utils";
|
||||||
|
import {
|
||||||
|
SearchProducts_search_edges_node,
|
||||||
|
SearchProducts_search_edges_node_variants
|
||||||
|
} from "@saleor/searches/types/SearchProducts";
|
||||||
|
import useScrollableDialogStyle from "@saleor/styles/useScrollableDialogStyle";
|
||||||
|
import { DialogProps, FetchMoreProps } from "@saleor/types";
|
||||||
|
import React from "react";
|
||||||
|
import InfiniteScroll from "react-infinite-scroll-component";
|
||||||
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
|
|
||||||
|
import Checkbox from "../Checkbox";
|
||||||
|
import { messages } from "./messages";
|
||||||
|
import { useStyles } from "./styles";
|
||||||
|
|
||||||
|
type SetVariantsAction = (
|
||||||
|
data: SearchProducts_search_edges_node_variants[]
|
||||||
|
) => void;
|
||||||
|
export interface AssignVariantDialogFormData {
|
||||||
|
products: SearchProducts_search_edges_node[];
|
||||||
|
query: string;
|
||||||
|
}
|
||||||
|
export interface AssignVariantDialogProps extends FetchMoreProps, DialogProps {
|
||||||
|
confirmButtonState: ConfirmButtonTransitionState;
|
||||||
|
products: SearchProducts_search_edges_node[];
|
||||||
|
loading: boolean;
|
||||||
|
onFetch: (value: string) => void;
|
||||||
|
onSubmit: (data: SearchProducts_search_edges_node_variants[]) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isVariantSelected(
|
||||||
|
variant: SearchProducts_search_edges_node_variants,
|
||||||
|
selectedVariantsToProductsMap: SearchProducts_search_edges_node_variants[]
|
||||||
|
): boolean {
|
||||||
|
return !!selectedVariantsToProductsMap.find(getById(variant.id));
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleProductAssign = (
|
||||||
|
product: SearchProducts_search_edges_node,
|
||||||
|
productIndex: number,
|
||||||
|
productsWithAllVariantsSelected: boolean[],
|
||||||
|
variants: SearchProducts_search_edges_node_variants[],
|
||||||
|
setVariants: SetVariantsAction
|
||||||
|
) =>
|
||||||
|
productsWithAllVariantsSelected[productIndex]
|
||||||
|
? setVariants(
|
||||||
|
variants.filter(
|
||||||
|
selectedVariant => !product.variants.find(getById(selectedVariant.id))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
: setVariants([
|
||||||
|
...variants,
|
||||||
|
...product.variants.filter(
|
||||||
|
productVariant => !variants.find(getById(productVariant.id))
|
||||||
|
)
|
||||||
|
]);
|
||||||
|
|
||||||
|
const handleVariantAssign = (
|
||||||
|
variant: SearchProducts_search_edges_node_variants,
|
||||||
|
variantIndex: number,
|
||||||
|
productIndex: number,
|
||||||
|
variants: SearchProducts_search_edges_node_variants[],
|
||||||
|
selectedVariantsToProductsMap: boolean[][],
|
||||||
|
setVariants: SetVariantsAction
|
||||||
|
) =>
|
||||||
|
selectedVariantsToProductsMap[productIndex][variantIndex]
|
||||||
|
? setVariants(variants.filter(getByUnmatchingId(variant.id)))
|
||||||
|
: setVariants([...variants, variant]);
|
||||||
|
|
||||||
|
function hasAllVariantsSelected(
|
||||||
|
productVariants: SearchProducts_search_edges_node_variants[],
|
||||||
|
selectedVariantsToProductsMap: SearchProducts_search_edges_node_variants[]
|
||||||
|
): boolean {
|
||||||
|
return productVariants.reduce(
|
||||||
|
(acc, productVariant) =>
|
||||||
|
acc && !!selectedVariantsToProductsMap.find(getById(productVariant.id)),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const scrollableTargetId = "assignVariantScrollableDialog";
|
||||||
|
|
||||||
|
const AssignVariantDialog: React.FC<AssignVariantDialogProps> = props => {
|
||||||
|
const {
|
||||||
|
confirmButtonState,
|
||||||
|
hasMore,
|
||||||
|
open,
|
||||||
|
loading,
|
||||||
|
products,
|
||||||
|
onClose,
|
||||||
|
onFetch,
|
||||||
|
onFetchMore,
|
||||||
|
onSubmit
|
||||||
|
} = props;
|
||||||
|
const classes = useStyles(props);
|
||||||
|
const scrollableDialogClasses = useScrollableDialogStyle({});
|
||||||
|
|
||||||
|
const intl = useIntl();
|
||||||
|
const [query, onQueryChange] = useSearchQuery(onFetch);
|
||||||
|
const [variants, setVariants] = React.useState<
|
||||||
|
SearchProducts_search_edges_node_variants[]
|
||||||
|
>([]);
|
||||||
|
|
||||||
|
const productChoices =
|
||||||
|
products?.filter(product => product?.variants?.length > 0) || [];
|
||||||
|
|
||||||
|
const selectedVariantsToProductsMap = productChoices
|
||||||
|
? productChoices.map(product =>
|
||||||
|
product.variants.map(variant => isVariantSelected(variant, variants))
|
||||||
|
)
|
||||||
|
: [];
|
||||||
|
|
||||||
|
const productsWithAllVariantsSelected = productChoices
|
||||||
|
? productChoices.map(product =>
|
||||||
|
hasAllVariantsSelected(product.variants, variants)
|
||||||
|
)
|
||||||
|
: [];
|
||||||
|
|
||||||
|
const handleSubmit = () => onSubmit(variants);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dialog
|
||||||
|
onClose={onClose}
|
||||||
|
open={open}
|
||||||
|
classes={{ paper: scrollableDialogClasses.dialog }}
|
||||||
|
fullWidth
|
||||||
|
maxWidth="sm"
|
||||||
|
>
|
||||||
|
<DialogTitle>
|
||||||
|
<FormattedMessage {...messages.assignVariantDialogHeader} />
|
||||||
|
</DialogTitle>
|
||||||
|
<DialogContent className={scrollableDialogClasses.topArea}>
|
||||||
|
<TextField
|
||||||
|
name="query"
|
||||||
|
value={query}
|
||||||
|
onChange={onQueryChange}
|
||||||
|
label={intl.formatMessage(messages.assignVariantDialogSearch)}
|
||||||
|
placeholder={intl.formatMessage(messages.assignVariantDialogContent)}
|
||||||
|
fullWidth
|
||||||
|
InputProps={{
|
||||||
|
autoComplete: "off",
|
||||||
|
endAdornment: loading && <CircularProgress size={16} />
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</DialogContent>
|
||||||
|
<DialogContent
|
||||||
|
className={scrollableDialogClasses.scrollArea}
|
||||||
|
id={scrollableTargetId}
|
||||||
|
>
|
||||||
|
<InfiniteScroll
|
||||||
|
dataLength={variants?.length}
|
||||||
|
next={onFetchMore}
|
||||||
|
hasMore={hasMore}
|
||||||
|
scrollThreshold="100px"
|
||||||
|
loader={
|
||||||
|
<div className={scrollableDialogClasses.loadMoreLoaderContainer}>
|
||||||
|
<CircularProgress size={16} />
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
scrollableTarget={scrollableTargetId}
|
||||||
|
>
|
||||||
|
<ResponsiveTable key="table">
|
||||||
|
<TableBody>
|
||||||
|
{renderCollection(
|
||||||
|
products,
|
||||||
|
(product, productIndex) => (
|
||||||
|
<React.Fragment key={product ? product.id : "skeleton"}>
|
||||||
|
<TableRow>
|
||||||
|
<TableCell
|
||||||
|
padding="checkbox"
|
||||||
|
className={classes.productCheckboxCell}
|
||||||
|
>
|
||||||
|
<Checkbox
|
||||||
|
checked={
|
||||||
|
productsWithAllVariantsSelected[productIndex]
|
||||||
|
}
|
||||||
|
disabled={loading}
|
||||||
|
onChange={() =>
|
||||||
|
handleProductAssign(
|
||||||
|
product,
|
||||||
|
productIndex,
|
||||||
|
productsWithAllVariantsSelected,
|
||||||
|
variants,
|
||||||
|
setVariants
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</TableCell>
|
||||||
|
<TableCellAvatar
|
||||||
|
className={classes.avatar}
|
||||||
|
thumbnail={maybe(() => product.thumbnail.url)}
|
||||||
|
/>
|
||||||
|
<TableCell className={classes.colName} colSpan={2}>
|
||||||
|
{maybe(() => product.name)}
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
{maybe(() => product.variants, []).map(
|
||||||
|
(variant, variantIndex) => (
|
||||||
|
<TableRow key={variant.id}>
|
||||||
|
<TableCell />
|
||||||
|
<TableCell className={classes.colVariantCheckbox}>
|
||||||
|
<Checkbox
|
||||||
|
className={classes.variantCheckbox}
|
||||||
|
checked={
|
||||||
|
selectedVariantsToProductsMap[productIndex][
|
||||||
|
variantIndex
|
||||||
|
]
|
||||||
|
}
|
||||||
|
disabled={loading}
|
||||||
|
onChange={() =>
|
||||||
|
handleVariantAssign(
|
||||||
|
variant,
|
||||||
|
variantIndex,
|
||||||
|
productIndex,
|
||||||
|
variants,
|
||||||
|
selectedVariantsToProductsMap,
|
||||||
|
setVariants
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className={classes.colName}>
|
||||||
|
<div>{variant.name}</div>
|
||||||
|
<div className={classes.grayText}>
|
||||||
|
<FormattedMessage
|
||||||
|
{...messages.assignVariantDialogSKU}
|
||||||
|
values={{
|
||||||
|
sku: variant.sku
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className={classes.textRight}>
|
||||||
|
{variant?.channelListings[0]?.price && (
|
||||||
|
<Money money={variant.channelListings[0].price} />
|
||||||
|
)}
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</React.Fragment>
|
||||||
|
),
|
||||||
|
() => (
|
||||||
|
<TableRow>
|
||||||
|
<TableCell colSpan={4}>
|
||||||
|
<FormattedMessage defaultMessage="No products available in order channel matching given query" />
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</TableBody>
|
||||||
|
</ResponsiveTable>
|
||||||
|
</InfiniteScroll>
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<Button onClick={onClose}>
|
||||||
|
<FormattedMessage {...buttonMessages.back} />
|
||||||
|
</Button>
|
||||||
|
<ConfirmButton
|
||||||
|
data-test="submit"
|
||||||
|
transitionState={confirmButtonState}
|
||||||
|
color="primary"
|
||||||
|
variant="contained"
|
||||||
|
type="submit"
|
||||||
|
onClick={handleSubmit}
|
||||||
|
>
|
||||||
|
<FormattedMessage {...messages.assignVariantDialogButton} />
|
||||||
|
</ConfirmButton>
|
||||||
|
</DialogActions>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
AssignVariantDialog.displayName = "AssignVariantDialog";
|
||||||
|
export default AssignVariantDialog;
|
2
src/components/AssignVariantDialog/index.ts
Normal file
2
src/components/AssignVariantDialog/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
export { default } from "./AssignVariantDialog";
|
||||||
|
export * from "./AssignVariantDialog";
|
22
src/components/AssignVariantDialog/messages.ts
Normal file
22
src/components/AssignVariantDialog/messages.ts
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
import { defineMessages } from "react-intl";
|
||||||
|
|
||||||
|
export const messages = defineMessages({
|
||||||
|
assignVariantDialogHeader: {
|
||||||
|
defaultMessage: "Assign Variant",
|
||||||
|
description: "dialog header"
|
||||||
|
},
|
||||||
|
assignVariantDialogButton: {
|
||||||
|
defaultMessage: "Assign",
|
||||||
|
description: "button"
|
||||||
|
},
|
||||||
|
assignVariantDialogContent: {
|
||||||
|
defaultMessage: "Search Variants"
|
||||||
|
},
|
||||||
|
assignVariantDialogSearch: {
|
||||||
|
defaultMessage: "Search by product name, attribute, product type etc..."
|
||||||
|
},
|
||||||
|
assignVariantDialogSKU: {
|
||||||
|
defaultMessage: "SKU {sku}",
|
||||||
|
description: "variant sku"
|
||||||
|
}
|
||||||
|
});
|
56
src/components/AssignVariantDialog/styles.ts
Normal file
56
src/components/AssignVariantDialog/styles.ts
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
import { makeStyles } from "@saleor/macaw-ui";
|
||||||
|
|
||||||
|
export const useStyles = makeStyles(
|
||||||
|
theme => ({
|
||||||
|
avatar: {
|
||||||
|
paddingLeft: 0,
|
||||||
|
width: 64
|
||||||
|
},
|
||||||
|
colName: {
|
||||||
|
paddingLeft: 0
|
||||||
|
},
|
||||||
|
colVariantCheckbox: {
|
||||||
|
padding: 0
|
||||||
|
},
|
||||||
|
content: {
|
||||||
|
overflowY: "scroll",
|
||||||
|
paddingTop: 0,
|
||||||
|
marginBottom: theme.spacing(3)
|
||||||
|
},
|
||||||
|
grayText: {
|
||||||
|
color: theme.palette.text.disabled
|
||||||
|
},
|
||||||
|
loadMoreLoaderContainer: {
|
||||||
|
alignItems: "center",
|
||||||
|
display: "flex",
|
||||||
|
height: theme.spacing(3),
|
||||||
|
justifyContent: "center",
|
||||||
|
marginTop: theme.spacing(3)
|
||||||
|
},
|
||||||
|
overflow: {
|
||||||
|
overflowY: "hidden"
|
||||||
|
},
|
||||||
|
topArea: {
|
||||||
|
overflowY: "hidden",
|
||||||
|
paddingBottom: theme.spacing(6),
|
||||||
|
margin: theme.spacing(0, 3, 3, 3)
|
||||||
|
},
|
||||||
|
productCheckboxCell: {
|
||||||
|
"&:first-child": {
|
||||||
|
paddingLeft: 0,
|
||||||
|
paddingRight: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
textRight: {
|
||||||
|
textAlign: "right"
|
||||||
|
},
|
||||||
|
variantCheckbox: {
|
||||||
|
left: theme.spacing(),
|
||||||
|
position: "relative"
|
||||||
|
},
|
||||||
|
wideCell: {
|
||||||
|
width: "100%"
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
{ name: "AssignVariantDialog" }
|
||||||
|
);
|
|
@ -14,7 +14,6 @@ import ResponsiveTable from "@saleor/components/ResponsiveTable";
|
||||||
import Skeleton from "@saleor/components/Skeleton";
|
import Skeleton from "@saleor/components/Skeleton";
|
||||||
import TableHead from "@saleor/components/TableHead";
|
import TableHead from "@saleor/components/TableHead";
|
||||||
import TablePagination from "@saleor/components/TablePagination";
|
import TablePagination from "@saleor/components/TablePagination";
|
||||||
import { makeStyles } from "@saleor/macaw-ui";
|
|
||||||
import { mapEdgesToItems } from "@saleor/utils/maps";
|
import { mapEdgesToItems } from "@saleor/utils/maps";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
|
@ -23,35 +22,14 @@ import { maybe, renderCollection } from "../../../misc";
|
||||||
import { ListActions, ListProps } from "../../../types";
|
import { ListActions, ListProps } from "../../../types";
|
||||||
import { SaleDetails_sale } from "../../types/SaleDetails";
|
import { SaleDetails_sale } from "../../types/SaleDetails";
|
||||||
import { VoucherDetails_voucher } from "../../types/VoucherDetails";
|
import { VoucherDetails_voucher } from "../../types/VoucherDetails";
|
||||||
|
import { messages } from "./messages";
|
||||||
|
import { useStyles } from "./styles";
|
||||||
export interface DiscountCategoriesProps extends ListProps, ListActions {
|
export interface DiscountCategoriesProps extends ListProps, ListActions {
|
||||||
discount: SaleDetails_sale | VoucherDetails_voucher;
|
discount: SaleDetails_sale | VoucherDetails_voucher;
|
||||||
onCategoryAssign: () => void;
|
onCategoryAssign: () => void;
|
||||||
onCategoryUnassign: (id: string) => void;
|
onCategoryUnassign: (id: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const useStyles = makeStyles(
|
|
||||||
{
|
|
||||||
colActions: {
|
|
||||||
"&:last-child": {
|
|
||||||
paddingRight: 0
|
|
||||||
},
|
|
||||||
width: 80
|
|
||||||
},
|
|
||||||
colName: {
|
|
||||||
width: "auto"
|
|
||||||
},
|
|
||||||
colProducts: {
|
|
||||||
textAlign: "right",
|
|
||||||
width: 140
|
|
||||||
},
|
|
||||||
tableRow: {
|
|
||||||
cursor: "pointer"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{ name: "DiscountCategories" }
|
|
||||||
);
|
|
||||||
|
|
||||||
const numberOfColumns = 4;
|
const numberOfColumns = 4;
|
||||||
|
|
||||||
const DiscountCategories: React.FC<DiscountCategoriesProps> = props => {
|
const DiscountCategories: React.FC<DiscountCategoriesProps> = props => {
|
||||||
|
@ -77,16 +55,10 @@ const DiscountCategories: React.FC<DiscountCategoriesProps> = props => {
|
||||||
return (
|
return (
|
||||||
<Card>
|
<Card>
|
||||||
<CardTitle
|
<CardTitle
|
||||||
title={intl.formatMessage({
|
title={intl.formatMessage(messages.discountCategoriesHeader)}
|
||||||
defaultMessage: "Eligible Categories",
|
|
||||||
description: "section header"
|
|
||||||
})}
|
|
||||||
toolbar={
|
toolbar={
|
||||||
<Button color="primary" onClick={onCategoryAssign}>
|
<Button color="primary" onClick={onCategoryAssign}>
|
||||||
<FormattedMessage
|
<FormattedMessage {...messages.discountCategoriesButton} />
|
||||||
defaultMessage="Assign categories"
|
|
||||||
description="button"
|
|
||||||
/>
|
|
||||||
</Button>
|
</Button>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
@ -107,12 +79,13 @@ const DiscountCategories: React.FC<DiscountCategoriesProps> = props => {
|
||||||
>
|
>
|
||||||
<>
|
<>
|
||||||
<TableCell className={classes.colName}>
|
<TableCell className={classes.colName}>
|
||||||
<FormattedMessage defaultMessage="Category name" />
|
<FormattedMessage
|
||||||
|
{...messages.discountCategoriesTableProductHeader}
|
||||||
|
/>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell className={classes.colProducts}>
|
<TableCell className={classes.colProducts}>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
defaultMessage="Products"
|
{...messages.discountCategoriesTableProductNumber}
|
||||||
description="number of products"
|
|
||||||
/>
|
/>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell />
|
<TableCell />
|
||||||
|
@ -179,7 +152,7 @@ const DiscountCategories: React.FC<DiscountCategoriesProps> = props => {
|
||||||
() => (
|
() => (
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell colSpan={numberOfColumns}>
|
<TableCell colSpan={numberOfColumns}>
|
||||||
<FormattedMessage defaultMessage="No categories found" />
|
<FormattedMessage {...messages.discountCategoriesNotFound} />
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
)
|
)
|
||||||
|
|
24
src/discounts/components/DiscountCategories/messages.ts
Normal file
24
src/discounts/components/DiscountCategories/messages.ts
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
import { defineMessages } from "react-intl";
|
||||||
|
|
||||||
|
export const messages = defineMessages({
|
||||||
|
discountCategoriesHeader: {
|
||||||
|
defaultMessage: "Eligible Categories",
|
||||||
|
description: "section header"
|
||||||
|
},
|
||||||
|
discountCategoriesButton: {
|
||||||
|
defaultMessage: "Assign categories",
|
||||||
|
description: "button"
|
||||||
|
},
|
||||||
|
discountCategoriesTableProductHeader: {
|
||||||
|
defaultMessage: "Category Name",
|
||||||
|
description: "table head"
|
||||||
|
},
|
||||||
|
discountCategoriesTableProductNumber: {
|
||||||
|
defaultMessage: "Products",
|
||||||
|
description: "number of products"
|
||||||
|
},
|
||||||
|
discountCategoriesNotFound: {
|
||||||
|
defaultMessage: "No categories found",
|
||||||
|
description: "no categories"
|
||||||
|
}
|
||||||
|
});
|
23
src/discounts/components/DiscountCategories/styles.ts
Normal file
23
src/discounts/components/DiscountCategories/styles.ts
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
import { makeStyles } from "@saleor/macaw-ui";
|
||||||
|
|
||||||
|
export const useStyles = makeStyles(
|
||||||
|
{
|
||||||
|
colActions: {
|
||||||
|
"&:last-child": {
|
||||||
|
paddingRight: 0
|
||||||
|
},
|
||||||
|
width: 80
|
||||||
|
},
|
||||||
|
colName: {
|
||||||
|
width: "auto"
|
||||||
|
},
|
||||||
|
colProducts: {
|
||||||
|
textAlign: "right",
|
||||||
|
width: 140
|
||||||
|
},
|
||||||
|
tableRow: {
|
||||||
|
cursor: "pointer"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ name: "DiscountCategories" }
|
||||||
|
);
|
|
@ -14,7 +14,6 @@ import ResponsiveTable from "@saleor/components/ResponsiveTable";
|
||||||
import Skeleton from "@saleor/components/Skeleton";
|
import Skeleton from "@saleor/components/Skeleton";
|
||||||
import TableHead from "@saleor/components/TableHead";
|
import TableHead from "@saleor/components/TableHead";
|
||||||
import TablePagination from "@saleor/components/TablePagination";
|
import TablePagination from "@saleor/components/TablePagination";
|
||||||
import { makeStyles } from "@saleor/macaw-ui";
|
|
||||||
import { mapEdgesToItems } from "@saleor/utils/maps";
|
import { mapEdgesToItems } from "@saleor/utils/maps";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
|
@ -23,36 +22,14 @@ import { maybe, renderCollection } from "../../../misc";
|
||||||
import { ListActions, ListProps } from "../../../types";
|
import { ListActions, ListProps } from "../../../types";
|
||||||
import { SaleDetails_sale } from "../../types/SaleDetails";
|
import { SaleDetails_sale } from "../../types/SaleDetails";
|
||||||
import { VoucherDetails_voucher } from "../../types/VoucherDetails";
|
import { VoucherDetails_voucher } from "../../types/VoucherDetails";
|
||||||
|
import { messages } from "./messages";
|
||||||
|
import { useStyles } from "./styles";
|
||||||
export interface DiscountCollectionsProps extends ListProps, ListActions {
|
export interface DiscountCollectionsProps extends ListProps, ListActions {
|
||||||
discount: SaleDetails_sale | VoucherDetails_voucher;
|
discount: SaleDetails_sale | VoucherDetails_voucher;
|
||||||
onCollectionAssign: () => void;
|
onCollectionAssign: () => void;
|
||||||
onCollectionUnassign: (id: string) => void;
|
onCollectionUnassign: (id: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const useStyles = makeStyles(
|
|
||||||
{
|
|
||||||
colActions: {
|
|
||||||
"&:last-child": {
|
|
||||||
paddingRight: 0
|
|
||||||
},
|
|
||||||
width: 80
|
|
||||||
},
|
|
||||||
colName: {
|
|
||||||
width: "auto"
|
|
||||||
},
|
|
||||||
colProducts: {
|
|
||||||
textAlign: "right",
|
|
||||||
width: 140
|
|
||||||
},
|
|
||||||
tableRow: {
|
|
||||||
cursor: "pointer"
|
|
||||||
},
|
|
||||||
textRight: {}
|
|
||||||
},
|
|
||||||
{ name: "DiscountCollections" }
|
|
||||||
);
|
|
||||||
|
|
||||||
const numberOfColumns = 4;
|
const numberOfColumns = 4;
|
||||||
|
|
||||||
const DiscountCollections: React.FC<DiscountCollectionsProps> = props => {
|
const DiscountCollections: React.FC<DiscountCollectionsProps> = props => {
|
||||||
|
@ -79,16 +56,10 @@ const DiscountCollections: React.FC<DiscountCollectionsProps> = props => {
|
||||||
return (
|
return (
|
||||||
<Card>
|
<Card>
|
||||||
<CardTitle
|
<CardTitle
|
||||||
title={intl.formatMessage({
|
title={intl.formatMessage(messages.discountCollectionsHeader)}
|
||||||
defaultMessage: "Eligible Collections",
|
|
||||||
description: "section header"
|
|
||||||
})}
|
|
||||||
toolbar={
|
toolbar={
|
||||||
<Button color="primary" onClick={onCollectionAssign}>
|
<Button color="primary" onClick={onCollectionAssign}>
|
||||||
<FormattedMessage
|
<FormattedMessage {...messages.discountCollectionsButton} />
|
||||||
defaultMessage="Assign collections"
|
|
||||||
description="button"
|
|
||||||
/>
|
|
||||||
</Button>
|
</Button>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
@ -108,12 +79,13 @@ const DiscountCollections: React.FC<DiscountCollectionsProps> = props => {
|
||||||
toolbar={toolbar}
|
toolbar={toolbar}
|
||||||
>
|
>
|
||||||
<TableCell className={classes.colName}>
|
<TableCell className={classes.colName}>
|
||||||
<FormattedMessage defaultMessage="Collection name" />
|
|
||||||
</TableCell>
|
|
||||||
<TableCell className={classes.textRight}>
|
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
defaultMessage="Products"
|
{...messages.discountCollectionsTableProductHeader}
|
||||||
description="number of products"
|
/>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className={classes.colProducts}>
|
||||||
|
<FormattedMessage
|
||||||
|
{...messages.discountCollectionsTableProductNumber}
|
||||||
/>
|
/>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell />
|
<TableCell />
|
||||||
|
@ -181,7 +153,7 @@ const DiscountCollections: React.FC<DiscountCollectionsProps> = props => {
|
||||||
() => (
|
() => (
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell colSpan={numberOfColumns}>
|
<TableCell colSpan={numberOfColumns}>
|
||||||
<FormattedMessage defaultMessage="No collections found" />
|
<FormattedMessage {...messages.discountCollectionsNotFound} />
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
)
|
)
|
||||||
|
|
24
src/discounts/components/DiscountCollections/messages.ts
Normal file
24
src/discounts/components/DiscountCollections/messages.ts
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
import { defineMessages } from "react-intl";
|
||||||
|
|
||||||
|
export const messages = defineMessages({
|
||||||
|
discountCollectionsHeader: {
|
||||||
|
defaultMessage: "Eligible Collections",
|
||||||
|
description: "section header"
|
||||||
|
},
|
||||||
|
discountCollectionsButton: {
|
||||||
|
defaultMessage: "Assign collections",
|
||||||
|
description: "button"
|
||||||
|
},
|
||||||
|
discountCollectionsTableProductHeader: {
|
||||||
|
defaultMessage: "Collection Name",
|
||||||
|
description: "table head"
|
||||||
|
},
|
||||||
|
discountCollectionsTableProductNumber: {
|
||||||
|
defaultMessage: "Products",
|
||||||
|
description: "number of products"
|
||||||
|
},
|
||||||
|
discountCollectionsNotFound: {
|
||||||
|
defaultMessage: "No collections found",
|
||||||
|
description: "no collections"
|
||||||
|
}
|
||||||
|
});
|
23
src/discounts/components/DiscountCollections/styles.ts
Normal file
23
src/discounts/components/DiscountCollections/styles.ts
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
import { makeStyles } from "@saleor/macaw-ui";
|
||||||
|
|
||||||
|
export const useStyles = makeStyles(
|
||||||
|
{
|
||||||
|
colActions: {
|
||||||
|
"&:last-child": {
|
||||||
|
paddingRight: 0
|
||||||
|
},
|
||||||
|
width: 80
|
||||||
|
},
|
||||||
|
colName: {
|
||||||
|
width: "auto"
|
||||||
|
},
|
||||||
|
colProducts: {
|
||||||
|
textAlign: "right",
|
||||||
|
width: 140
|
||||||
|
},
|
||||||
|
tableRow: {
|
||||||
|
cursor: "pointer"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ name: "DiscountCollections" }
|
||||||
|
);
|
|
@ -14,63 +14,32 @@ import Checkbox from "@saleor/components/Checkbox";
|
||||||
import ResponsiveTable from "@saleor/components/ResponsiveTable";
|
import ResponsiveTable from "@saleor/components/ResponsiveTable";
|
||||||
import Skeleton from "@saleor/components/Skeleton";
|
import Skeleton from "@saleor/components/Skeleton";
|
||||||
import TableCellAvatar from "@saleor/components/TableCellAvatar";
|
import TableCellAvatar from "@saleor/components/TableCellAvatar";
|
||||||
import { AVATAR_MARGIN } from "@saleor/components/TableCellAvatar/Avatar";
|
|
||||||
import TableHead from "@saleor/components/TableHead";
|
import TableHead from "@saleor/components/TableHead";
|
||||||
import TablePagination from "@saleor/components/TablePagination";
|
import TablePagination from "@saleor/components/TablePagination";
|
||||||
import { makeStyles } from "@saleor/macaw-ui";
|
|
||||||
import { mapEdgesToItems } from "@saleor/utils/maps";
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
|
|
||||||
import { maybe, renderCollection } from "../../../misc";
|
import { maybe, renderCollection } from "../../../misc";
|
||||||
import { ListActions, ListProps } from "../../../types";
|
import { ListActions, ListProps } from "../../../types";
|
||||||
import { SaleDetails_sale } from "../../types/SaleDetails";
|
import { SaleDetails_sale_products_edges_node } from "../../types/SaleDetails";
|
||||||
import { VoucherDetails_voucher } from "../../types/VoucherDetails";
|
import { VoucherDetails_voucher_products_edges_node } from "../../types/VoucherDetails";
|
||||||
|
import { messages } from "./messages";
|
||||||
|
import { useStyles } from "./styles";
|
||||||
export interface SaleProductsProps extends ListProps, ListActions {
|
export interface SaleProductsProps extends ListProps, ListActions {
|
||||||
discount: SaleDetails_sale | VoucherDetails_voucher;
|
products:
|
||||||
|
| SaleDetails_sale_products_edges_node[]
|
||||||
|
| VoucherDetails_voucher_products_edges_node[];
|
||||||
channelsCount: number;
|
channelsCount: number;
|
||||||
onProductAssign: () => void;
|
onProductAssign: () => void;
|
||||||
onProductUnassign: (id: string) => void;
|
onProductUnassign: (id: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const useStyles = makeStyles(
|
|
||||||
theme => ({
|
|
||||||
colActions: {
|
|
||||||
"&:last-child": {
|
|
||||||
paddingRight: 0
|
|
||||||
},
|
|
||||||
width: `calc(76px + ${theme.spacing(0.5)})`
|
|
||||||
},
|
|
||||||
colName: {
|
|
||||||
paddingLeft: 0,
|
|
||||||
width: "auto"
|
|
||||||
},
|
|
||||||
colNameLabel: {
|
|
||||||
marginLeft: `calc(${AVATAR_MARGIN}px + ${theme.spacing(3)})`
|
|
||||||
},
|
|
||||||
colPublished: {
|
|
||||||
width: 150
|
|
||||||
},
|
|
||||||
colType: {
|
|
||||||
width: 200
|
|
||||||
},
|
|
||||||
table: {
|
|
||||||
tableLayout: "fixed"
|
|
||||||
},
|
|
||||||
tableRow: {
|
|
||||||
cursor: "pointer"
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
{ name: "DiscountProducts" }
|
|
||||||
);
|
|
||||||
|
|
||||||
const numberOfColumns = 5;
|
const numberOfColumns = 5;
|
||||||
|
|
||||||
const DiscountProducts: React.FC<SaleProductsProps> = props => {
|
const DiscountProducts: React.FC<SaleProductsProps> = props => {
|
||||||
const {
|
const {
|
||||||
channelsCount,
|
channelsCount,
|
||||||
discount: sale,
|
products,
|
||||||
disabled,
|
disabled,
|
||||||
pageInfo,
|
pageInfo,
|
||||||
onRowClick,
|
onRowClick,
|
||||||
|
@ -91,20 +60,14 @@ const DiscountProducts: React.FC<SaleProductsProps> = props => {
|
||||||
return (
|
return (
|
||||||
<Card>
|
<Card>
|
||||||
<CardTitle
|
<CardTitle
|
||||||
title={intl.formatMessage({
|
title={intl.formatMessage(messages.discountProductsHeader)}
|
||||||
defaultMessage: "Eligible Products",
|
|
||||||
description: "section header"
|
|
||||||
})}
|
|
||||||
toolbar={
|
toolbar={
|
||||||
<Button
|
<Button
|
||||||
color="primary"
|
color="primary"
|
||||||
onClick={onProductAssign}
|
onClick={onProductAssign}
|
||||||
data-test-id="assign-products"
|
data-test-id="assign-products"
|
||||||
>
|
>
|
||||||
<FormattedMessage
|
<FormattedMessage {...messages.discountProductsButton} />
|
||||||
defaultMessage="Assign products"
|
|
||||||
description="button"
|
|
||||||
/>
|
|
||||||
</Button>
|
</Button>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
@ -120,22 +83,23 @@ const DiscountProducts: React.FC<SaleProductsProps> = props => {
|
||||||
colSpan={numberOfColumns}
|
colSpan={numberOfColumns}
|
||||||
selected={selected}
|
selected={selected}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
items={mapEdgesToItems(sale?.products)}
|
items={products}
|
||||||
toggleAll={toggleAll}
|
toggleAll={toggleAll}
|
||||||
toolbar={toolbar}
|
toolbar={toolbar}
|
||||||
>
|
>
|
||||||
<TableCell className={classes.colName}>
|
<TableCell className={classes.colName}>
|
||||||
<span className={classes.colNameLabel}>
|
<span className={products?.length > 0 && classes.colNameLabel}>
|
||||||
<FormattedMessage defaultMessage="Product Name" />
|
<FormattedMessage
|
||||||
|
{...messages.discountProductsTableProductHeader}
|
||||||
|
/>
|
||||||
</span>
|
</span>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell className={classes.colType}>
|
<TableCell className={classes.colType}>
|
||||||
<FormattedMessage defaultMessage="Product Type" />
|
<FormattedMessage {...messages.discountProductsTableTypeHeader} />
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell className={classes.colPublished}>
|
<TableCell className={classes.colPublished}>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
defaultMessage="Availability"
|
{...messages.discountProductsTableAvailabilityHeader}
|
||||||
description="product availability"
|
|
||||||
/>
|
/>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell className={classes.colActions} />
|
<TableCell className={classes.colActions} />
|
||||||
|
@ -155,7 +119,7 @@ const DiscountProducts: React.FC<SaleProductsProps> = props => {
|
||||||
</TableFooter>
|
</TableFooter>
|
||||||
<TableBody>
|
<TableBody>
|
||||||
{renderCollection(
|
{renderCollection(
|
||||||
mapEdgesToItems(sale?.products),
|
products,
|
||||||
product => {
|
product => {
|
||||||
const isSelected = product ? isChecked(product.id) : false;
|
const isSelected = product ? isChecked(product.id) : false;
|
||||||
|
|
||||||
|
@ -216,7 +180,7 @@ const DiscountProducts: React.FC<SaleProductsProps> = props => {
|
||||||
() => (
|
() => (
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell colSpan={numberOfColumns}>
|
<TableCell colSpan={numberOfColumns}>
|
||||||
<FormattedMessage defaultMessage="No products found" />
|
<FormattedMessage {...messages.discountProductsNotFound} />
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
)
|
)
|
||||||
|
|
28
src/discounts/components/DiscountProducts/messages.ts
Normal file
28
src/discounts/components/DiscountProducts/messages.ts
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
import { defineMessages } from "react-intl";
|
||||||
|
|
||||||
|
export const messages = defineMessages({
|
||||||
|
discountProductsHeader: {
|
||||||
|
defaultMessage: "Eligible Products",
|
||||||
|
description: "section header"
|
||||||
|
},
|
||||||
|
discountProductsButton: {
|
||||||
|
defaultMessage: "Assign products",
|
||||||
|
description: "button"
|
||||||
|
},
|
||||||
|
discountProductsTableProductHeader: {
|
||||||
|
defaultMessage: "Product Name",
|
||||||
|
description: "table head"
|
||||||
|
},
|
||||||
|
discountProductsTableTypeHeader: {
|
||||||
|
defaultMessage: "Product Type",
|
||||||
|
description: "product type"
|
||||||
|
},
|
||||||
|
discountProductsTableAvailabilityHeader: {
|
||||||
|
defaultMessage: "Availability",
|
||||||
|
description: "product availability"
|
||||||
|
},
|
||||||
|
discountProductsNotFound: {
|
||||||
|
defaultMessage: "No products found",
|
||||||
|
description: "no products"
|
||||||
|
}
|
||||||
|
});
|
36
src/discounts/components/DiscountProducts/styles.ts
Normal file
36
src/discounts/components/DiscountProducts/styles.ts
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
import { AVATAR_MARGIN } from "@saleor/components/TableCellAvatar/Avatar";
|
||||||
|
import { makeStyles } from "@saleor/macaw-ui";
|
||||||
|
|
||||||
|
export const useStyles = makeStyles(
|
||||||
|
theme => ({
|
||||||
|
colActions: {
|
||||||
|
"&:last-child": {
|
||||||
|
paddingRight: 0
|
||||||
|
},
|
||||||
|
width: `calc(76px + ${theme.spacing(0.5)})`
|
||||||
|
},
|
||||||
|
colName: {
|
||||||
|
paddingLeft: 0,
|
||||||
|
width: "auto",
|
||||||
|
minWidth: 200
|
||||||
|
},
|
||||||
|
colNameLabel: {
|
||||||
|
marginLeft: `calc(${AVATAR_MARGIN}px + ${theme.spacing(3)})`
|
||||||
|
},
|
||||||
|
colPublished: {
|
||||||
|
width: "auto",
|
||||||
|
minWidth: 150
|
||||||
|
},
|
||||||
|
colType: {
|
||||||
|
width: "auto",
|
||||||
|
minWidth: 150
|
||||||
|
},
|
||||||
|
table: {
|
||||||
|
tableLayout: "fixed"
|
||||||
|
},
|
||||||
|
tableRow: {
|
||||||
|
cursor: "pointer"
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
{ name: "DiscountProducts" }
|
||||||
|
);
|
189
src/discounts/components/DiscountVariants/DiscountVariants.tsx
Normal file
189
src/discounts/components/DiscountVariants/DiscountVariants.tsx
Normal file
|
@ -0,0 +1,189 @@
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
Card,
|
||||||
|
IconButton,
|
||||||
|
TableBody,
|
||||||
|
TableCell,
|
||||||
|
TableFooter,
|
||||||
|
TableRow
|
||||||
|
} from "@material-ui/core";
|
||||||
|
import DeleteIcon from "@material-ui/icons/Delete";
|
||||||
|
import CardTitle from "@saleor/components/CardTitle";
|
||||||
|
import Checkbox from "@saleor/components/Checkbox";
|
||||||
|
import ResponsiveTable from "@saleor/components/ResponsiveTable";
|
||||||
|
import Skeleton from "@saleor/components/Skeleton";
|
||||||
|
import TableCellAvatar from "@saleor/components/TableCellAvatar";
|
||||||
|
import TableHead from "@saleor/components/TableHead";
|
||||||
|
import TablePagination from "@saleor/components/TablePagination";
|
||||||
|
import React from "react";
|
||||||
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
|
|
||||||
|
import { maybe, renderCollection } from "../../../misc";
|
||||||
|
import { ListActions, ListProps } from "../../../types";
|
||||||
|
import { SaleDetails_sale_variants_edges_node } from "../../types/SaleDetails";
|
||||||
|
import { messages } from "./messages";
|
||||||
|
import { useStyles } from "./styles";
|
||||||
|
export interface SaleVariantsProps
|
||||||
|
extends Omit<ListProps, "onRowClick">,
|
||||||
|
ListActions {
|
||||||
|
variants: SaleDetails_sale_variants_edges_node[] | null;
|
||||||
|
onVariantAssign: () => void;
|
||||||
|
onRowClick: (productId: string, variantId: string) => () => void;
|
||||||
|
onVariantUnassign: (id: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const numberOfColumns = 5;
|
||||||
|
|
||||||
|
const DiscountVariants: React.FC<SaleVariantsProps> = props => {
|
||||||
|
const {
|
||||||
|
variants,
|
||||||
|
disabled,
|
||||||
|
pageInfo,
|
||||||
|
onRowClick,
|
||||||
|
onPreviousPage,
|
||||||
|
onVariantAssign,
|
||||||
|
onVariantUnassign,
|
||||||
|
onNextPage,
|
||||||
|
isChecked,
|
||||||
|
selected,
|
||||||
|
toggle,
|
||||||
|
toggleAll,
|
||||||
|
toolbar
|
||||||
|
} = props;
|
||||||
|
const classes = useStyles(props);
|
||||||
|
|
||||||
|
const intl = useIntl();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card>
|
||||||
|
<CardTitle
|
||||||
|
title={intl.formatMessage(messages.discountVariantsHeader)}
|
||||||
|
toolbar={
|
||||||
|
<Button
|
||||||
|
color="primary"
|
||||||
|
onClick={onVariantAssign}
|
||||||
|
data-test-id="assign-variant"
|
||||||
|
>
|
||||||
|
<FormattedMessage {...messages.discountVariantsButton} />
|
||||||
|
</Button>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<ResponsiveTable>
|
||||||
|
<colgroup>
|
||||||
|
<col />
|
||||||
|
<col className={classes.colProductName} />
|
||||||
|
<col className={classes.colVariantName} />
|
||||||
|
<col className={classes.colType} />
|
||||||
|
<col className={classes.colActions} />
|
||||||
|
</colgroup>
|
||||||
|
<TableHead
|
||||||
|
colSpan={numberOfColumns}
|
||||||
|
selected={selected}
|
||||||
|
disabled={disabled}
|
||||||
|
items={variants}
|
||||||
|
toggleAll={toggleAll}
|
||||||
|
toolbar={toolbar}
|
||||||
|
>
|
||||||
|
<TableCell className={classes.colProductName}>
|
||||||
|
<span className={variants?.length > 0 && classes.colNameLabel}>
|
||||||
|
<FormattedMessage
|
||||||
|
{...messages.discountVariantsTableProductHeader}
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className={classes.colVariantName}>
|
||||||
|
<FormattedMessage
|
||||||
|
{...messages.discountVariantsTableVariantHeader}
|
||||||
|
/>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className={classes.colType}>
|
||||||
|
<FormattedMessage
|
||||||
|
{...messages.discountVariantsTableProductHeader}
|
||||||
|
/>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className={classes.colActions} />
|
||||||
|
</TableHead>
|
||||||
|
<TableFooter>
|
||||||
|
<TableRow>
|
||||||
|
<TablePagination
|
||||||
|
colSpan={numberOfColumns}
|
||||||
|
hasNextPage={pageInfo && !disabled ? pageInfo.hasNextPage : false}
|
||||||
|
onNextPage={onNextPage}
|
||||||
|
hasPreviousPage={
|
||||||
|
pageInfo && !disabled ? pageInfo.hasPreviousPage : false
|
||||||
|
}
|
||||||
|
onPreviousPage={onPreviousPage}
|
||||||
|
/>
|
||||||
|
</TableRow>
|
||||||
|
</TableFooter>
|
||||||
|
<TableBody>
|
||||||
|
{renderCollection(
|
||||||
|
variants,
|
||||||
|
variant => {
|
||||||
|
const isSelected = variant ? isChecked(variant.id) : false;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TableRow
|
||||||
|
hover={!!variant}
|
||||||
|
key={variant ? variant.id : "skeleton"}
|
||||||
|
onClick={
|
||||||
|
variant && onRowClick(variant.product.id, variant.id)
|
||||||
|
}
|
||||||
|
className={classes.tableRow}
|
||||||
|
selected={isSelected}
|
||||||
|
>
|
||||||
|
<TableCell padding="checkbox">
|
||||||
|
<Checkbox
|
||||||
|
checked={isSelected}
|
||||||
|
disabled={disabled}
|
||||||
|
disableClickPropagation
|
||||||
|
onChange={() => toggle(variant.id)}
|
||||||
|
/>
|
||||||
|
</TableCell>
|
||||||
|
<TableCellAvatar
|
||||||
|
className={classes.colProductName}
|
||||||
|
thumbnail={maybe(() => variant.product.thumbnail.url)}
|
||||||
|
>
|
||||||
|
{maybe<React.ReactNode>(
|
||||||
|
() => variant.product.name,
|
||||||
|
<Skeleton />
|
||||||
|
)}
|
||||||
|
</TableCellAvatar>
|
||||||
|
<TableCell className={classes.colType}>
|
||||||
|
{maybe<React.ReactNode>(() => variant.name, <Skeleton />)}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className={classes.colType}>
|
||||||
|
{maybe<React.ReactNode>(
|
||||||
|
() => variant.product.productType.name,
|
||||||
|
<Skeleton />
|
||||||
|
)}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className={classes.colActions}>
|
||||||
|
<IconButton
|
||||||
|
disabled={!variant || disabled}
|
||||||
|
onClick={event => {
|
||||||
|
event.stopPropagation();
|
||||||
|
onVariantUnassign(variant.id);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<DeleteIcon color="primary" />
|
||||||
|
</IconButton>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
() => (
|
||||||
|
<TableRow>
|
||||||
|
<TableCell colSpan={numberOfColumns}>
|
||||||
|
<FormattedMessage {...messages.discountVariantsNotFound} />
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</TableBody>
|
||||||
|
</ResponsiveTable>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
DiscountVariants.displayName = "DiscountVariants";
|
||||||
|
export default DiscountVariants;
|
2
src/discounts/components/DiscountVariants/index.ts
Normal file
2
src/discounts/components/DiscountVariants/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
export { default } from "./DiscountVariants";
|
||||||
|
export * from "./DiscountVariants";
|
28
src/discounts/components/DiscountVariants/messages.ts
Normal file
28
src/discounts/components/DiscountVariants/messages.ts
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
import { defineMessages } from "react-intl";
|
||||||
|
|
||||||
|
export const messages = defineMessages({
|
||||||
|
discountVariantsHeader: {
|
||||||
|
defaultMessage: "Eligible Variants",
|
||||||
|
description: "section header"
|
||||||
|
},
|
||||||
|
discountVariantsButton: {
|
||||||
|
defaultMessage: "Assign variants",
|
||||||
|
description: "button"
|
||||||
|
},
|
||||||
|
discountVariantsTableProductHeader: {
|
||||||
|
defaultMessage: "Product Name",
|
||||||
|
description: "table head"
|
||||||
|
},
|
||||||
|
discountVariantsTableVariantHeader: {
|
||||||
|
defaultMessage: "Variant Name",
|
||||||
|
description: "table head"
|
||||||
|
},
|
||||||
|
discountVariantsTableTypeHeader: {
|
||||||
|
defaultMessage: "Product Type",
|
||||||
|
description: "table head"
|
||||||
|
},
|
||||||
|
discountVariantsNotFound: {
|
||||||
|
defaultMessage: "No variants found",
|
||||||
|
description: "no variants"
|
||||||
|
}
|
||||||
|
});
|
36
src/discounts/components/DiscountVariants/styles.ts
Normal file
36
src/discounts/components/DiscountVariants/styles.ts
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
import { AVATAR_MARGIN } from "@saleor/components/TableCellAvatar/Avatar";
|
||||||
|
import { makeStyles } from "@saleor/macaw-ui";
|
||||||
|
|
||||||
|
export const useStyles = makeStyles(
|
||||||
|
theme => ({
|
||||||
|
colActions: {
|
||||||
|
"&:last-child": {
|
||||||
|
paddingRight: 0
|
||||||
|
},
|
||||||
|
width: `calc(76px + ${theme.spacing(0.5)})`
|
||||||
|
},
|
||||||
|
colProductName: {
|
||||||
|
paddingLeft: 0,
|
||||||
|
width: "auto",
|
||||||
|
minWidth: 200
|
||||||
|
},
|
||||||
|
colNameLabel: {
|
||||||
|
marginLeft: `calc(${AVATAR_MARGIN}px + ${theme.spacing(3)})`
|
||||||
|
},
|
||||||
|
colVariantName: {
|
||||||
|
width: "auto",
|
||||||
|
minWidth: 150
|
||||||
|
},
|
||||||
|
colType: {
|
||||||
|
width: "auto",
|
||||||
|
minWidth: 150
|
||||||
|
},
|
||||||
|
table: {
|
||||||
|
tableLayout: "fixed"
|
||||||
|
},
|
||||||
|
tableRow: {
|
||||||
|
cursor: "pointer"
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
{ name: "DiscountVariants" }
|
||||||
|
);
|
|
@ -14,6 +14,7 @@ import { DiscountErrorFragment } from "@saleor/fragments/types/DiscountErrorFrag
|
||||||
import { sectionNames } from "@saleor/intl";
|
import { sectionNames } from "@saleor/intl";
|
||||||
import { Backlink } from "@saleor/macaw-ui";
|
import { Backlink } from "@saleor/macaw-ui";
|
||||||
import { validatePrice } from "@saleor/products/utils/validation";
|
import { validatePrice } from "@saleor/products/utils/validation";
|
||||||
|
import { mapEdgesToItems } from "@saleor/utils/maps";
|
||||||
import { mapMetadataItemToInput } from "@saleor/utils/maps";
|
import { mapMetadataItemToInput } from "@saleor/utils/maps";
|
||||||
import useMetadataChangeTrigger from "@saleor/utils/metadata/useMetadataChangeTrigger";
|
import useMetadataChangeTrigger from "@saleor/utils/metadata/useMetadataChangeTrigger";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
@ -30,6 +31,7 @@ import DiscountCategories from "../DiscountCategories";
|
||||||
import DiscountCollections from "../DiscountCollections";
|
import DiscountCollections from "../DiscountCollections";
|
||||||
import DiscountDates from "../DiscountDates";
|
import DiscountDates from "../DiscountDates";
|
||||||
import DiscountProducts from "../DiscountProducts";
|
import DiscountProducts from "../DiscountProducts";
|
||||||
|
import DiscountVariants from "../DiscountVariants";
|
||||||
import SaleInfo from "../SaleInfo";
|
import SaleInfo from "../SaleInfo";
|
||||||
import SaleSummary from "../SaleSummary";
|
import SaleSummary from "../SaleSummary";
|
||||||
import SaleType from "../SaleType";
|
import SaleType from "../SaleType";
|
||||||
|
@ -49,20 +51,27 @@ export interface SaleDetailsPageFormData extends MetadataFormData {
|
||||||
export enum SaleDetailsPageTab {
|
export enum SaleDetailsPageTab {
|
||||||
categories = "categories",
|
categories = "categories",
|
||||||
collections = "collections",
|
collections = "collections",
|
||||||
products = "products"
|
products = "products",
|
||||||
|
variants = "variants"
|
||||||
}
|
}
|
||||||
|
|
||||||
export function saleDetailsPageTab(tab: string): SaleDetailsPageTab {
|
export function saleDetailsPageTab(tab: string): SaleDetailsPageTab {
|
||||||
return tab === SaleDetailsPageTab.products
|
return tab === SaleDetailsPageTab.products
|
||||||
? SaleDetailsPageTab.products
|
? SaleDetailsPageTab.products
|
||||||
: tab === SaleDetailsPageTab.collections
|
: tab === SaleDetailsPageTab.collections
|
||||||
? SaleDetailsPageTab.collections
|
? SaleDetailsPageTab.collections
|
||||||
: SaleDetailsPageTab.categories;
|
: tab === SaleDetailsPageTab.categories
|
||||||
|
? SaleDetailsPageTab.categories
|
||||||
|
: SaleDetailsPageTab.variants;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SaleDetailsPageProps
|
export interface SaleDetailsPageProps
|
||||||
extends Pick<ListProps, Exclude<keyof ListProps, "onRowClick">>,
|
extends Pick<ListProps, Exclude<keyof ListProps, "onRowClick">>,
|
||||||
TabListActions<
|
TabListActions<
|
||||||
"categoryListToolbar" | "collectionListToolbar" | "productListToolbar"
|
| "categoryListToolbar"
|
||||||
|
| "collectionListToolbar"
|
||||||
|
| "productListToolbar"
|
||||||
|
| "variantListToolbar"
|
||||||
>,
|
>,
|
||||||
ChannelProps {
|
ChannelProps {
|
||||||
activeTab: SaleDetailsPageTab;
|
activeTab: SaleDetailsPageTab;
|
||||||
|
@ -82,6 +91,9 @@ export interface SaleDetailsPageProps
|
||||||
onProductAssign: () => void;
|
onProductAssign: () => void;
|
||||||
onProductUnassign: (id: string) => void;
|
onProductUnassign: (id: string) => void;
|
||||||
onProductClick: (id: string) => () => void;
|
onProductClick: (id: string) => () => void;
|
||||||
|
onVariantAssign: () => void;
|
||||||
|
onVariantUnassign: (id: string) => void;
|
||||||
|
onVariantClick: (productId: string, variantId: string) => () => void;
|
||||||
onRemove: () => void;
|
onRemove: () => void;
|
||||||
onSubmit: (data: SaleDetailsPageFormData) => void;
|
onSubmit: (data: SaleDetailsPageFormData) => void;
|
||||||
onTabClick: (index: SaleDetailsPageTab) => void;
|
onTabClick: (index: SaleDetailsPageTab) => void;
|
||||||
|
@ -92,6 +104,7 @@ export interface SaleDetailsPageProps
|
||||||
const CategoriesTab = Tab(SaleDetailsPageTab.categories);
|
const CategoriesTab = Tab(SaleDetailsPageTab.categories);
|
||||||
const CollectionsTab = Tab(SaleDetailsPageTab.collections);
|
const CollectionsTab = Tab(SaleDetailsPageTab.collections);
|
||||||
const ProductsTab = Tab(SaleDetailsPageTab.products);
|
const ProductsTab = Tab(SaleDetailsPageTab.products);
|
||||||
|
const VariantsTab = Tab(SaleDetailsPageTab.variants);
|
||||||
|
|
||||||
const SaleDetailsPage: React.FC<SaleDetailsPageProps> = ({
|
const SaleDetailsPage: React.FC<SaleDetailsPageProps> = ({
|
||||||
activeTab,
|
activeTab,
|
||||||
|
@ -120,9 +133,13 @@ const SaleDetailsPage: React.FC<SaleDetailsPageProps> = ({
|
||||||
onProductAssign,
|
onProductAssign,
|
||||||
onProductUnassign,
|
onProductUnassign,
|
||||||
onProductClick,
|
onProductClick,
|
||||||
|
onVariantAssign,
|
||||||
|
onVariantUnassign,
|
||||||
|
onVariantClick,
|
||||||
categoryListToolbar,
|
categoryListToolbar,
|
||||||
collectionListToolbar,
|
collectionListToolbar,
|
||||||
productListToolbar,
|
productListToolbar,
|
||||||
|
variantListToolbar,
|
||||||
isChecked,
|
isChecked,
|
||||||
selected,
|
selected,
|
||||||
selectedChannelId,
|
selectedChannelId,
|
||||||
|
@ -239,6 +256,25 @@ const SaleDetailsPage: React.FC<SaleDetailsPageProps> = ({
|
||||||
}
|
}
|
||||||
)}
|
)}
|
||||||
</ProductsTab>
|
</ProductsTab>
|
||||||
|
<VariantsTab
|
||||||
|
testId="variants-tab"
|
||||||
|
isActive={activeTab === SaleDetailsPageTab.variants}
|
||||||
|
changeTab={onTabClick}
|
||||||
|
>
|
||||||
|
{intl.formatMessage(
|
||||||
|
{
|
||||||
|
defaultMessage: "Variants ({quantity})",
|
||||||
|
description: "number of variants",
|
||||||
|
id: "saleDetailsPageVariantsQuantity"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
quantity: maybe(
|
||||||
|
() => sale.variants.totalCount.toString(),
|
||||||
|
"…"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)}
|
||||||
|
</VariantsTab>
|
||||||
</TabContainer>
|
</TabContainer>
|
||||||
<CardSpacer />
|
<CardSpacer />
|
||||||
{activeTab === SaleDetailsPageTab.categories ? (
|
{activeTab === SaleDetailsPageTab.categories ? (
|
||||||
|
@ -273,7 +309,7 @@ const SaleDetailsPage: React.FC<SaleDetailsPageProps> = ({
|
||||||
toggleAll={toggleAll}
|
toggleAll={toggleAll}
|
||||||
toolbar={collectionListToolbar}
|
toolbar={collectionListToolbar}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : activeTab === SaleDetailsPageTab.products ? (
|
||||||
<DiscountProducts
|
<DiscountProducts
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
onNextPage={onNextPage}
|
onNextPage={onNextPage}
|
||||||
|
@ -282,7 +318,7 @@ const SaleDetailsPage: React.FC<SaleDetailsPageProps> = ({
|
||||||
onProductUnassign={onProductUnassign}
|
onProductUnassign={onProductUnassign}
|
||||||
onRowClick={onProductClick}
|
onRowClick={onProductClick}
|
||||||
pageInfo={pageInfo}
|
pageInfo={pageInfo}
|
||||||
discount={sale}
|
products={mapEdgesToItems(sale?.products)}
|
||||||
channelsCount={allChannelsCount}
|
channelsCount={allChannelsCount}
|
||||||
isChecked={isChecked}
|
isChecked={isChecked}
|
||||||
selected={selected}
|
selected={selected}
|
||||||
|
@ -290,6 +326,22 @@ const SaleDetailsPage: React.FC<SaleDetailsPageProps> = ({
|
||||||
toggleAll={toggleAll}
|
toggleAll={toggleAll}
|
||||||
toolbar={productListToolbar}
|
toolbar={productListToolbar}
|
||||||
/>
|
/>
|
||||||
|
) : (
|
||||||
|
<DiscountVariants
|
||||||
|
disabled={disabled}
|
||||||
|
onNextPage={onNextPage}
|
||||||
|
onPreviousPage={onPreviousPage}
|
||||||
|
onVariantAssign={onVariantAssign}
|
||||||
|
onVariantUnassign={onVariantUnassign}
|
||||||
|
onRowClick={onVariantClick}
|
||||||
|
pageInfo={pageInfo}
|
||||||
|
variants={mapEdgesToItems(sale?.variants)}
|
||||||
|
isChecked={isChecked}
|
||||||
|
selected={selected}
|
||||||
|
toggle={toggle}
|
||||||
|
toggleAll={toggleAll}
|
||||||
|
toolbar={variantListToolbar}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
<CardSpacer />
|
<CardSpacer />
|
||||||
<DiscountDates
|
<DiscountDates
|
||||||
|
|
|
@ -20,6 +20,7 @@ import { DiscountErrorFragment } from "@saleor/fragments/types/DiscountErrorFrag
|
||||||
import { sectionNames } from "@saleor/intl";
|
import { sectionNames } from "@saleor/intl";
|
||||||
import { Backlink } from "@saleor/macaw-ui";
|
import { Backlink } from "@saleor/macaw-ui";
|
||||||
import { validatePrice } from "@saleor/products/utils/validation";
|
import { validatePrice } from "@saleor/products/utils/validation";
|
||||||
|
import { mapEdgesToItems } from "@saleor/utils/maps";
|
||||||
import { mapMetadataItemToInput } from "@saleor/utils/maps";
|
import { mapMetadataItemToInput } from "@saleor/utils/maps";
|
||||||
import useMetadataChangeTrigger from "@saleor/utils/metadata/useMetadataChangeTrigger";
|
import useMetadataChangeTrigger from "@saleor/utils/metadata/useMetadataChangeTrigger";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
@ -353,7 +354,7 @@ const VoucherDetailsPage: React.FC<VoucherDetailsPageProps> = ({
|
||||||
onProductUnassign={onProductUnassign}
|
onProductUnassign={onProductUnassign}
|
||||||
onRowClick={onProductClick}
|
onRowClick={onProductClick}
|
||||||
pageInfo={pageInfo}
|
pageInfo={pageInfo}
|
||||||
discount={voucher}
|
products={mapEdgesToItems(voucher.products)}
|
||||||
channelsCount={allChannelsCount}
|
channelsCount={allChannelsCount}
|
||||||
isChecked={isChecked}
|
isChecked={isChecked}
|
||||||
selected={selected}
|
selected={selected}
|
||||||
|
|
|
@ -424,6 +424,147 @@ export const sale: SaleDetails_sale = {
|
||||||
},
|
},
|
||||||
totalCount: 4
|
totalCount: 4
|
||||||
},
|
},
|
||||||
|
variants: {
|
||||||
|
edges: [
|
||||||
|
{
|
||||||
|
node: {
|
||||||
|
id: "UHJvZHVjdFZhcmlhbnQ6MzE0",
|
||||||
|
name: "XL",
|
||||||
|
product: {
|
||||||
|
id: "UHJvZHVjdDoxMTg=",
|
||||||
|
name: "White Hoodie",
|
||||||
|
thumbnail: {
|
||||||
|
url: placeholderImage,
|
||||||
|
__typename: "Image"
|
||||||
|
},
|
||||||
|
productType: {
|
||||||
|
id: "UHJvZHVjdFR5cGU6MTQ=",
|
||||||
|
name: "Top (clothing)",
|
||||||
|
__typename: "ProductType"
|
||||||
|
},
|
||||||
|
channelListings: [
|
||||||
|
{
|
||||||
|
isPublished: true,
|
||||||
|
publicationDate: "2020-01-01",
|
||||||
|
isAvailableForPurchase: true,
|
||||||
|
availableForPurchase: "2020-08-31",
|
||||||
|
visibleInListings: true,
|
||||||
|
channel: {
|
||||||
|
id: "Q2hhbm5lbDox",
|
||||||
|
name: "Channel-USD",
|
||||||
|
currencyCode: "USD",
|
||||||
|
__typename: "Channel"
|
||||||
|
},
|
||||||
|
__typename: "ProductChannelListing"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
__typename: "Product"
|
||||||
|
},
|
||||||
|
__typename: "ProductVariant"
|
||||||
|
},
|
||||||
|
__typename: "ProductVariantCountableEdge"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
node: {
|
||||||
|
id: "UHJvZHVjdFZhcmlhbnQ6Mjc4",
|
||||||
|
name: "L",
|
||||||
|
product: {
|
||||||
|
id: "UHJvZHVjdDoxMTE=",
|
||||||
|
name: "T-shirt",
|
||||||
|
thumbnail: {
|
||||||
|
url: placeholderImage,
|
||||||
|
__typename: "Image"
|
||||||
|
},
|
||||||
|
productType: {
|
||||||
|
id: "UHJvZHVjdFR5cGU6MTQ=",
|
||||||
|
name: "Top (clothing)",
|
||||||
|
__typename: "ProductType"
|
||||||
|
},
|
||||||
|
channelListings: [
|
||||||
|
{
|
||||||
|
isPublished: true,
|
||||||
|
publicationDate: "2020-01-01",
|
||||||
|
isAvailableForPurchase: true,
|
||||||
|
availableForPurchase: "2020-08-31",
|
||||||
|
visibleInListings: true,
|
||||||
|
channel: {
|
||||||
|
id: "Q2hhbm5lbDox",
|
||||||
|
name: "Channel-USD",
|
||||||
|
currencyCode: "USD",
|
||||||
|
__typename: "Channel"
|
||||||
|
},
|
||||||
|
__typename: "ProductChannelListing"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
__typename: "Product"
|
||||||
|
},
|
||||||
|
__typename: "ProductVariant"
|
||||||
|
},
|
||||||
|
__typename: "ProductVariantCountableEdge"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
node: {
|
||||||
|
id: "UHJvZHVjdFZhcmlhbnQ6MjUz",
|
||||||
|
name: "L",
|
||||||
|
product: {
|
||||||
|
id: "UHJvZHVjdDo4OQ==",
|
||||||
|
name: "Code Division T-shirt",
|
||||||
|
thumbnail: {
|
||||||
|
url: placeholderImage,
|
||||||
|
__typename: "Image"
|
||||||
|
},
|
||||||
|
productType: {
|
||||||
|
id: "UHJvZHVjdFR5cGU6MTQ=",
|
||||||
|
name: "Top (clothing)",
|
||||||
|
__typename: "ProductType"
|
||||||
|
},
|
||||||
|
channelListings: [
|
||||||
|
{
|
||||||
|
isPublished: true,
|
||||||
|
publicationDate: "2020-01-01",
|
||||||
|
isAvailableForPurchase: true,
|
||||||
|
availableForPurchase: "2020-08-31",
|
||||||
|
visibleInListings: true,
|
||||||
|
channel: {
|
||||||
|
id: "Q2hhbm5lbDox",
|
||||||
|
name: "Channel-USD",
|
||||||
|
currencyCode: "USD",
|
||||||
|
__typename: "Channel"
|
||||||
|
},
|
||||||
|
__typename: "ProductChannelListing"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
isPublished: true,
|
||||||
|
publicationDate: "2020-01-01",
|
||||||
|
isAvailableForPurchase: true,
|
||||||
|
availableForPurchase: "2020-08-31",
|
||||||
|
visibleInListings: true,
|
||||||
|
channel: {
|
||||||
|
id: "Q2hhbm5lbDoy",
|
||||||
|
name: "Channel-PLN",
|
||||||
|
currencyCode: "PLN",
|
||||||
|
__typename: "Channel"
|
||||||
|
},
|
||||||
|
__typename: "ProductChannelListing"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
__typename: "Product"
|
||||||
|
},
|
||||||
|
__typename: "ProductVariant"
|
||||||
|
},
|
||||||
|
__typename: "ProductVariantCountableEdge"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
pageInfo: {
|
||||||
|
endCursor: "W251bGwsICIxMTgyMjM1OTEiXQ==",
|
||||||
|
hasNextPage: false,
|
||||||
|
hasPreviousPage: false,
|
||||||
|
startCursor: "W251bGwsICIxMDQwNDk0NiJd",
|
||||||
|
__typename: "PageInfo"
|
||||||
|
},
|
||||||
|
totalCount: 3,
|
||||||
|
__typename: "ProductVariantCountableConnection"
|
||||||
|
},
|
||||||
startDate: "2019-01-03",
|
startDate: "2019-01-03",
|
||||||
type: "PERCENTAGE" as SaleType
|
type: "PERCENTAGE" as SaleType
|
||||||
};
|
};
|
||||||
|
|
|
@ -43,6 +43,70 @@ export interface SaleCataloguesAdd_saleCataloguesAdd_sale_channelListings {
|
||||||
currency: string;
|
currency: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface SaleCataloguesAdd_saleCataloguesAdd_sale_variants_edges_node_product_thumbnail {
|
||||||
|
__typename: "Image";
|
||||||
|
url: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SaleCataloguesAdd_saleCataloguesAdd_sale_variants_edges_node_product_productType {
|
||||||
|
__typename: "ProductType";
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SaleCataloguesAdd_saleCataloguesAdd_sale_variants_edges_node_product_channelListings_channel {
|
||||||
|
__typename: "Channel";
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
currencyCode: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SaleCataloguesAdd_saleCataloguesAdd_sale_variants_edges_node_product_channelListings {
|
||||||
|
__typename: "ProductChannelListing";
|
||||||
|
isPublished: boolean;
|
||||||
|
publicationDate: any | null;
|
||||||
|
isAvailableForPurchase: boolean | null;
|
||||||
|
availableForPurchase: any | null;
|
||||||
|
visibleInListings: boolean;
|
||||||
|
channel: SaleCataloguesAdd_saleCataloguesAdd_sale_variants_edges_node_product_channelListings_channel;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SaleCataloguesAdd_saleCataloguesAdd_sale_variants_edges_node_product {
|
||||||
|
__typename: "Product";
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
thumbnail: SaleCataloguesAdd_saleCataloguesAdd_sale_variants_edges_node_product_thumbnail | null;
|
||||||
|
productType: SaleCataloguesAdd_saleCataloguesAdd_sale_variants_edges_node_product_productType;
|
||||||
|
channelListings: SaleCataloguesAdd_saleCataloguesAdd_sale_variants_edges_node_product_channelListings[] | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SaleCataloguesAdd_saleCataloguesAdd_sale_variants_edges_node {
|
||||||
|
__typename: "ProductVariant";
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
product: SaleCataloguesAdd_saleCataloguesAdd_sale_variants_edges_node_product;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SaleCataloguesAdd_saleCataloguesAdd_sale_variants_edges {
|
||||||
|
__typename: "ProductVariantCountableEdge";
|
||||||
|
node: SaleCataloguesAdd_saleCataloguesAdd_sale_variants_edges_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SaleCataloguesAdd_saleCataloguesAdd_sale_variants_pageInfo {
|
||||||
|
__typename: "PageInfo";
|
||||||
|
endCursor: string | null;
|
||||||
|
hasNextPage: boolean;
|
||||||
|
hasPreviousPage: boolean;
|
||||||
|
startCursor: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SaleCataloguesAdd_saleCataloguesAdd_sale_variants {
|
||||||
|
__typename: "ProductVariantCountableConnection";
|
||||||
|
edges: SaleCataloguesAdd_saleCataloguesAdd_sale_variants_edges[];
|
||||||
|
pageInfo: SaleCataloguesAdd_saleCataloguesAdd_sale_variants_pageInfo;
|
||||||
|
totalCount: number | null;
|
||||||
|
}
|
||||||
|
|
||||||
export interface SaleCataloguesAdd_saleCataloguesAdd_sale_products_edges_node_productType {
|
export interface SaleCataloguesAdd_saleCataloguesAdd_sale_products_edges_node_productType {
|
||||||
__typename: "ProductType";
|
__typename: "ProductType";
|
||||||
id: string;
|
id: string;
|
||||||
|
@ -174,6 +238,7 @@ export interface SaleCataloguesAdd_saleCataloguesAdd_sale {
|
||||||
startDate: any;
|
startDate: any;
|
||||||
endDate: any | null;
|
endDate: any | null;
|
||||||
channelListings: SaleCataloguesAdd_saleCataloguesAdd_sale_channelListings[] | null;
|
channelListings: SaleCataloguesAdd_saleCataloguesAdd_sale_channelListings[] | null;
|
||||||
|
variants: SaleCataloguesAdd_saleCataloguesAdd_sale_variants | null;
|
||||||
products: SaleCataloguesAdd_saleCataloguesAdd_sale_products | null;
|
products: SaleCataloguesAdd_saleCataloguesAdd_sale_products | null;
|
||||||
categories: SaleCataloguesAdd_saleCataloguesAdd_sale_categories | null;
|
categories: SaleCataloguesAdd_saleCataloguesAdd_sale_categories | null;
|
||||||
collections: SaleCataloguesAdd_saleCataloguesAdd_sale_collections | null;
|
collections: SaleCataloguesAdd_saleCataloguesAdd_sale_collections | null;
|
||||||
|
|
|
@ -43,6 +43,70 @@ export interface SaleCataloguesRemove_saleCataloguesRemove_sale_channelListings
|
||||||
currency: string;
|
currency: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface SaleCataloguesRemove_saleCataloguesRemove_sale_variants_edges_node_product_thumbnail {
|
||||||
|
__typename: "Image";
|
||||||
|
url: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SaleCataloguesRemove_saleCataloguesRemove_sale_variants_edges_node_product_productType {
|
||||||
|
__typename: "ProductType";
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SaleCataloguesRemove_saleCataloguesRemove_sale_variants_edges_node_product_channelListings_channel {
|
||||||
|
__typename: "Channel";
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
currencyCode: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SaleCataloguesRemove_saleCataloguesRemove_sale_variants_edges_node_product_channelListings {
|
||||||
|
__typename: "ProductChannelListing";
|
||||||
|
isPublished: boolean;
|
||||||
|
publicationDate: any | null;
|
||||||
|
isAvailableForPurchase: boolean | null;
|
||||||
|
availableForPurchase: any | null;
|
||||||
|
visibleInListings: boolean;
|
||||||
|
channel: SaleCataloguesRemove_saleCataloguesRemove_sale_variants_edges_node_product_channelListings_channel;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SaleCataloguesRemove_saleCataloguesRemove_sale_variants_edges_node_product {
|
||||||
|
__typename: "Product";
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
thumbnail: SaleCataloguesRemove_saleCataloguesRemove_sale_variants_edges_node_product_thumbnail | null;
|
||||||
|
productType: SaleCataloguesRemove_saleCataloguesRemove_sale_variants_edges_node_product_productType;
|
||||||
|
channelListings: SaleCataloguesRemove_saleCataloguesRemove_sale_variants_edges_node_product_channelListings[] | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SaleCataloguesRemove_saleCataloguesRemove_sale_variants_edges_node {
|
||||||
|
__typename: "ProductVariant";
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
product: SaleCataloguesRemove_saleCataloguesRemove_sale_variants_edges_node_product;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SaleCataloguesRemove_saleCataloguesRemove_sale_variants_edges {
|
||||||
|
__typename: "ProductVariantCountableEdge";
|
||||||
|
node: SaleCataloguesRemove_saleCataloguesRemove_sale_variants_edges_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SaleCataloguesRemove_saleCataloguesRemove_sale_variants_pageInfo {
|
||||||
|
__typename: "PageInfo";
|
||||||
|
endCursor: string | null;
|
||||||
|
hasNextPage: boolean;
|
||||||
|
hasPreviousPage: boolean;
|
||||||
|
startCursor: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SaleCataloguesRemove_saleCataloguesRemove_sale_variants {
|
||||||
|
__typename: "ProductVariantCountableConnection";
|
||||||
|
edges: SaleCataloguesRemove_saleCataloguesRemove_sale_variants_edges[];
|
||||||
|
pageInfo: SaleCataloguesRemove_saleCataloguesRemove_sale_variants_pageInfo;
|
||||||
|
totalCount: number | null;
|
||||||
|
}
|
||||||
|
|
||||||
export interface SaleCataloguesRemove_saleCataloguesRemove_sale_products_edges_node_productType {
|
export interface SaleCataloguesRemove_saleCataloguesRemove_sale_products_edges_node_productType {
|
||||||
__typename: "ProductType";
|
__typename: "ProductType";
|
||||||
id: string;
|
id: string;
|
||||||
|
@ -174,6 +238,7 @@ export interface SaleCataloguesRemove_saleCataloguesRemove_sale {
|
||||||
startDate: any;
|
startDate: any;
|
||||||
endDate: any | null;
|
endDate: any | null;
|
||||||
channelListings: SaleCataloguesRemove_saleCataloguesRemove_sale_channelListings[] | null;
|
channelListings: SaleCataloguesRemove_saleCataloguesRemove_sale_channelListings[] | null;
|
||||||
|
variants: SaleCataloguesRemove_saleCataloguesRemove_sale_variants | null;
|
||||||
products: SaleCataloguesRemove_saleCataloguesRemove_sale_products | null;
|
products: SaleCataloguesRemove_saleCataloguesRemove_sale_products | null;
|
||||||
categories: SaleCataloguesRemove_saleCataloguesRemove_sale_categories | null;
|
categories: SaleCataloguesRemove_saleCataloguesRemove_sale_categories | null;
|
||||||
collections: SaleCataloguesRemove_saleCataloguesRemove_sale_collections | null;
|
collections: SaleCataloguesRemove_saleCataloguesRemove_sale_collections | null;
|
||||||
|
|
|
@ -36,6 +36,70 @@ export interface SaleDetails_sale_channelListings {
|
||||||
currency: string;
|
currency: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface SaleDetails_sale_variants_edges_node_product_thumbnail {
|
||||||
|
__typename: "Image";
|
||||||
|
url: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SaleDetails_sale_variants_edges_node_product_productType {
|
||||||
|
__typename: "ProductType";
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SaleDetails_sale_variants_edges_node_product_channelListings_channel {
|
||||||
|
__typename: "Channel";
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
currencyCode: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SaleDetails_sale_variants_edges_node_product_channelListings {
|
||||||
|
__typename: "ProductChannelListing";
|
||||||
|
isPublished: boolean;
|
||||||
|
publicationDate: any | null;
|
||||||
|
isAvailableForPurchase: boolean | null;
|
||||||
|
availableForPurchase: any | null;
|
||||||
|
visibleInListings: boolean;
|
||||||
|
channel: SaleDetails_sale_variants_edges_node_product_channelListings_channel;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SaleDetails_sale_variants_edges_node_product {
|
||||||
|
__typename: "Product";
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
thumbnail: SaleDetails_sale_variants_edges_node_product_thumbnail | null;
|
||||||
|
productType: SaleDetails_sale_variants_edges_node_product_productType;
|
||||||
|
channelListings: SaleDetails_sale_variants_edges_node_product_channelListings[] | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SaleDetails_sale_variants_edges_node {
|
||||||
|
__typename: "ProductVariant";
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
product: SaleDetails_sale_variants_edges_node_product;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SaleDetails_sale_variants_edges {
|
||||||
|
__typename: "ProductVariantCountableEdge";
|
||||||
|
node: SaleDetails_sale_variants_edges_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SaleDetails_sale_variants_pageInfo {
|
||||||
|
__typename: "PageInfo";
|
||||||
|
endCursor: string | null;
|
||||||
|
hasNextPage: boolean;
|
||||||
|
hasPreviousPage: boolean;
|
||||||
|
startCursor: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SaleDetails_sale_variants {
|
||||||
|
__typename: "ProductVariantCountableConnection";
|
||||||
|
edges: SaleDetails_sale_variants_edges[];
|
||||||
|
pageInfo: SaleDetails_sale_variants_pageInfo;
|
||||||
|
totalCount: number | null;
|
||||||
|
}
|
||||||
|
|
||||||
export interface SaleDetails_sale_products_edges_node_productType {
|
export interface SaleDetails_sale_products_edges_node_productType {
|
||||||
__typename: "ProductType";
|
__typename: "ProductType";
|
||||||
id: string;
|
id: string;
|
||||||
|
@ -167,6 +231,7 @@ export interface SaleDetails_sale {
|
||||||
startDate: any;
|
startDate: any;
|
||||||
endDate: any | null;
|
endDate: any | null;
|
||||||
channelListings: SaleDetails_sale_channelListings[] | null;
|
channelListings: SaleDetails_sale_channelListings[] | null;
|
||||||
|
variants: SaleDetails_sale_variants | null;
|
||||||
products: SaleDetails_sale_products | null;
|
products: SaleDetails_sale_products | null;
|
||||||
categories: SaleDetails_sale_categories | null;
|
categories: SaleDetails_sale_categories | null;
|
||||||
collections: SaleDetails_sale_collections | null;
|
collections: SaleDetails_sale_collections | null;
|
||||||
|
|
|
@ -53,9 +53,11 @@ export type SaleUrlDialog =
|
||||||
| "assign-category"
|
| "assign-category"
|
||||||
| "assign-collection"
|
| "assign-collection"
|
||||||
| "assign-product"
|
| "assign-product"
|
||||||
|
| "assign-variant"
|
||||||
| "unassign-category"
|
| "unassign-category"
|
||||||
| "unassign-collection"
|
| "unassign-collection"
|
||||||
| "unassign-product"
|
| "unassign-product"
|
||||||
|
| "unassign-variant"
|
||||||
| "remove"
|
| "remove"
|
||||||
| ChannelsAction;
|
| ChannelsAction;
|
||||||
export type SaleUrlQueryParams = Pagination &
|
export type SaleUrlQueryParams = Pagination &
|
||||||
|
|
|
@ -11,6 +11,7 @@ import useAppChannel from "@saleor/components/AppLayout/AppChannelContext";
|
||||||
import AssignCategoriesDialog from "@saleor/components/AssignCategoryDialog";
|
import AssignCategoriesDialog from "@saleor/components/AssignCategoryDialog";
|
||||||
import AssignCollectionDialog from "@saleor/components/AssignCollectionDialog";
|
import AssignCollectionDialog from "@saleor/components/AssignCollectionDialog";
|
||||||
import AssignProductDialog from "@saleor/components/AssignProductDialog";
|
import AssignProductDialog from "@saleor/components/AssignProductDialog";
|
||||||
|
import AssignVariantDialog from "@saleor/components/AssignVariantDialog";
|
||||||
import ChannelsAvailabilityDialog from "@saleor/components/ChannelsAvailabilityDialog";
|
import ChannelsAvailabilityDialog from "@saleor/components/ChannelsAvailabilityDialog";
|
||||||
import { WindowTitle } from "@saleor/components/WindowTitle";
|
import { WindowTitle } from "@saleor/components/WindowTitle";
|
||||||
import { DEFAULT_INITIAL_SEARCH_DATA, PAGINATE_BY } from "@saleor/config";
|
import { DEFAULT_INITIAL_SEARCH_DATA, PAGINATE_BY } from "@saleor/config";
|
||||||
|
@ -45,7 +46,7 @@ import usePaginator, {
|
||||||
} from "@saleor/hooks/usePaginator";
|
} from "@saleor/hooks/usePaginator";
|
||||||
import { commonMessages, sectionNames } from "@saleor/intl";
|
import { commonMessages, sectionNames } from "@saleor/intl";
|
||||||
import { maybe } from "@saleor/misc";
|
import { maybe } from "@saleor/misc";
|
||||||
import { productUrl } from "@saleor/products/urls";
|
import { productUrl, productVariantEditPath } from "@saleor/products/urls";
|
||||||
import useCategorySearch from "@saleor/searches/useCategorySearch";
|
import useCategorySearch from "@saleor/searches/useCategorySearch";
|
||||||
import useCollectionSearch from "@saleor/searches/useCollectionSearch";
|
import useCollectionSearch from "@saleor/searches/useCollectionSearch";
|
||||||
import useProductSearch from "@saleor/searches/useProductSearch";
|
import useProductSearch from "@saleor/searches/useProductSearch";
|
||||||
|
@ -60,6 +61,7 @@ import React from "react";
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
|
|
||||||
import { createUpdateHandler } from "./handlers";
|
import { createUpdateHandler } from "./handlers";
|
||||||
|
import { messages } from "./messages";
|
||||||
|
|
||||||
interface SaleDetailsProps {
|
interface SaleDetailsProps {
|
||||||
id: string;
|
id: string;
|
||||||
|
@ -155,9 +157,7 @@ export const SaleDetails: React.FC<SaleDetailsProps> = ({ id, params }) => {
|
||||||
if (data.saleDelete.errors.length === 0) {
|
if (data.saleDelete.errors.length === 0) {
|
||||||
notify({
|
notify({
|
||||||
status: "success",
|
status: "success",
|
||||||
text: intl.formatMessage({
|
text: intl.formatMessage(messages.saleDetailsSaleDeleteDialog)
|
||||||
defaultMessage: "Removed sale"
|
|
||||||
})
|
|
||||||
});
|
});
|
||||||
navigate(saleListUrl(), true);
|
navigate(saleListUrl(), true);
|
||||||
}
|
}
|
||||||
|
@ -197,9 +197,9 @@ export const SaleDetails: React.FC<SaleDetailsProps> = ({ id, params }) => {
|
||||||
onChange={channelsToggle}
|
onChange={channelsToggle}
|
||||||
onClose={handleChannelsModalClose}
|
onClose={handleChannelsModalClose}
|
||||||
open={isChannelsModalOpen}
|
open={isChannelsModalOpen}
|
||||||
title={intl.formatMessage({
|
title={intl.formatMessage(
|
||||||
defaultMessage: "Manage Channel Availability"
|
messages.saleDetailsChannelAvailabilityDialogHeader
|
||||||
})}
|
)}
|
||||||
selected={channelListElements.length}
|
selected={channelListElements.length}
|
||||||
confirmButtonState="default"
|
confirmButtonState="default"
|
||||||
onConfirm={handleChannelsConfirm}
|
onConfirm={handleChannelsConfirm}
|
||||||
|
@ -219,7 +219,9 @@ export const SaleDetails: React.FC<SaleDetailsProps> = ({ id, params }) => {
|
||||||
? maybe(() => data.sale.categories.pageInfo)
|
? maybe(() => data.sale.categories.pageInfo)
|
||||||
: params.activeTab === SaleDetailsPageTab.collections
|
: params.activeTab === SaleDetailsPageTab.collections
|
||||||
? maybe(() => data.sale.collections.pageInfo)
|
? maybe(() => data.sale.collections.pageInfo)
|
||||||
: maybe(() => data.sale.products.pageInfo);
|
: params.activeTab === SaleDetailsPageTab.products
|
||||||
|
? maybe(() => data.sale.products.pageInfo)
|
||||||
|
: maybe(() => data.sale.variants.pageInfo);
|
||||||
|
|
||||||
const handleCategoriesUnassign = (ids: string[]) =>
|
const handleCategoriesUnassign = (ids: string[]) =>
|
||||||
saleCataloguesRemove({
|
saleCataloguesRemove({
|
||||||
|
@ -254,6 +256,17 @@ export const SaleDetails: React.FC<SaleDetailsProps> = ({ id, params }) => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const handleVariantsUnassign = (ids: string[]) =>
|
||||||
|
saleCataloguesRemove({
|
||||||
|
variables: {
|
||||||
|
...paginationState,
|
||||||
|
id,
|
||||||
|
input: {
|
||||||
|
variants: ids
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const {
|
const {
|
||||||
loadNextPage,
|
loadNextPage,
|
||||||
loadPreviousPage,
|
loadPreviousPage,
|
||||||
|
@ -324,6 +337,14 @@ export const SaleDetails: React.FC<SaleDetailsProps> = ({ id, params }) => {
|
||||||
}
|
}
|
||||||
onProductClick={id => () =>
|
onProductClick={id => () =>
|
||||||
navigate(productUrl(id))}
|
navigate(productUrl(id))}
|
||||||
|
onVariantAssign={() => openModal("assign-variant")}
|
||||||
|
onVariantUnassign={variantId =>
|
||||||
|
handleVariantsUnassign([variantId])
|
||||||
|
}
|
||||||
|
onVariantClick={(productId, variantId) => () =>
|
||||||
|
navigate(
|
||||||
|
productVariantEditPath(productId, variantId)
|
||||||
|
)}
|
||||||
activeTab={params.activeTab}
|
activeTab={params.activeTab}
|
||||||
onBack={() => navigate(saleListUrl())}
|
onBack={() => navigate(saleListUrl())}
|
||||||
onTabClick={changeTab}
|
onTabClick={changeTab}
|
||||||
|
@ -340,9 +361,7 @@ export const SaleDetails: React.FC<SaleDetailsProps> = ({ id, params }) => {
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
defaultMessage="Unassign"
|
{...messages.saleDetailsUnassignCategory}
|
||||||
description="unassign category from sale, button"
|
|
||||||
id="saleDetailsUnassignCategory"
|
|
||||||
/>
|
/>
|
||||||
</Button>
|
</Button>
|
||||||
}
|
}
|
||||||
|
@ -356,9 +375,7 @@ export const SaleDetails: React.FC<SaleDetailsProps> = ({ id, params }) => {
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
defaultMessage="Unassign"
|
{...messages.saleDetailsUnassignCollection}
|
||||||
description="unassign collection from sale, button"
|
|
||||||
id="saleDetailsUnassignCollection"
|
|
||||||
/>
|
/>
|
||||||
</Button>
|
</Button>
|
||||||
}
|
}
|
||||||
|
@ -372,9 +389,21 @@ export const SaleDetails: React.FC<SaleDetailsProps> = ({ id, params }) => {
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
defaultMessage="Unassign"
|
{...messages.saleDetailsUnassignProduct}
|
||||||
description="unassign product from sale, button"
|
/>
|
||||||
id="saleDetailsUnassignProduct"
|
</Button>
|
||||||
|
}
|
||||||
|
variantListToolbar={
|
||||||
|
<Button
|
||||||
|
color="primary"
|
||||||
|
onClick={() =>
|
||||||
|
openModal("unassign-variant", {
|
||||||
|
ids: listElements
|
||||||
|
})
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<FormattedMessage
|
||||||
|
{...messages.saleDetailsUnassignVariant}
|
||||||
/>
|
/>
|
||||||
</Button>
|
</Button>
|
||||||
}
|
}
|
||||||
|
@ -383,6 +412,34 @@ export const SaleDetails: React.FC<SaleDetailsProps> = ({ id, params }) => {
|
||||||
toggle={toggle}
|
toggle={toggle}
|
||||||
toggleAll={toggleAll}
|
toggleAll={toggleAll}
|
||||||
/>
|
/>
|
||||||
|
<AssignVariantDialog
|
||||||
|
confirmButtonState={saleCataloguesAddOpts.status}
|
||||||
|
hasMore={
|
||||||
|
searchProductsOpts.data?.search.pageInfo
|
||||||
|
.hasNextPage
|
||||||
|
}
|
||||||
|
open={params.action === "assign-variant"}
|
||||||
|
onFetch={searchProducts}
|
||||||
|
onFetchMore={loadMoreProducts}
|
||||||
|
loading={searchProductsOpts.loading}
|
||||||
|
onClose={closeModal}
|
||||||
|
onSubmit={variants =>
|
||||||
|
saleCataloguesAdd({
|
||||||
|
variables: {
|
||||||
|
...paginationState,
|
||||||
|
id,
|
||||||
|
input: {
|
||||||
|
variants: variants.map(
|
||||||
|
variant => variant.id
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
products={mapEdgesToItems(
|
||||||
|
searchProductsOpts?.data?.search
|
||||||
|
)?.filter(suggestedProduct => suggestedProduct.id)}
|
||||||
|
/>
|
||||||
<AssignProductDialog
|
<AssignProductDialog
|
||||||
confirmButtonState={saleCataloguesAddOpts.status}
|
confirmButtonState={saleCataloguesAddOpts.status}
|
||||||
hasMore={
|
hasMore={
|
||||||
|
@ -400,9 +457,7 @@ export const SaleDetails: React.FC<SaleDetailsProps> = ({ id, params }) => {
|
||||||
...paginationState,
|
...paginationState,
|
||||||
id,
|
id,
|
||||||
input: {
|
input: {
|
||||||
products: products.map(
|
products
|
||||||
product => product.id
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -472,10 +527,9 @@ export const SaleDetails: React.FC<SaleDetailsProps> = ({ id, params }) => {
|
||||||
params.action === "unassign-category" &&
|
params.action === "unassign-category" &&
|
||||||
canOpenBulkActionDialog
|
canOpenBulkActionDialog
|
||||||
}
|
}
|
||||||
title={intl.formatMessage({
|
title={intl.formatMessage(
|
||||||
defaultMessage: "Unassign Categories From Sale",
|
messages.saleDetailsUnassignCategoryDialogHeader
|
||||||
description: "dialog header"
|
)}
|
||||||
})}
|
|
||||||
confirmButtonState={saleCataloguesRemoveOpts.status}
|
confirmButtonState={saleCataloguesRemoveOpts.status}
|
||||||
onClose={closeModal}
|
onClose={closeModal}
|
||||||
onConfirm={() =>
|
onConfirm={() =>
|
||||||
|
@ -485,8 +539,7 @@ export const SaleDetails: React.FC<SaleDetailsProps> = ({ id, params }) => {
|
||||||
{canOpenBulkActionDialog && (
|
{canOpenBulkActionDialog && (
|
||||||
<DialogContentText>
|
<DialogContentText>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
defaultMessage="{counter,plural,one{Are you sure you want to unassign this category?} other{Are you sure you want to unassign {displayQuantity} categories?}}"
|
{...messages.saleDetailsUnassignCategoryDialog}
|
||||||
description="dialog content"
|
|
||||||
values={{
|
values={{
|
||||||
counter: params.ids.length,
|
counter: params.ids.length,
|
||||||
displayQuantity: (
|
displayQuantity: (
|
||||||
|
@ -502,10 +555,9 @@ export const SaleDetails: React.FC<SaleDetailsProps> = ({ id, params }) => {
|
||||||
params.action === "unassign-collection" &&
|
params.action === "unassign-collection" &&
|
||||||
canOpenBulkActionDialog
|
canOpenBulkActionDialog
|
||||||
}
|
}
|
||||||
title={intl.formatMessage({
|
title={intl.formatMessage(
|
||||||
defaultMessage: "Unassign Collections From Sale",
|
messages.saleDetailsUnassignCollectionDialogHeader
|
||||||
description: "dialog header"
|
)}
|
||||||
})}
|
|
||||||
confirmButtonState={saleCataloguesRemoveOpts.status}
|
confirmButtonState={saleCataloguesRemoveOpts.status}
|
||||||
onClose={closeModal}
|
onClose={closeModal}
|
||||||
onConfirm={() =>
|
onConfirm={() =>
|
||||||
|
@ -515,8 +567,7 @@ export const SaleDetails: React.FC<SaleDetailsProps> = ({ id, params }) => {
|
||||||
{canOpenBulkActionDialog && (
|
{canOpenBulkActionDialog && (
|
||||||
<DialogContentText>
|
<DialogContentText>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
defaultMessage="{counter,plural,one{Are you sure you want to unassign this collection?} other{Are you sure you want to unassign {displayQuantity} collections?}}"
|
{...messages.saleDetailsUnassignCollectionDialog}
|
||||||
description="dialog content"
|
|
||||||
values={{
|
values={{
|
||||||
counter: params.ids.length,
|
counter: params.ids.length,
|
||||||
displayQuantity: (
|
displayQuantity: (
|
||||||
|
@ -532,10 +583,9 @@ export const SaleDetails: React.FC<SaleDetailsProps> = ({ id, params }) => {
|
||||||
params.action === "unassign-product" &&
|
params.action === "unassign-product" &&
|
||||||
canOpenBulkActionDialog
|
canOpenBulkActionDialog
|
||||||
}
|
}
|
||||||
title={intl.formatMessage({
|
title={intl.formatMessage(
|
||||||
defaultMessage: "Unassign Products From Sale",
|
messages.saleDetailsUnassignProductDialogHeader
|
||||||
description: "dialog header"
|
)}
|
||||||
})}
|
|
||||||
confirmButtonState={saleCataloguesRemoveOpts.status}
|
confirmButtonState={saleCataloguesRemoveOpts.status}
|
||||||
onClose={closeModal}
|
onClose={closeModal}
|
||||||
onConfirm={() => handleProductsUnassign(params.ids)}
|
onConfirm={() => handleProductsUnassign(params.ids)}
|
||||||
|
@ -543,8 +593,33 @@ export const SaleDetails: React.FC<SaleDetailsProps> = ({ id, params }) => {
|
||||||
{canOpenBulkActionDialog && (
|
{canOpenBulkActionDialog && (
|
||||||
<DialogContentText>
|
<DialogContentText>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
defaultMessage="{counter,plural,one{Are you sure you want to unassign this product?} other{Are you sure you want to unassign {displayQuantity} products?}}"
|
{...messages.saleDetailsUnassignCategoryDialog}
|
||||||
description="dialog content"
|
values={{
|
||||||
|
counter: params.ids.length,
|
||||||
|
displayQuantity: (
|
||||||
|
<strong>{params.ids.length}</strong>
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</DialogContentText>
|
||||||
|
)}
|
||||||
|
</ActionDialog>
|
||||||
|
<ActionDialog
|
||||||
|
open={
|
||||||
|
params.action === "unassign-variant" &&
|
||||||
|
canOpenBulkActionDialog
|
||||||
|
}
|
||||||
|
title={intl.formatMessage(
|
||||||
|
messages.saleDetailsUnassignVariantDialogHeader
|
||||||
|
)}
|
||||||
|
confirmButtonState={saleCataloguesRemoveOpts.status}
|
||||||
|
onClose={closeModal}
|
||||||
|
onConfirm={() => handleVariantsUnassign(params.ids)}
|
||||||
|
>
|
||||||
|
{canOpenBulkActionDialog && (
|
||||||
|
<DialogContentText>
|
||||||
|
<FormattedMessage
|
||||||
|
{...messages.saleDetailsUnassignVariantDialog}
|
||||||
values={{
|
values={{
|
||||||
counter: params.ids.length,
|
counter: params.ids.length,
|
||||||
displayQuantity: (
|
displayQuantity: (
|
||||||
|
@ -557,10 +632,9 @@ export const SaleDetails: React.FC<SaleDetailsProps> = ({ id, params }) => {
|
||||||
</ActionDialog>
|
</ActionDialog>
|
||||||
<ActionDialog
|
<ActionDialog
|
||||||
open={params.action === "remove"}
|
open={params.action === "remove"}
|
||||||
title={intl.formatMessage({
|
title={intl.formatMessage(
|
||||||
defaultMessage: "Delete Sale",
|
messages.saleDetailsSaleDeleteDialogHeader
|
||||||
description: "dialog header"
|
)}
|
||||||
})}
|
|
||||||
confirmButtonState={saleDeleteOpts.status}
|
confirmButtonState={saleDeleteOpts.status}
|
||||||
onClose={closeModal}
|
onClose={closeModal}
|
||||||
variant="delete"
|
variant="delete"
|
||||||
|
@ -572,8 +646,7 @@ export const SaleDetails: React.FC<SaleDetailsProps> = ({ id, params }) => {
|
||||||
>
|
>
|
||||||
<DialogContentText>
|
<DialogContentText>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
defaultMessage="Are you sure you want to delete {saleName}?"
|
{...messages.saleDetailsUnassignDialogDelete}
|
||||||
description="dialog content"
|
|
||||||
values={{
|
values={{
|
||||||
saleName: (
|
saleName: (
|
||||||
<strong>
|
<strong>
|
||||||
|
|
76
src/discounts/views/SaleDetails/messages.ts
Normal file
76
src/discounts/views/SaleDetails/messages.ts
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
import { defineMessages } from "react-intl";
|
||||||
|
|
||||||
|
export const messages = defineMessages({
|
||||||
|
saleDetailsUnassignCategory: {
|
||||||
|
defaultMessage: "Unassign",
|
||||||
|
description: "unassign category from sale, button"
|
||||||
|
},
|
||||||
|
saleDetailsUnassignCollection: {
|
||||||
|
defaultMessage: "Unassign",
|
||||||
|
description: "unassign collection from sale, button"
|
||||||
|
},
|
||||||
|
saleDetailsUnassignProduct: {
|
||||||
|
defaultMessage: "Unassign",
|
||||||
|
description: "unassign product from sale, button"
|
||||||
|
},
|
||||||
|
saleDetailsUnassignVariant: {
|
||||||
|
defaultMessage: "Unassign",
|
||||||
|
description: "unassign variant from sale, button"
|
||||||
|
},
|
||||||
|
saleDetailsUnassignCategoryDialog: {
|
||||||
|
defaultMessage:
|
||||||
|
"{counter,plural,one{Are you sure you want to unassign this category?} other{Are you sure you want to unassign {displayQuantity} categories?}}",
|
||||||
|
description: "dialog content"
|
||||||
|
},
|
||||||
|
saleDetailsUnassignCollectionDialog: {
|
||||||
|
defaultMessage:
|
||||||
|
"{counter,plural,one{Are you sure you want to unassign this collection?} other{Are you sure you want to unassign {displayQuantity} collections?}}",
|
||||||
|
description: "dialog content"
|
||||||
|
},
|
||||||
|
saleDetailsUnassignProductDialog: {
|
||||||
|
defaultMessage:
|
||||||
|
"{counter,plural,one{Are you sure you want to unassign this product?} other{Are you sure you want to unassign {displayQuantity} products?}}",
|
||||||
|
description: "dialog content"
|
||||||
|
},
|
||||||
|
saleDetailsUnassignVariantDialog: {
|
||||||
|
defaultMessage:
|
||||||
|
"{counter,plural,one{Are you sure you want to unassign this variant?} other{Are you sure you want to unassign {displayQuantity} variants?}}",
|
||||||
|
description: "dialog content"
|
||||||
|
},
|
||||||
|
saleDetailsUnassignDialogDelete: {
|
||||||
|
defaultMessage: "Are you sure you want to delete {saleName}?",
|
||||||
|
description: "dialog content"
|
||||||
|
},
|
||||||
|
saleDetailsSaleDelate: {
|
||||||
|
defaultMessage: "Removed sale",
|
||||||
|
description: "sale Details delete button"
|
||||||
|
},
|
||||||
|
saleDetailsUnassignCategoryDialogHeader: {
|
||||||
|
defaultMessage: "Unassign Categories From Sale",
|
||||||
|
description: "dialog header"
|
||||||
|
},
|
||||||
|
saleDetailsUnassignCollectionDialogHeader: {
|
||||||
|
defaultMessage: "Unassign Collection From Sale",
|
||||||
|
description: "dialog header"
|
||||||
|
},
|
||||||
|
saleDetailsUnassignProductDialogHeader: {
|
||||||
|
defaultMessage: "Unassign Product From Sale",
|
||||||
|
description: "dialog header"
|
||||||
|
},
|
||||||
|
saleDetailsUnassignVariantDialogHeader: {
|
||||||
|
defaultMessage: "Unassign Variant From Sale",
|
||||||
|
description: "dialog header"
|
||||||
|
},
|
||||||
|
saleDetailsSaleDeleteDialog: {
|
||||||
|
defaultMessage: "Removed sale",
|
||||||
|
description: "dialog content"
|
||||||
|
},
|
||||||
|
saleDetailsSaleDeleteDialogHeader: {
|
||||||
|
defaultMessage: "Delete Sale",
|
||||||
|
description: "dialog header"
|
||||||
|
},
|
||||||
|
saleDetailsChannelAvailabilityDialogHeader: {
|
||||||
|
defaultMessage: "Manage Channel Availability",
|
||||||
|
description: "channel availability dialog header"
|
||||||
|
}
|
||||||
|
});
|
|
@ -533,9 +533,7 @@ export const VoucherDetails: React.FC<VoucherDetailsProps> = ({
|
||||||
...paginationState,
|
...paginationState,
|
||||||
id,
|
id,
|
||||||
input: {
|
input: {
|
||||||
products: products.map(
|
products
|
||||||
product => product.id
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -32,6 +32,32 @@ export const saleDetailsFragment = gql`
|
||||||
${saleFragment}
|
${saleFragment}
|
||||||
fragment SaleDetailsFragment on Sale {
|
fragment SaleDetailsFragment on Sale {
|
||||||
...SaleFragment
|
...SaleFragment
|
||||||
|
variants(after: $after, before: $before, first: $first, last: $last) {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
product {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
thumbnail {
|
||||||
|
url
|
||||||
|
}
|
||||||
|
productType {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
}
|
||||||
|
channelListings {
|
||||||
|
...ChannelListingProductWithoutPricingFragment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pageInfo {
|
||||||
|
...PageInfoFragment
|
||||||
|
}
|
||||||
|
totalCount
|
||||||
|
}
|
||||||
products(after: $after, before: $before, first: $first, last: $last) {
|
products(after: $after, before: $before, first: $first, last: $last) {
|
||||||
edges {
|
edges {
|
||||||
node {
|
node {
|
||||||
|
|
|
@ -36,6 +36,70 @@ export interface SaleDetailsFragment_channelListings {
|
||||||
currency: string;
|
currency: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface SaleDetailsFragment_variants_edges_node_product_thumbnail {
|
||||||
|
__typename: "Image";
|
||||||
|
url: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SaleDetailsFragment_variants_edges_node_product_productType {
|
||||||
|
__typename: "ProductType";
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SaleDetailsFragment_variants_edges_node_product_channelListings_channel {
|
||||||
|
__typename: "Channel";
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
currencyCode: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SaleDetailsFragment_variants_edges_node_product_channelListings {
|
||||||
|
__typename: "ProductChannelListing";
|
||||||
|
isPublished: boolean;
|
||||||
|
publicationDate: any | null;
|
||||||
|
isAvailableForPurchase: boolean | null;
|
||||||
|
availableForPurchase: any | null;
|
||||||
|
visibleInListings: boolean;
|
||||||
|
channel: SaleDetailsFragment_variants_edges_node_product_channelListings_channel;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SaleDetailsFragment_variants_edges_node_product {
|
||||||
|
__typename: "Product";
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
thumbnail: SaleDetailsFragment_variants_edges_node_product_thumbnail | null;
|
||||||
|
productType: SaleDetailsFragment_variants_edges_node_product_productType;
|
||||||
|
channelListings: SaleDetailsFragment_variants_edges_node_product_channelListings[] | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SaleDetailsFragment_variants_edges_node {
|
||||||
|
__typename: "ProductVariant";
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
product: SaleDetailsFragment_variants_edges_node_product;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SaleDetailsFragment_variants_edges {
|
||||||
|
__typename: "ProductVariantCountableEdge";
|
||||||
|
node: SaleDetailsFragment_variants_edges_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SaleDetailsFragment_variants_pageInfo {
|
||||||
|
__typename: "PageInfo";
|
||||||
|
endCursor: string | null;
|
||||||
|
hasNextPage: boolean;
|
||||||
|
hasPreviousPage: boolean;
|
||||||
|
startCursor: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SaleDetailsFragment_variants {
|
||||||
|
__typename: "ProductVariantCountableConnection";
|
||||||
|
edges: SaleDetailsFragment_variants_edges[];
|
||||||
|
pageInfo: SaleDetailsFragment_variants_pageInfo;
|
||||||
|
totalCount: number | null;
|
||||||
|
}
|
||||||
|
|
||||||
export interface SaleDetailsFragment_products_edges_node_productType {
|
export interface SaleDetailsFragment_products_edges_node_productType {
|
||||||
__typename: "ProductType";
|
__typename: "ProductType";
|
||||||
id: string;
|
id: string;
|
||||||
|
@ -167,6 +231,7 @@ export interface SaleDetailsFragment {
|
||||||
startDate: any;
|
startDate: any;
|
||||||
endDate: any | null;
|
endDate: any | null;
|
||||||
channelListings: SaleDetailsFragment_channelListings[] | null;
|
channelListings: SaleDetailsFragment_channelListings[] | null;
|
||||||
|
variants: SaleDetailsFragment_variants | null;
|
||||||
products: SaleDetailsFragment_products | null;
|
products: SaleDetailsFragment_products | null;
|
||||||
categories: SaleDetailsFragment_categories | null;
|
categories: SaleDetailsFragment_categories | null;
|
||||||
collections: SaleDetailsFragment_collections | null;
|
collections: SaleDetailsFragment_collections | null;
|
||||||
|
|
|
@ -12,11 +12,40 @@ export interface SearchProducts_search_edges_node_thumbnail {
|
||||||
url: string;
|
url: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface SearchProducts_search_edges_node_variants_channelListings_channel {
|
||||||
|
__typename: "Channel";
|
||||||
|
id: string;
|
||||||
|
isActive: boolean;
|
||||||
|
name: string;
|
||||||
|
currencyCode: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SearchProducts_search_edges_node_variants_channelListings_price {
|
||||||
|
__typename: "Money";
|
||||||
|
amount: number;
|
||||||
|
currency: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SearchProducts_search_edges_node_variants_channelListings {
|
||||||
|
__typename: "ProductVariantChannelListing";
|
||||||
|
channel: SearchProducts_search_edges_node_variants_channelListings_channel;
|
||||||
|
price: SearchProducts_search_edges_node_variants_channelListings_price | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SearchProducts_search_edges_node_variants {
|
||||||
|
__typename: "ProductVariant";
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
sku: string;
|
||||||
|
channelListings: SearchProducts_search_edges_node_variants_channelListings[] | null;
|
||||||
|
}
|
||||||
|
|
||||||
export interface SearchProducts_search_edges_node {
|
export interface SearchProducts_search_edges_node {
|
||||||
__typename: "Product";
|
__typename: "Product";
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
thumbnail: SearchProducts_search_edges_node_thumbnail | null;
|
thumbnail: SearchProducts_search_edges_node_thumbnail | null;
|
||||||
|
variants: (SearchProducts_search_edges_node_variants | null)[] | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SearchProducts_search_edges {
|
export interface SearchProducts_search_edges {
|
||||||
|
|
55
src/searches/types/SearchVariants.ts
Normal file
55
src/searches/types/SearchVariants.ts
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
// @generated
|
||||||
|
// This file was automatically generated and should not be edited.
|
||||||
|
|
||||||
|
// ====================================================
|
||||||
|
// GraphQL query operation: SearchVariants
|
||||||
|
// ====================================================
|
||||||
|
|
||||||
|
export interface SearchVariants_search_edges_node_product_thumbnail {
|
||||||
|
__typename: "Image";
|
||||||
|
url: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SearchVariants_search_edges_node_product {
|
||||||
|
__typename: "Product";
|
||||||
|
name: string;
|
||||||
|
thumbnail: SearchVariants_search_edges_node_product_thumbnail | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SearchVariants_search_edges_node {
|
||||||
|
__typename: "ProductVariant";
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
product: SearchVariants_search_edges_node_product;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SearchVariants_search_edges {
|
||||||
|
__typename: "ProductVariantCountableEdge";
|
||||||
|
node: SearchVariants_search_edges_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SearchVariants_search_pageInfo {
|
||||||
|
__typename: "PageInfo";
|
||||||
|
endCursor: string | null;
|
||||||
|
hasNextPage: boolean;
|
||||||
|
hasPreviousPage: boolean;
|
||||||
|
startCursor: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SearchVariants_search {
|
||||||
|
__typename: "ProductVariantCountableConnection";
|
||||||
|
edges: SearchVariants_search_edges[];
|
||||||
|
pageInfo: SearchVariants_search_pageInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SearchVariants {
|
||||||
|
search: SearchVariants_search | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SearchVariantsVariables {
|
||||||
|
after?: string | null;
|
||||||
|
first: number;
|
||||||
|
query: string;
|
||||||
|
}
|
|
@ -18,6 +18,23 @@ export const searchProducts = gql`
|
||||||
thumbnail {
|
thumbnail {
|
||||||
url
|
url
|
||||||
}
|
}
|
||||||
|
variants {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
sku
|
||||||
|
channelListings {
|
||||||
|
channel {
|
||||||
|
id
|
||||||
|
isActive
|
||||||
|
name
|
||||||
|
currencyCode
|
||||||
|
}
|
||||||
|
price {
|
||||||
|
amount
|
||||||
|
currency
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pageInfo {
|
pageInfo {
|
||||||
|
|
|
@ -1873,15 +1873,46 @@ export const products: SearchProducts_search_edges_node[] = [
|
||||||
thumbnail: {
|
thumbnail: {
|
||||||
__typename: "Image",
|
__typename: "Image",
|
||||||
url: ""
|
url: ""
|
||||||
}
|
},
|
||||||
},
|
variants: [
|
||||||
{
|
{
|
||||||
__typename: "Product",
|
__typename: "ProductVariant",
|
||||||
id: "2",
|
id: "UHJvZHVjdFZhcmlhbnQ6MjAz",
|
||||||
name: "Banana Juice",
|
name: "1l",
|
||||||
thumbnail: {
|
sku: "43226647",
|
||||||
__typename: "Image",
|
channelListings: [
|
||||||
url: ""
|
{
|
||||||
}
|
__typename: "ProductVariantChannelListing",
|
||||||
|
channel: {
|
||||||
|
__typename: "Channel",
|
||||||
|
id: "Q2hhbm5lbDox",
|
||||||
|
isActive: true,
|
||||||
|
name: "Channel-USD",
|
||||||
|
currencyCode: "USD"
|
||||||
|
},
|
||||||
|
price: {
|
||||||
|
__typename: "Money",
|
||||||
|
amount: 5,
|
||||||
|
currency: "USD"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
__typename: "ProductVariantChannelListing",
|
||||||
|
channel: {
|
||||||
|
__typename: "Channel",
|
||||||
|
id: "Q2hhbm5lbDoy",
|
||||||
|
isActive: true,
|
||||||
|
name: "Channel-PLN",
|
||||||
|
currencyCode: "PLN"
|
||||||
|
},
|
||||||
|
price: {
|
||||||
|
__typename: "Money",
|
||||||
|
amount: 20,
|
||||||
|
currency: "PLN"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
|
@ -88061,6 +88061,12 @@ exports[`Storyshots Views / Discounts / Sale details collections 1`] = `
|
||||||
>
|
>
|
||||||
Products (4)
|
Products (4)
|
||||||
</span>
|
</span>
|
||||||
|
<span
|
||||||
|
class="MuiTypography-root-id Tab-root-id MuiTypography-body1-id"
|
||||||
|
data-test-id="variants-tab"
|
||||||
|
>
|
||||||
|
Variants (3)
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="CardSpacer-spacer-id"
|
class="CardSpacer-spacer-id"
|
||||||
|
@ -88155,10 +88161,10 @@ exports[`Storyshots Views / Discounts / Sale details collections 1`] = `
|
||||||
class="MuiTableCell-root-id MuiTableCell-head-id DiscountCollections-colName-id"
|
class="MuiTableCell-root-id MuiTableCell-head-id DiscountCollections-colName-id"
|
||||||
scope="col"
|
scope="col"
|
||||||
>
|
>
|
||||||
Collection name
|
Collection Name
|
||||||
</th>
|
</th>
|
||||||
<th
|
<th
|
||||||
class="MuiTableCell-root-id MuiTableCell-head-id DiscountCollections-textRight-id"
|
class="MuiTableCell-root-id MuiTableCell-head-id DiscountCollections-colProducts-id"
|
||||||
scope="col"
|
scope="col"
|
||||||
>
|
>
|
||||||
Products
|
Products
|
||||||
|
@ -89484,6 +89490,12 @@ exports[`Storyshots Views / Discounts / Sale details default 1`] = `
|
||||||
>
|
>
|
||||||
Products (4)
|
Products (4)
|
||||||
</span>
|
</span>
|
||||||
|
<span
|
||||||
|
class="MuiTypography-root-id Tab-root-id MuiTypography-body1-id"
|
||||||
|
data-test-id="variants-tab"
|
||||||
|
>
|
||||||
|
Variants (3)
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="CardSpacer-spacer-id"
|
class="CardSpacer-spacer-id"
|
||||||
|
@ -89578,7 +89590,7 @@ exports[`Storyshots Views / Discounts / Sale details default 1`] = `
|
||||||
class="MuiTableCell-root-id MuiTableCell-head-id DiscountCategories-colName-id"
|
class="MuiTableCell-root-id MuiTableCell-head-id DiscountCategories-colName-id"
|
||||||
scope="col"
|
scope="col"
|
||||||
>
|
>
|
||||||
Category name
|
Category Name
|
||||||
</th>
|
</th>
|
||||||
<th
|
<th
|
||||||
class="MuiTableCell-root-id MuiTableCell-head-id DiscountCategories-colProducts-id"
|
class="MuiTableCell-root-id MuiTableCell-head-id DiscountCategories-colProducts-id"
|
||||||
|
@ -90912,6 +90924,12 @@ exports[`Storyshots Views / Discounts / Sale details form errors 1`] = `
|
||||||
>
|
>
|
||||||
Products (4)
|
Products (4)
|
||||||
</span>
|
</span>
|
||||||
|
<span
|
||||||
|
class="MuiTypography-root-id Tab-root-id MuiTypography-body1-id"
|
||||||
|
data-test-id="variants-tab"
|
||||||
|
>
|
||||||
|
Variants (3)
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="CardSpacer-spacer-id"
|
class="CardSpacer-spacer-id"
|
||||||
|
@ -91006,7 +91024,7 @@ exports[`Storyshots Views / Discounts / Sale details form errors 1`] = `
|
||||||
class="MuiTableCell-root-id MuiTableCell-head-id DiscountCategories-colName-id"
|
class="MuiTableCell-root-id MuiTableCell-head-id DiscountCategories-colName-id"
|
||||||
scope="col"
|
scope="col"
|
||||||
>
|
>
|
||||||
Category name
|
Category Name
|
||||||
</th>
|
</th>
|
||||||
<th
|
<th
|
||||||
class="MuiTableCell-root-id MuiTableCell-head-id DiscountCategories-colProducts-id"
|
class="MuiTableCell-root-id MuiTableCell-head-id DiscountCategories-colProducts-id"
|
||||||
|
@ -92363,6 +92381,12 @@ exports[`Storyshots Views / Discounts / Sale details loading 1`] = `
|
||||||
>
|
>
|
||||||
Products (…)
|
Products (…)
|
||||||
</span>
|
</span>
|
||||||
|
<span
|
||||||
|
class="MuiTypography-root-id Tab-root-id MuiTypography-body1-id"
|
||||||
|
data-test-id="variants-tab"
|
||||||
|
>
|
||||||
|
Variants (…)
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="CardSpacer-spacer-id"
|
class="CardSpacer-spacer-id"
|
||||||
|
@ -92459,7 +92483,7 @@ exports[`Storyshots Views / Discounts / Sale details loading 1`] = `
|
||||||
class="MuiTableCell-root-id MuiTableCell-head-id DiscountCategories-colName-id"
|
class="MuiTableCell-root-id MuiTableCell-head-id DiscountCategories-colName-id"
|
||||||
scope="col"
|
scope="col"
|
||||||
>
|
>
|
||||||
Category name
|
Category Name
|
||||||
</th>
|
</th>
|
||||||
<th
|
<th
|
||||||
class="MuiTableCell-root-id MuiTableCell-head-id DiscountCategories-colProducts-id"
|
class="MuiTableCell-root-id MuiTableCell-head-id DiscountCategories-colProducts-id"
|
||||||
|
@ -93778,6 +93802,12 @@ exports[`Storyshots Views / Discounts / Sale details products 1`] = `
|
||||||
>
|
>
|
||||||
Products (4)
|
Products (4)
|
||||||
</span>
|
</span>
|
||||||
|
<span
|
||||||
|
class="MuiTypography-root-id Tab-root-id MuiTypography-body1-id"
|
||||||
|
data-test-id="variants-tab"
|
||||||
|
>
|
||||||
|
Variants (3)
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="CardSpacer-spacer-id"
|
class="CardSpacer-spacer-id"
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
import placeholderImage from "@assets/images/placeholder60x60.png";
|
|
||||||
import AssignProductDialog, {
|
import AssignProductDialog, {
|
||||||
AssignProductDialogProps
|
AssignProductDialogProps
|
||||||
} from "@saleor/components/AssignProductDialog";
|
} from "@saleor/components/AssignProductDialog";
|
||||||
import { fetchMoreProps } from "@saleor/fixtures";
|
import { fetchMoreProps } from "@saleor/fixtures";
|
||||||
import { products } from "@saleor/products/fixtures";
|
import { products } from "@saleor/shipping/fixtures";
|
||||||
import { storiesOf } from "@storybook/react";
|
import { storiesOf } from "@storybook/react";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
|
@ -17,7 +16,7 @@ const props: AssignProductDialogProps = {
|
||||||
onFetch: () => undefined,
|
onFetch: () => undefined,
|
||||||
onSubmit: () => undefined,
|
onSubmit: () => undefined,
|
||||||
open: true,
|
open: true,
|
||||||
products: products(placeholderImage)
|
products
|
||||||
};
|
};
|
||||||
|
|
||||||
storiesOf("Generics / Assign product", module)
|
storiesOf("Generics / Assign product", module)
|
||||||
|
|
|
@ -36,6 +36,9 @@ const props: SaleDetailsPageProps = {
|
||||||
onProductAssign: () => undefined,
|
onProductAssign: () => undefined,
|
||||||
onProductClick: () => undefined,
|
onProductClick: () => undefined,
|
||||||
onProductUnassign: () => undefined,
|
onProductUnassign: () => undefined,
|
||||||
|
onVariantAssign: () => undefined,
|
||||||
|
onVariantClick: () => undefined,
|
||||||
|
onVariantUnassign: () => undefined,
|
||||||
onRemove: () => undefined,
|
onRemove: () => undefined,
|
||||||
onSubmit: () => undefined,
|
onSubmit: () => undefined,
|
||||||
onTabClick: () => undefined,
|
onTabClick: () => undefined,
|
||||||
|
@ -45,6 +48,7 @@ const props: SaleDetailsPageProps = {
|
||||||
hasPreviousPage: false
|
hasPreviousPage: false
|
||||||
},
|
},
|
||||||
productListToolbar: null,
|
productListToolbar: null,
|
||||||
|
variantListToolbar: null,
|
||||||
sale,
|
sale,
|
||||||
saveButtonBarState: "default",
|
saveButtonBarState: "default",
|
||||||
selectedChannelId: "123",
|
selectedChannelId: "123",
|
||||||
|
|
|
@ -2018,6 +2018,7 @@ export interface CatalogueInput {
|
||||||
products?: (string | null)[] | null;
|
products?: (string | null)[] | null;
|
||||||
categories?: (string | null)[] | null;
|
categories?: (string | null)[] | null;
|
||||||
collections?: (string | null)[] | null;
|
collections?: (string | null)[] | null;
|
||||||
|
variants?: (string | null)[] | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CategoryFilterInput {
|
export interface CategoryFilterInput {
|
||||||
|
@ -2674,6 +2675,7 @@ export interface SaleInput {
|
||||||
type?: DiscountValueTypeEnum | null;
|
type?: DiscountValueTypeEnum | null;
|
||||||
value?: any | null;
|
value?: any | null;
|
||||||
products?: (string | null)[] | null;
|
products?: (string | null)[] | null;
|
||||||
|
variants?: (string | null)[] | null;
|
||||||
categories?: (string | null)[] | null;
|
categories?: (string | null)[] | null;
|
||||||
collections?: (string | null)[] | null;
|
collections?: (string | null)[] | null;
|
||||||
startDate?: any | null;
|
startDate?: any | null;
|
||||||
|
|
Loading…
Reference in a new issue