commit
2b0f2933ec
127 changed files with 6869 additions and 1625 deletions
|
@ -21,3 +21,4 @@ All notable, unreleased changes to this project will be documented in this file.
|
||||||
- UI improvements - #166 by @benekex2
|
- UI improvements - #166 by @benekex2
|
||||||
- Fix en locale matching - #165 by @dominik-zeglen
|
- Fix en locale matching - #165 by @dominik-zeglen
|
||||||
- Implement the Credential Management API - #158 by @patrys
|
- Implement the Credential Management API - #158 by @patrys
|
||||||
|
- Add search bars - #172 by @dominik-zeglen
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"POT-Creation-Date: 2019-09-10T11:00:36.829Z\n"
|
"POT-Creation-Date: 2019-09-12T15:12:49.543Z\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
|
@ -455,8 +455,8 @@ msgctxt "button"
|
||||||
msgid "Add staff member"
|
msgid "Add staff member"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/locale/src/categories/components/CategoryList/CategoryList.json
|
#: build/locale/src/categories/components/CategoryUpdatePage/CategoryUpdatePage.json
|
||||||
#. [src.categories.components.CategoryList.435697837] - button
|
#. [src.categories.components.CategoryUpdatePage.435697837] - button
|
||||||
#. defaultMessage is:
|
#. defaultMessage is:
|
||||||
#. Add subcategory
|
#. Add subcategory
|
||||||
msgctxt "button"
|
msgctxt "button"
|
||||||
|
@ -627,6 +627,46 @@ msgctxt "tax rate"
|
||||||
msgid "Agricultural supplies"
|
msgid "Agricultural supplies"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: build/locale/src/attributes/components/AttributeListPage/AttributeListPage.json
|
||||||
|
#. [src.attributes.components.AttributeListPage.2417065806] - tab name
|
||||||
|
#. defaultMessage is:
|
||||||
|
#. All Attributes
|
||||||
|
msgctxt "tab name"
|
||||||
|
msgid "All Attributes"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: build/locale/src/categories/components/CategoryListPage/CategoryListPage.json
|
||||||
|
#. [src.categories.components.CategoryListPage.4294878092] - tab name
|
||||||
|
#. defaultMessage is:
|
||||||
|
#. All Categories
|
||||||
|
msgctxt "tab name"
|
||||||
|
msgid "All Categories"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: build/locale/src/collections/components/CollectionListPage/CollectionListPage.json
|
||||||
|
#. [src.collections.components.CollectionListPage.1631917001] - tab name
|
||||||
|
#. defaultMessage is:
|
||||||
|
#. All Collections
|
||||||
|
msgctxt "tab name"
|
||||||
|
msgid "All Collections"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: build/locale/src/customers/components/CustomerListPage/CustomerListPage.json
|
||||||
|
#. [src.customers.components.CustomerListPage.477293306] - tab name
|
||||||
|
#. defaultMessage is:
|
||||||
|
#. All Customers
|
||||||
|
msgctxt "tab name"
|
||||||
|
msgid "All Customers"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: build/locale/src/orders/components/OrderDraftListPage/OrderDraftListPage.json
|
||||||
|
#. [src.orders.components.OrderDraftListPage.551325728] - tab name
|
||||||
|
#. defaultMessage is:
|
||||||
|
#. All Drafts
|
||||||
|
msgctxt "tab name"
|
||||||
|
msgid "All Drafts"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: build/locale/src/orders/components/OrderListPage/OrderListPage.json
|
#: build/locale/src/orders/components/OrderListPage/OrderListPage.json
|
||||||
#. [src.orders.components.OrderListPage.875489544] - tab name
|
#. [src.orders.components.OrderListPage.875489544] - tab name
|
||||||
#. defaultMessage is:
|
#. defaultMessage is:
|
||||||
|
@ -643,22 +683,54 @@ msgctxt "section header"
|
||||||
msgid "All Photos"
|
msgid "All Photos"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/locale/src/products/components/ProductListPage/ProductListPage.json
|
#: build/locale/src/productTypes/components/ProductTypeListPage/ProductTypeListPage.json
|
||||||
#. [src.products.components.ProductListPage.821159718] - tab name
|
#. [src.productTypes.components.ProductTypeListPage.1776073799] - tab name
|
||||||
|
#. defaultMessage is:
|
||||||
|
#. All Product Types
|
||||||
|
msgctxt "tab name"
|
||||||
|
msgid "All Product Types"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: build/locale/src/products/components/ProductListFilter/ProductListFilter.json
|
||||||
|
#. [src.products.components.ProductListFilter.821159718] - tab name
|
||||||
#. defaultMessage is:
|
#. defaultMessage is:
|
||||||
#. All Products
|
#. All Products
|
||||||
msgctxt "tab name"
|
msgctxt "tab name"
|
||||||
msgid "All Products"
|
msgid "All Products"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/locale/src/categories/components/CategoryList/CategoryList.json
|
#: build/locale/src/discounts/components/SaleListPage/SaleListPage.json
|
||||||
#. [src.categories.components.CategoryList.3229914152] - section header
|
#. [src.discounts.components.SaleListPage.3907768880] - tab name
|
||||||
|
#. defaultMessage is:
|
||||||
|
#. All Sales
|
||||||
|
msgctxt "tab name"
|
||||||
|
msgid "All Sales"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: build/locale/src/staff/components/StaffListPage/StaffListPage.json
|
||||||
|
#. [src.staff.components.StaffListPage.2852350932] - tab name
|
||||||
|
#. defaultMessage is:
|
||||||
|
#. All Staff Members
|
||||||
|
msgctxt "tab name"
|
||||||
|
msgid "All Staff Members"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: build/locale/src/categories/components/CategoryUpdatePage/CategoryUpdatePage.json
|
||||||
|
#. [src.categories.components.CategoryUpdatePage.3229914152] - section header
|
||||||
#. defaultMessage is:
|
#. defaultMessage is:
|
||||||
#. All Subcategories
|
#. All Subcategories
|
||||||
msgctxt "section header"
|
msgctxt "section header"
|
||||||
msgid "All Subcategories"
|
msgid "All Subcategories"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: build/locale/src/discounts/components/VoucherListPage/VoucherListPage.json
|
||||||
|
#. [src.discounts.components.VoucherListPage.1112241061] - tab name
|
||||||
|
#. defaultMessage is:
|
||||||
|
#. All Vouchers
|
||||||
|
msgctxt "tab name"
|
||||||
|
msgid "All Vouchers"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: build/locale/src/taxes/components/TaxConfiguration/TaxConfiguration.json
|
#: build/locale/src/taxes/components/TaxConfiguration/TaxConfiguration.json
|
||||||
#. [src.taxes.components.TaxConfiguration.142803418]
|
#. [src.taxes.components.TaxConfiguration.142803418]
|
||||||
#. defaultMessage is:
|
#. defaultMessage is:
|
||||||
|
@ -815,10 +887,6 @@ msgstr ""
|
||||||
#. [src.categories.views.299584400]
|
#. [src.categories.views.299584400]
|
||||||
#. defaultMessage is:
|
#. defaultMessage is:
|
||||||
#. Are you sure you want to delete {counter,plural,one{this attribute} other{{displayQuantity} categories}}?
|
#. Are you sure you want to delete {counter,plural,one{this attribute} other{{displayQuantity} categories}}?
|
||||||
#: build/locale/src/categories/views/CategoryList.json
|
|
||||||
#. [src.categories.views.844574071]
|
|
||||||
#. defaultMessage is:
|
|
||||||
#. Are you sure you want to delete {counter,plural,one{this attribute} other{{displayQuantity} categories}}?
|
|
||||||
msgctxt "description"
|
msgctxt "description"
|
||||||
msgid "Are you sure you want to delete {counter,plural,one{this attribute} other{{displayQuantity} categories}}?"
|
msgid "Are you sure you want to delete {counter,plural,one{this attribute} other{{displayQuantity} categories}}?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -831,16 +899,24 @@ msgctxt "description"
|
||||||
msgid "Are you sure you want to delete {counter,plural,one{this attribute} other{{displayQuantity} products}}?"
|
msgid "Are you sure you want to delete {counter,plural,one{this attribute} other{{displayQuantity} products}}?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/locale/src/collections/views/CollectionList.json
|
#: build/locale/src/categories/views/CategoryList/CategoryList.json
|
||||||
#. [src.collections.views.2497542455]
|
#. [src.categories.views.CategoryList.2144707585]
|
||||||
|
#. defaultMessage is:
|
||||||
|
#. Are you sure you want to delete {counter,plural,one{this category} other{{displayQuantity} categories}}?
|
||||||
|
msgctxt "description"
|
||||||
|
msgid "Are you sure you want to delete {counter,plural,one{this category} other{{displayQuantity} categories}}?"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: build/locale/src/collections/views/CollectionList/CollectionList.json
|
||||||
|
#. [src.collections.views.CollectionList.2497542455]
|
||||||
#. defaultMessage is:
|
#. defaultMessage is:
|
||||||
#. Are you sure you want to delete {counter,plural,one{this collection} other{{displayQuantity} collections}}?
|
#. Are you sure you want to delete {counter,plural,one{this collection} other{{displayQuantity} collections}}?
|
||||||
msgctxt "description"
|
msgctxt "description"
|
||||||
msgid "Are you sure you want to delete {counter,plural,one{this collection} other{{displayQuantity} collections}}?"
|
msgid "Are you sure you want to delete {counter,plural,one{this collection} other{{displayQuantity} collections}}?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/locale/src/customers/views/CustomerList.json
|
#: build/locale/src/customers/views/CustomerList/CustomerList.json
|
||||||
#. [src.customers.views.409347866]
|
#. [src.customers.views.CustomerList.409347866]
|
||||||
#. defaultMessage is:
|
#. defaultMessage is:
|
||||||
#. Are you sure you want to delete {counter,plural,one{this customer} other{{displayQuantity} customers}}?
|
#. Are you sure you want to delete {counter,plural,one{this customer} other{{displayQuantity} customers}}?
|
||||||
msgctxt "description"
|
msgctxt "description"
|
||||||
|
@ -855,8 +931,8 @@ msgctxt "description"
|
||||||
msgid "Are you sure you want to delete {counter,plural,one{this menu} other{{displayQuantity} menus}}?"
|
msgid "Are you sure you want to delete {counter,plural,one{this menu} other{{displayQuantity} menus}}?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/locale/src/orders/views/OrderDraftList.json
|
#: build/locale/src/orders/views/OrderDraftList/OrderDraftList.json
|
||||||
#. [src.orders.views.1389231130] - dialog content
|
#. [src.orders.views.OrderDraftList.1389231130] - dialog content
|
||||||
#. defaultMessage is:
|
#. defaultMessage is:
|
||||||
#. Are you sure you want to delete {counter,plural,one{this order draft} other{{displayQuantity} orderDrafts}}?
|
#. Are you sure you want to delete {counter,plural,one{this order draft} other{{displayQuantity} orderDrafts}}?
|
||||||
msgctxt "dialog content"
|
msgctxt "dialog content"
|
||||||
|
@ -871,8 +947,8 @@ msgctxt "dialog content"
|
||||||
msgid "Are you sure you want to delete {counter,plural,one{this page} other{{displayQuantity} pages}}?"
|
msgid "Are you sure you want to delete {counter,plural,one{this page} other{{displayQuantity} pages}}?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/locale/src/productTypes/views/ProductTypeList.json
|
#: build/locale/src/productTypes/views/ProductTypeList/ProductTypeList.json
|
||||||
#. [src.productTypes.views.2294091098] - dialog content
|
#. [src.productTypes.views.ProductTypeList.2294091098] - dialog content
|
||||||
#. defaultMessage is:
|
#. defaultMessage is:
|
||||||
#. Are you sure you want to delete {counter,plural,one{this product type} other{{displayQuantity} product types}}?
|
#. Are you sure you want to delete {counter,plural,one{this product type} other{{displayQuantity} product types}}?
|
||||||
msgctxt "dialog content"
|
msgctxt "dialog content"
|
||||||
|
@ -887,8 +963,8 @@ msgctxt "dialog content"
|
||||||
msgid "Are you sure you want to delete {counter,plural,one{this product} other{{displayQuantity} products}}?"
|
msgid "Are you sure you want to delete {counter,plural,one{this product} other{{displayQuantity} products}}?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/locale/src/discounts/views/SaleList.json
|
#: build/locale/src/discounts/views/SaleList/SaleList.json
|
||||||
#. [src.discounts.views.2516361175] - dialog content
|
#. [src.discounts.views.SaleList.2516361175] - dialog content
|
||||||
#. defaultMessage is:
|
#. defaultMessage is:
|
||||||
#. Are you sure you want to delete {counter,plural,one{this sale} other{{displayQuantity} sales}}?
|
#. Are you sure you want to delete {counter,plural,one{this sale} other{{displayQuantity} sales}}?
|
||||||
msgctxt "dialog content"
|
msgctxt "dialog content"
|
||||||
|
@ -911,8 +987,8 @@ msgctxt "dialog content"
|
||||||
msgid "Are you sure you want to delete {counter,plural,one{this variant} other{{displayQuantity} variants}}?"
|
msgid "Are you sure you want to delete {counter,plural,one{this variant} other{{displayQuantity} variants}}?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/locale/src/discounts/views/VoucherList.json
|
#: build/locale/src/discounts/views/VoucherList/VoucherList.json
|
||||||
#. [src.discounts.views.1791926983] - dialog content
|
#. [src.discounts.views.VoucherList.1791926983] - dialog content
|
||||||
#. defaultMessage is:
|
#. defaultMessage is:
|
||||||
#. Are you sure you want to delete {counter,plural,one{this voucher} other{{displayQuantity} vouchers}}?
|
#. Are you sure you want to delete {counter,plural,one{this voucher} other{{displayQuantity} vouchers}}?
|
||||||
msgctxt "dialog content"
|
msgctxt "dialog content"
|
||||||
|
@ -1031,8 +1107,8 @@ msgctxt "description"
|
||||||
msgid "Are you sure you want to mark this order as paid?"
|
msgid "Are you sure you want to mark this order as paid?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/locale/src/collections/views/CollectionList.json
|
#: build/locale/src/collections/views/CollectionList/CollectionList.json
|
||||||
#. [src.collections.views.1348793822]
|
#. [src.collections.views.CollectionList.1348793822]
|
||||||
#. defaultMessage is:
|
#. defaultMessage is:
|
||||||
#. Are you sure you want to publish {counter,plural,one{this collection} other{{displayQuantity} collections}}?
|
#. Are you sure you want to publish {counter,plural,one{this collection} other{{displayQuantity} collections}}?
|
||||||
msgctxt "description"
|
msgctxt "description"
|
||||||
|
@ -1155,8 +1231,8 @@ msgctxt "dialog content"
|
||||||
msgid "Are you sure you want to unassign {counter,plural,one{this product} other{{displayQuantity} products}}?"
|
msgid "Are you sure you want to unassign {counter,plural,one{this product} other{{displayQuantity} products}}?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/locale/src/collections/views/CollectionList.json
|
#: build/locale/src/collections/views/CollectionList/CollectionList.json
|
||||||
#. [src.collections.views.3944356444]
|
#. [src.collections.views.CollectionList.3944356444]
|
||||||
#. defaultMessage is:
|
#. defaultMessage is:
|
||||||
#. Are you sure you want to unpublish {counter,plural,one{this collection} other{{displayQuantity} collections}}?
|
#. Are you sure you want to unpublish {counter,plural,one{this collection} other{{displayQuantity} collections}}?
|
||||||
msgctxt "description"
|
msgctxt "description"
|
||||||
|
@ -1439,10 +1515,6 @@ msgctxt "description"
|
||||||
msgid "Availability"
|
msgid "Availability"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/locale/src/attributes/components/ProductListFilter/ProductListFilter.json
|
|
||||||
#. [src.attributes.components.ProductListFilter.2157131639] - product status
|
|
||||||
#. defaultMessage is:
|
|
||||||
#. Available
|
|
||||||
#: build/locale/src/products/components/ProductListFilter/ProductListFilter.json
|
#: build/locale/src/products/components/ProductListFilter/ProductListFilter.json
|
||||||
#. [src.products.components.ProductListFilter.2157131639] - product status
|
#. [src.products.components.ProductListFilter.2157131639] - product status
|
||||||
#. defaultMessage is:
|
#. defaultMessage is:
|
||||||
|
@ -2319,6 +2391,10 @@ msgstr ""
|
||||||
#. [src.components.FilterBar.2340527467]
|
#. [src.components.FilterBar.2340527467]
|
||||||
#. defaultMessage is:
|
#. defaultMessage is:
|
||||||
#. Custom Filter
|
#. Custom Filter
|
||||||
|
#: build/locale/src/components/SearchBar/SearchBar.json
|
||||||
|
#. [src.components.SearchBar.2340527467]
|
||||||
|
#. defaultMessage is:
|
||||||
|
#. Custom Filter
|
||||||
msgctxt "description"
|
msgctxt "description"
|
||||||
msgid "Custom Filter"
|
msgid "Custom Filter"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -2571,8 +2647,8 @@ msgctxt "dialog title"
|
||||||
msgid "Delete Collection"
|
msgid "Delete Collection"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/locale/src/orders/views/OrderDraftList.json
|
#: build/locale/src/orders/views/OrderDraftList/OrderDraftList.json
|
||||||
#. [src.orders.views.1161115149] - dialog header
|
#. [src.orders.views.OrderDraftList.1161115149] - dialog header
|
||||||
#. defaultMessage is:
|
#. defaultMessage is:
|
||||||
#. Delete Order Drafts
|
#. Delete Order Drafts
|
||||||
msgctxt "dialog header"
|
msgctxt "dialog header"
|
||||||
|
@ -2611,8 +2687,8 @@ msgctxt "dialog header"
|
||||||
msgid "Delete Product Type"
|
msgid "Delete Product Type"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/locale/src/productTypes/views/ProductTypeList.json
|
#: build/locale/src/productTypes/views/ProductTypeList/ProductTypeList.json
|
||||||
#. [src.productTypes.views.4080551769] - dialog header
|
#. [src.productTypes.views.ProductTypeList.4080551769] - dialog header
|
||||||
#. defaultMessage is:
|
#. defaultMessage is:
|
||||||
#. Delete Product Types
|
#. Delete Product Types
|
||||||
msgctxt "dialog header"
|
msgctxt "dialog header"
|
||||||
|
@ -2643,8 +2719,8 @@ msgctxt "dialog header"
|
||||||
msgid "Delete Sale"
|
msgid "Delete Sale"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/locale/src/discounts/views/SaleList.json
|
#: build/locale/src/discounts/views/SaleList/SaleList.json
|
||||||
#. [src.discounts.views.2809303671] - dialog header
|
#. [src.discounts.views.SaleList.2809303671] - dialog header
|
||||||
#. defaultMessage is:
|
#. defaultMessage is:
|
||||||
#. Delete Sales
|
#. Delete Sales
|
||||||
msgctxt "dialog header"
|
msgctxt "dialog header"
|
||||||
|
@ -2659,6 +2735,10 @@ msgctxt "custom search delete, dialog header"
|
||||||
msgid "Delete Search"
|
msgid "Delete Search"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: build/locale/src/components/Filter/FilterSearch.json
|
||||||
|
#. [src.components.Filter.2173195312] - button
|
||||||
|
#. defaultMessage is:
|
||||||
|
#. Delete Search
|
||||||
#: build/locale/src/components/TableFilter/FilterChips.json
|
#: build/locale/src/components/TableFilter/FilterChips.json
|
||||||
#. [src.components.TableFilter.2173195312] - button
|
#. [src.components.TableFilter.2173195312] - button
|
||||||
#. defaultMessage is:
|
#. defaultMessage is:
|
||||||
|
@ -2727,8 +2807,8 @@ msgctxt "dialog header"
|
||||||
msgid "Delete Voucher"
|
msgid "Delete Voucher"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/locale/src/discounts/views/VoucherList.json
|
#: build/locale/src/discounts/views/VoucherList/VoucherList.json
|
||||||
#. [src.discounts.views.367317371] - dialog header
|
#. [src.discounts.views.VoucherList.367317371] - dialog header
|
||||||
#. defaultMessage is:
|
#. defaultMessage is:
|
||||||
#. Delete Vouchers
|
#. Delete Vouchers
|
||||||
msgctxt "dialog header"
|
msgctxt "dialog header"
|
||||||
|
@ -2763,8 +2843,8 @@ msgstr ""
|
||||||
#. [src.categories.views.712767046] - dialog title
|
#. [src.categories.views.712767046] - dialog title
|
||||||
#. defaultMessage is:
|
#. defaultMessage is:
|
||||||
#. Delete categories
|
#. Delete categories
|
||||||
#: build/locale/src/categories/views/CategoryList.json
|
#: build/locale/src/categories/views/CategoryList/CategoryList.json
|
||||||
#. [src.categories.views.712767046] - dialog title
|
#. [src.categories.views.CategoryList.712767046] - dialog title
|
||||||
#. defaultMessage is:
|
#. defaultMessage is:
|
||||||
#. Delete categories
|
#. Delete categories
|
||||||
msgctxt "dialog title"
|
msgctxt "dialog title"
|
||||||
|
@ -2783,8 +2863,8 @@ msgctxt "dialog title"
|
||||||
msgid "Delete category"
|
msgid "Delete category"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/locale/src/collections/views/CollectionList.json
|
#: build/locale/src/collections/views/CollectionList/CollectionList.json
|
||||||
#. [src.collections.views.3817188998] - dialog title
|
#. [src.collections.views.CollectionList.3817188998] - dialog title
|
||||||
#. defaultMessage is:
|
#. defaultMessage is:
|
||||||
#. Delete collections
|
#. Delete collections
|
||||||
msgctxt "dialog title"
|
msgctxt "dialog title"
|
||||||
|
@ -2799,8 +2879,8 @@ msgctxt "dialog header"
|
||||||
msgid "Delete customer"
|
msgid "Delete customer"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/locale/src/customers/views/CustomerList.json
|
#: build/locale/src/customers/views/CustomerList/CustomerList.json
|
||||||
#. [src.customers.views.1946482599] - dialog header
|
#. [src.customers.views.CustomerList.1946482599] - dialog header
|
||||||
#. defaultMessage is:
|
#. defaultMessage is:
|
||||||
#. Delete customers
|
#. Delete customers
|
||||||
msgctxt "dialog header"
|
msgctxt "dialog header"
|
||||||
|
@ -3551,18 +3631,6 @@ msgctxt "subheader"
|
||||||
msgid "Here is some information we gathered about your store"
|
msgid "Here is some information we gathered about your store"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/locale/src/attributes/components/ProductListFilter/ProductListFilter.json
|
|
||||||
#. [src.attributes.components.ProductListFilter.77815154] - product is hidden
|
|
||||||
#. defaultMessage is:
|
|
||||||
#. Hidden
|
|
||||||
#: build/locale/src/products/components/ProductListFilter/ProductListFilter.json
|
|
||||||
#. [src.products.components.ProductListFilter.77815154] - product is hidden
|
|
||||||
#. defaultMessage is:
|
|
||||||
#. Hidden
|
|
||||||
msgctxt "product is hidden"
|
|
||||||
msgid "Hidden"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: build/locale/src/components/VisibilityCard/VisibilityCard.json
|
#: build/locale/src/components/VisibilityCard/VisibilityCard.json
|
||||||
#. [src.components.VisibilityCard.77815154]
|
#. [src.components.VisibilityCard.77815154]
|
||||||
#. defaultMessage is:
|
#. defaultMessage is:
|
||||||
|
@ -3571,6 +3639,14 @@ msgctxt "description"
|
||||||
msgid "Hidden"
|
msgid "Hidden"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: build/locale/src/products/components/ProductListFilter/ProductListFilter.json
|
||||||
|
#. [src.products.components.ProductListFilter.77815154] - product is hidden
|
||||||
|
#. defaultMessage is:
|
||||||
|
#. Hidden
|
||||||
|
msgctxt "product is hidden"
|
||||||
|
msgid "Hidden"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: build/locale/src/products/views/ProductList/filters.json
|
#: build/locale/src/products/views/ProductList/filters.json
|
||||||
#. [src.products.views.ProductList.hidden] - filter products by visibility
|
#. [src.products.views.ProductList.hidden] - filter products by visibility
|
||||||
#. defaultMessage is:
|
#. defaultMessage is:
|
||||||
|
@ -4895,8 +4971,8 @@ msgctxt "order history message"
|
||||||
msgid "Order confirmation was sent to customer"
|
msgid "Order confirmation was sent to customer"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/locale/src/orders/views/OrderDraftList.json
|
#: build/locale/src/orders/views/OrderDraftList/OrderDraftList.json
|
||||||
#. [src.orders.views.1872939752]
|
#. [src.orders.views.OrderDraftList.1872939752]
|
||||||
#. defaultMessage is:
|
#. defaultMessage is:
|
||||||
#. Order draft succesfully created
|
#. Order draft succesfully created
|
||||||
#: build/locale/src/orders/views/OrderList/OrderList.json
|
#: build/locale/src/orders/views/OrderList/OrderList.json
|
||||||
|
@ -5035,10 +5111,6 @@ msgctxt "description"
|
||||||
msgid "Original String"
|
msgid "Original String"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/locale/src/attributes/components/ProductListFilter/ProductListFilter.json
|
|
||||||
#. [src.attributes.components.ProductListFilter.1640493122] - product status
|
|
||||||
#. defaultMessage is:
|
|
||||||
#. Out Of Stock
|
|
||||||
#: build/locale/src/products/components/ProductListFilter/ProductListFilter.json
|
#: build/locale/src/products/components/ProductListFilter/ProductListFilter.json
|
||||||
#. [src.products.components.ProductListFilter.1640493122] - product status
|
#. [src.products.components.ProductListFilter.1640493122] - product status
|
||||||
#. defaultMessage is:
|
#. defaultMessage is:
|
||||||
|
@ -5375,18 +5447,6 @@ msgctxt "order payment"
|
||||||
msgid "Preauthorized amount"
|
msgid "Preauthorized amount"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/locale/src/attributes/components/ProductListFilter/ProductListFilter.json
|
|
||||||
#. [src.attributes.components.ProductListFilter.1134347598]
|
|
||||||
#. defaultMessage is:
|
|
||||||
#. Price
|
|
||||||
#: build/locale/src/products/components/ProductListFilter/ProductListFilter.json
|
|
||||||
#. [src.products.components.ProductListFilter.1134347598]
|
|
||||||
#. defaultMessage is:
|
|
||||||
#. Price
|
|
||||||
msgctxt "description"
|
|
||||||
msgid "Price"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: build/locale/src/categories/components/CategoryProductList/CategoryProductList.json
|
#: build/locale/src/categories/components/CategoryProductList/CategoryProductList.json
|
||||||
#. [src.categories.components.CategoryProductList.1134347598] - product price
|
#. [src.categories.components.CategoryProductList.1134347598] - product price
|
||||||
#. defaultMessage is:
|
#. defaultMessage is:
|
||||||
|
@ -5435,6 +5495,14 @@ msgctxt "product unit price"
|
||||||
msgid "Price"
|
msgid "Price"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: build/locale/src/products/components/ProductListFilter/ProductListFilter.json
|
||||||
|
#. [src.products.components.ProductListFilter.1134347598]
|
||||||
|
#. defaultMessage is:
|
||||||
|
#. Price
|
||||||
|
msgctxt "description"
|
||||||
|
msgid "Price"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: build/locale/src/products/components/ProductVariants/ProductVariants.json
|
#: build/locale/src/products/components/ProductVariants/ProductVariants.json
|
||||||
#. [src.products.components.ProductVariants.1134347598] - product variant price
|
#. [src.products.components.ProductVariants.1134347598] - product variant price
|
||||||
#. defaultMessage is:
|
#. defaultMessage is:
|
||||||
|
@ -5747,8 +5815,8 @@ msgctxt "description"
|
||||||
msgid "Provided email address does not exist in our database."
|
msgid "Provided email address does not exist in our database."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/locale/src/collections/views/CollectionList.json
|
#: build/locale/src/collections/views/CollectionList/CollectionList.json
|
||||||
#. [src.collections.views.1547167026] - publish collections
|
#. [src.collections.views.CollectionList.1547167026] - publish collections
|
||||||
#. defaultMessage is:
|
#. defaultMessage is:
|
||||||
#. Publish
|
#. Publish
|
||||||
msgctxt "publish collections"
|
msgctxt "publish collections"
|
||||||
|
@ -5787,8 +5855,8 @@ msgctxt "dialog header"
|
||||||
msgid "Publish Products"
|
msgid "Publish Products"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/locale/src/collections/views/CollectionList.json
|
#: build/locale/src/collections/views/CollectionList/CollectionList.json
|
||||||
#. [src.collections.views.2823425739] - dialog title
|
#. [src.collections.views.CollectionList.2823425739] - dialog title
|
||||||
#. defaultMessage is:
|
#. defaultMessage is:
|
||||||
#. Publish collections
|
#. Publish collections
|
||||||
msgctxt "dialog title"
|
msgctxt "dialog title"
|
||||||
|
@ -5919,10 +5987,6 @@ msgctxt "description"
|
||||||
msgid "Quick Pick"
|
msgid "Quick Pick"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/locale/src/attributes/components/ProductListFilter/ProductListFilter.json
|
|
||||||
#. [src.attributes.components.ProductListFilter.2545228781]
|
|
||||||
#. defaultMessage is:
|
|
||||||
#. Range
|
|
||||||
#: build/locale/src/orders/components/OrderListFilter/OrderListFilter.json
|
#: build/locale/src/orders/components/OrderListFilter/OrderListFilter.json
|
||||||
#. [src.orders.components.OrderListFilter.2545228781]
|
#. [src.orders.components.OrderListFilter.2545228781]
|
||||||
#. defaultMessage is:
|
#. defaultMessage is:
|
||||||
|
@ -6031,8 +6095,8 @@ msgstr ""
|
||||||
#. [src.categories.views.3488150607]
|
#. [src.categories.views.3488150607]
|
||||||
#. defaultMessage is:
|
#. defaultMessage is:
|
||||||
#. Remember this will also delete all products assigned to this category.
|
#. Remember this will also delete all products assigned to this category.
|
||||||
#: build/locale/src/categories/views/CategoryList.json
|
#: build/locale/src/categories/views/CategoryList/CategoryList.json
|
||||||
#. [src.categories.views.3488150607]
|
#. [src.categories.views.CategoryList.3488150607]
|
||||||
#. defaultMessage is:
|
#. defaultMessage is:
|
||||||
#. Remember this will also delete all products assigned to this category.
|
#. Remember this will also delete all products assigned to this category.
|
||||||
msgctxt "description"
|
msgctxt "description"
|
||||||
|
@ -6071,8 +6135,8 @@ msgctxt "unassign country, dialog header"
|
||||||
msgid "Remove from shipping zone"
|
msgid "Remove from shipping zone"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/locale/src/orders/views/OrderDraftList.json
|
#: build/locale/src/orders/views/OrderDraftList/OrderDraftList.json
|
||||||
#. [src.orders.views.3880993240]
|
#. [src.orders.views.OrderDraftList.3880993240]
|
||||||
#. defaultMessage is:
|
#. defaultMessage is:
|
||||||
#. Removed draft orders
|
#. Removed draft orders
|
||||||
msgctxt "description"
|
msgctxt "description"
|
||||||
|
@ -6243,14 +6307,10 @@ msgctxt "button"
|
||||||
msgid "Save"
|
msgid "Save"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/locale/src/components/SaveFilterTabDialog/SaveFilterTabDialog.json
|
#: build/locale/src/components/Filter/FilterSearch.json
|
||||||
#. [src.components.SaveFilterTabDialog.1514415736] - save filter tab, header
|
#. [src.components.Filter.1514415736] - button
|
||||||
#. defaultMessage is:
|
#. defaultMessage is:
|
||||||
#. Save Custom Search
|
#. Save Custom Search
|
||||||
msgctxt "save filter tab, header"
|
|
||||||
msgid "Save Custom Search"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: build/locale/src/components/TableFilter/FilterChips.json
|
#: build/locale/src/components/TableFilter/FilterChips.json
|
||||||
#. [src.components.TableFilter.1514415736] - button
|
#. [src.components.TableFilter.1514415736] - button
|
||||||
#. defaultMessage is:
|
#. defaultMessage is:
|
||||||
|
@ -6259,6 +6319,14 @@ msgctxt "button"
|
||||||
msgid "Save Custom Search"
|
msgid "Save Custom Search"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: build/locale/src/components/SaveFilterTabDialog/SaveFilterTabDialog.json
|
||||||
|
#. [src.components.SaveFilterTabDialog.1514415736] - save filter tab, header
|
||||||
|
#. defaultMessage is:
|
||||||
|
#. Save Custom Search
|
||||||
|
msgctxt "save filter tab, header"
|
||||||
|
msgid "Save Custom Search"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: build/locale/src/products/components/ProductVariantCreatePage/ProductVariantCreatePage.json
|
#: build/locale/src/products/components/ProductVariantCreatePage/ProductVariantCreatePage.json
|
||||||
#. [src.products.components.ProductVariantCreatePage.2853608829] - button
|
#. [src.products.components.ProductVariantCreatePage.2853608829] - button
|
||||||
#. defaultMessage is:
|
#. defaultMessage is:
|
||||||
|
@ -6275,6 +6343,14 @@ msgctxt "description"
|
||||||
msgid "Saved changes"
|
msgid "Saved changes"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: build/locale/src/attributes/components/AttributeListPage/AttributeListPage.json
|
||||||
|
#. [src.attributes.components.AttributeListPage.3916653510]
|
||||||
|
#. defaultMessage is:
|
||||||
|
#. Search Attribute
|
||||||
|
msgctxt "description"
|
||||||
|
msgid "Search Attribute"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: build/locale/src/productTypes/components/AssignAttributeDialog/AssignAttributeDialog.json
|
#: build/locale/src/productTypes/components/AssignAttributeDialog/AssignAttributeDialog.json
|
||||||
#. [src.productTypes.components.AssignAttributeDialog.902296540]
|
#. [src.productTypes.components.AssignAttributeDialog.902296540]
|
||||||
#. defaultMessage is:
|
#. defaultMessage is:
|
||||||
|
@ -6291,10 +6367,30 @@ msgctxt "description"
|
||||||
msgid "Search Categories"
|
msgid "Search Categories"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: build/locale/src/categories/components/CategoryListPage/CategoryListPage.json
|
||||||
|
#. [src.categories.components.CategoryListPage.3841025483]
|
||||||
|
#. defaultMessage is:
|
||||||
|
#. Search Category
|
||||||
|
#: build/locale/src/translations/components/TranslationsEntitiesListPage/TranslationsEntitiesListPage.json
|
||||||
|
#. [src.translations.components.TranslationsEntitiesListPage.3841025483]
|
||||||
|
#. defaultMessage is:
|
||||||
|
#. Search Category
|
||||||
|
msgctxt "description"
|
||||||
|
msgid "Search Category"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: build/locale/src/collections/components/CollectionListPage/CollectionListPage.json
|
||||||
|
#. [src.collections.components.CollectionListPage.4057224233]
|
||||||
|
#. defaultMessage is:
|
||||||
|
#. Search Collection
|
||||||
#: build/locale/src/components/AssignCollectionDialog/AssignCollectionDialog.json
|
#: build/locale/src/components/AssignCollectionDialog/AssignCollectionDialog.json
|
||||||
#. [src.components.AssignCollectionDialog.4057224233]
|
#. [src.components.AssignCollectionDialog.4057224233]
|
||||||
#. defaultMessage is:
|
#. defaultMessage is:
|
||||||
#. Search Collection
|
#. Search Collection
|
||||||
|
#: build/locale/src/translations/components/TranslationsEntitiesListPage/TranslationsEntitiesListPage.json
|
||||||
|
#. [src.translations.components.TranslationsEntitiesListPage.4057224233]
|
||||||
|
#. defaultMessage is:
|
||||||
|
#. Search Collection
|
||||||
msgctxt "description"
|
msgctxt "description"
|
||||||
msgid "Search Collection"
|
msgid "Search Collection"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -6307,6 +6403,14 @@ msgctxt "description"
|
||||||
msgid "Search Countries"
|
msgid "Search Countries"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: build/locale/src/customers/components/CustomerListPage/CustomerListPage.json
|
||||||
|
#. [src.customers.components.CustomerListPage.1643417013]
|
||||||
|
#. defaultMessage is:
|
||||||
|
#. Search Customer
|
||||||
|
msgctxt "description"
|
||||||
|
msgid "Search Customer"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: build/locale/src/orders/components/OrderCustomer/OrderCustomer.json
|
#: build/locale/src/orders/components/OrderCustomer/OrderCustomer.json
|
||||||
#. [src.orders.components.OrderCustomer.2433460203]
|
#. [src.orders.components.OrderCustomer.2433460203]
|
||||||
#. defaultMessage is:
|
#. defaultMessage is:
|
||||||
|
@ -6315,6 +6419,14 @@ msgctxt "description"
|
||||||
msgid "Search Customers"
|
msgid "Search Customers"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: build/locale/src/orders/components/OrderDraftListPage/OrderDraftListPage.json
|
||||||
|
#. [src.orders.components.OrderDraftListPage.77765281]
|
||||||
|
#. defaultMessage is:
|
||||||
|
#. Search Draft
|
||||||
|
msgctxt "description"
|
||||||
|
msgid "Search Draft"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: build/locale/src/translations/components/TranslationsCategoriesPage/TranslationsCategoriesPage.json
|
#: build/locale/src/translations/components/TranslationsCategoriesPage/TranslationsCategoriesPage.json
|
||||||
#. [src.translations.components.TranslationsCategoriesPage.1406947243]
|
#. [src.translations.components.TranslationsCategoriesPage.1406947243]
|
||||||
#. defaultMessage is:
|
#. defaultMessage is:
|
||||||
|
@ -6395,6 +6507,34 @@ msgctxt "description"
|
||||||
msgid "Search Orders..."
|
msgid "Search Orders..."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: build/locale/src/translations/components/TranslationsEntitiesListPage/TranslationsEntitiesListPage.json
|
||||||
|
#. [src.translations.components.TranslationsEntitiesListPage.2559018090]
|
||||||
|
#. defaultMessage is:
|
||||||
|
#. Search Page
|
||||||
|
msgctxt "description"
|
||||||
|
msgid "Search Page"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: build/locale/src/translations/components/TranslationsEntitiesListPage/TranslationsEntitiesListPage.json
|
||||||
|
#. [src.translations.components.TranslationsEntitiesListPage.2105464697]
|
||||||
|
#. defaultMessage is:
|
||||||
|
#. Search Product
|
||||||
|
msgctxt "description"
|
||||||
|
msgid "Search Product"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: build/locale/src/productTypes/components/ProductTypeListPage/ProductTypeListPage.json
|
||||||
|
#. [src.productTypes.components.ProductTypeListPage.3420445375]
|
||||||
|
#. defaultMessage is:
|
||||||
|
#. Search Product Type
|
||||||
|
#: build/locale/src/translations/components/TranslationsEntitiesListPage/TranslationsEntitiesListPage.json
|
||||||
|
#. [src.translations.components.TranslationsEntitiesListPage.3420445375]
|
||||||
|
#. defaultMessage is:
|
||||||
|
#. Search Product Type
|
||||||
|
msgctxt "description"
|
||||||
|
msgid "Search Product Type"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: build/locale/src/components/AssignProductDialog/AssignProductDialog.json
|
#: build/locale/src/components/AssignProductDialog/AssignProductDialog.json
|
||||||
#. [src.components.AssignProductDialog.2850255786]
|
#. [src.components.AssignProductDialog.2850255786]
|
||||||
#. defaultMessage is:
|
#. defaultMessage is:
|
||||||
|
@ -6407,14 +6547,46 @@ msgctxt "description"
|
||||||
msgid "Search Products"
|
msgid "Search Products"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/locale/src/products/components/ProductListPage/ProductListPage.json
|
#: build/locale/src/products/components/ProductListFilter/ProductListFilter.json
|
||||||
#. [src.products.components.ProductListPage.3550330425]
|
#. [src.products.components.ProductListFilter.3550330425]
|
||||||
#. defaultMessage is:
|
#. defaultMessage is:
|
||||||
#. Search Products...
|
#. Search Products...
|
||||||
msgctxt "description"
|
msgctxt "description"
|
||||||
msgid "Search Products..."
|
msgid "Search Products..."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: build/locale/src/discounts/components/SaleListPage/SaleListPage.json
|
||||||
|
#. [src.discounts.components.SaleListPage.1866913828]
|
||||||
|
#. defaultMessage is:
|
||||||
|
#. Search Sale
|
||||||
|
#: build/locale/src/translations/components/TranslationsEntitiesListPage/TranslationsEntitiesListPage.json
|
||||||
|
#. [src.translations.components.TranslationsEntitiesListPage.1866913828]
|
||||||
|
#. defaultMessage is:
|
||||||
|
#. Search Sale
|
||||||
|
msgctxt "description"
|
||||||
|
msgid "Search Sale"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: build/locale/src/staff/components/StaffListPage/StaffListPage.json
|
||||||
|
#. [src.staff.components.StaffListPage.61043583]
|
||||||
|
#. defaultMessage is:
|
||||||
|
#. Search Staff Member
|
||||||
|
msgctxt "description"
|
||||||
|
msgid "Search Staff Member"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: build/locale/src/discounts/components/VoucherListPage/VoucherListPage.json
|
||||||
|
#. [src.discounts.components.VoucherListPage.1930485532]
|
||||||
|
#. defaultMessage is:
|
||||||
|
#. Search Voucher
|
||||||
|
#: build/locale/src/translations/components/TranslationsEntitiesListPage/TranslationsEntitiesListPage.json
|
||||||
|
#. [src.translations.components.TranslationsEntitiesListPage.1930485532]
|
||||||
|
#. defaultMessage is:
|
||||||
|
#. Search Voucher
|
||||||
|
msgctxt "description"
|
||||||
|
msgid "Search Voucher"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: build/locale/src/productTypes/components/AssignAttributeDialog/AssignAttributeDialog.json
|
#: build/locale/src/productTypes/components/AssignAttributeDialog/AssignAttributeDialog.json
|
||||||
#. [src.productTypes.components.AssignAttributeDialog.524117994]
|
#. [src.productTypes.components.AssignAttributeDialog.524117994]
|
||||||
#. defaultMessage is:
|
#. defaultMessage is:
|
||||||
|
@ -6519,8 +6691,8 @@ msgctxt "description"
|
||||||
msgid "Select all orders where:"
|
msgid "Select all orders where:"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/locale/src/products/components/ProductListPage/ProductListPage.json
|
#: build/locale/src/products/components/ProductListFilter/ProductListFilter.json
|
||||||
#. [src.products.components.ProductListPage.1421689426]
|
#. [src.products.components.ProductListFilter.1421689426]
|
||||||
#. defaultMessage is:
|
#. defaultMessage is:
|
||||||
#. Select all products where:
|
#. Select all products where:
|
||||||
msgctxt "description"
|
msgctxt "description"
|
||||||
|
@ -6835,10 +7007,6 @@ msgctxt "description"
|
||||||
msgid "Specific Date"
|
msgid "Specific Date"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/locale/src/attributes/components/ProductListFilter/ProductListFilter.json
|
|
||||||
#. [src.attributes.components.ProductListFilter.2844426531]
|
|
||||||
#. defaultMessage is:
|
|
||||||
#. Specific Price
|
|
||||||
#: build/locale/src/products/components/ProductListFilter/ProductListFilter.json
|
#: build/locale/src/products/components/ProductListFilter/ProductListFilter.json
|
||||||
#. [src.products.components.ProductListFilter.2844426531]
|
#. [src.products.components.ProductListFilter.2844426531]
|
||||||
#. defaultMessage is:
|
#. defaultMessage is:
|
||||||
|
@ -6919,18 +7087,6 @@ msgctxt "voucher is active from date"
|
||||||
msgid "Starts"
|
msgid "Starts"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/locale/src/attributes/components/ProductListFilter/ProductListFilter.json
|
|
||||||
#. [src.attributes.components.ProductListFilter.1756106276] - product status
|
|
||||||
#. defaultMessage is:
|
|
||||||
#. Status
|
|
||||||
#: build/locale/src/products/components/ProductListFilter/ProductListFilter.json
|
|
||||||
#. [src.products.components.ProductListFilter.1756106276] - product status
|
|
||||||
#. defaultMessage is:
|
|
||||||
#. Status
|
|
||||||
msgctxt "product status"
|
|
||||||
msgid "Status"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: build/locale/src/customers/components/CustomerOrders/CustomerOrders.json
|
#: build/locale/src/customers/components/CustomerOrders/CustomerOrders.json
|
||||||
#. [src.customers.components.CustomerOrders.1756106276] - order status
|
#. [src.customers.components.CustomerOrders.1756106276] - order status
|
||||||
#. defaultMessage is:
|
#. defaultMessage is:
|
||||||
|
@ -6955,6 +7111,14 @@ msgctxt "plugin status"
|
||||||
msgid "Status"
|
msgid "Status"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: build/locale/src/products/components/ProductListFilter/ProductListFilter.json
|
||||||
|
#. [src.products.components.ProductListFilter.1756106276] - product status
|
||||||
|
#. defaultMessage is:
|
||||||
|
#. Status
|
||||||
|
msgctxt "product status"
|
||||||
|
msgid "Status"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: build/locale/src/products/components/ProductVariants/ProductVariants.json
|
#: build/locale/src/products/components/ProductVariants/ProductVariants.json
|
||||||
#. [src.products.components.ProductVariants.1756106276] - product variant status
|
#. [src.products.components.ProductVariants.1756106276] - product variant status
|
||||||
#. defaultMessage is:
|
#. defaultMessage is:
|
||||||
|
@ -6963,10 +7127,6 @@ msgctxt "product variant status"
|
||||||
msgid "Status"
|
msgid "Status"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/locale/src/attributes/components/ProductListFilter/ProductListFilter.json
|
|
||||||
#. [src.attributes.components.ProductListFilter.3841616483] - product stock
|
|
||||||
#. defaultMessage is:
|
|
||||||
#. Stock
|
|
||||||
#: build/locale/src/products/components/ProductListFilter/ProductListFilter.json
|
#: build/locale/src/products/components/ProductListFilter/ProductListFilter.json
|
||||||
#. [src.products.components.ProductListFilter.3841616483] - product stock
|
#. [src.products.components.ProductListFilter.3841616483] - product stock
|
||||||
#. defaultMessage is:
|
#. defaultMessage is:
|
||||||
|
@ -6983,10 +7143,6 @@ msgctxt "product variant stock, section header"
|
||||||
msgid "Stock"
|
msgid "Stock"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/locale/src/attributes/components/ProductListFilter/ProductListFilter.json
|
|
||||||
#. [src.attributes.components.ProductListFilter.3645081351]
|
|
||||||
#. defaultMessage is:
|
|
||||||
#. Stock quantity
|
|
||||||
#: build/locale/src/products/components/ProductListFilter/ProductListFilter.json
|
#: build/locale/src/products/components/ProductListFilter/ProductListFilter.json
|
||||||
#. [src.products.components.ProductListFilter.3645081351]
|
#. [src.products.components.ProductListFilter.3645081351]
|
||||||
#. defaultMessage is:
|
#. defaultMessage is:
|
||||||
|
@ -7815,8 +7971,8 @@ msgctxt "payment status"
|
||||||
msgid "Unpaid"
|
msgid "Unpaid"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/locale/src/collections/views/CollectionList.json
|
#: build/locale/src/collections/views/CollectionList/CollectionList.json
|
||||||
#. [src.collections.views.2237014112] - unpublish collections
|
#. [src.collections.views.CollectionList.2237014112] - unpublish collections
|
||||||
#. defaultMessage is:
|
#. defaultMessage is:
|
||||||
#. Unpublish
|
#. Unpublish
|
||||||
msgctxt "unpublish collections"
|
msgctxt "unpublish collections"
|
||||||
|
@ -7855,8 +8011,8 @@ msgctxt "dialog header"
|
||||||
msgid "Unpublish Products"
|
msgid "Unpublish Products"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/locale/src/collections/views/CollectionList.json
|
#: build/locale/src/collections/views/CollectionList/CollectionList.json
|
||||||
#. [src.collections.views.2637364047] - dialog title
|
#. [src.collections.views.CollectionList.2637364047] - dialog title
|
||||||
#. defaultMessage is:
|
#. defaultMessage is:
|
||||||
#. Unpublish collections
|
#. Unpublish collections
|
||||||
msgctxt "dialog title"
|
msgctxt "dialog title"
|
||||||
|
@ -8155,18 +8311,6 @@ msgctxt "description"
|
||||||
msgid "View and update your site settings"
|
msgid "View and update your site settings"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/locale/src/attributes/components/ProductListFilter/ProductListFilter.json
|
|
||||||
#. [src.attributes.components.ProductListFilter.1459686496] - product visibility
|
|
||||||
#. defaultMessage is:
|
|
||||||
#. Visibility
|
|
||||||
#: build/locale/src/products/components/ProductListFilter/ProductListFilter.json
|
|
||||||
#. [src.products.components.ProductListFilter.1459686496] - product visibility
|
|
||||||
#. defaultMessage is:
|
|
||||||
#. Visibility
|
|
||||||
msgctxt "product visibility"
|
|
||||||
msgid "Visibility"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: build/locale/src/components/VisibilityCard/VisibilityCard.json
|
#: build/locale/src/components/VisibilityCard/VisibilityCard.json
|
||||||
#. [src.components.VisibilityCard.1459686496] - section header
|
#. [src.components.VisibilityCard.1459686496] - section header
|
||||||
#. defaultMessage is:
|
#. defaultMessage is:
|
||||||
|
@ -8183,6 +8327,14 @@ msgctxt "page status"
|
||||||
msgid "Visibility"
|
msgid "Visibility"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: build/locale/src/products/components/ProductListFilter/ProductListFilter.json
|
||||||
|
#. [src.products.components.ProductListFilter.1459686496] - product visibility
|
||||||
|
#. defaultMessage is:
|
||||||
|
#. Visibility
|
||||||
|
msgctxt "product visibility"
|
||||||
|
msgid "Visibility"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: build/locale/src/attributes/components/AttributeList/AttributeList.json
|
#: build/locale/src/attributes/components/AttributeList/AttributeList.json
|
||||||
#. [src.attributes.components.AttributeList.643174786] - attribute is visible
|
#. [src.attributes.components.AttributeList.643174786] - attribute is visible
|
||||||
#. defaultMessage is:
|
#. defaultMessage is:
|
||||||
|
@ -8191,18 +8343,6 @@ msgctxt "attribute is visible"
|
||||||
msgid "Visible"
|
msgid "Visible"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/locale/src/attributes/components/ProductListFilter/ProductListFilter.json
|
|
||||||
#. [src.attributes.components.ProductListFilter.643174786] - product is visible
|
|
||||||
#. defaultMessage is:
|
|
||||||
#. Visible
|
|
||||||
#: build/locale/src/products/components/ProductListFilter/ProductListFilter.json
|
|
||||||
#. [src.products.components.ProductListFilter.643174786] - product is visible
|
|
||||||
#. defaultMessage is:
|
|
||||||
#. Visible
|
|
||||||
msgctxt "product is visible"
|
|
||||||
msgid "Visible"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: build/locale/src/components/VisibilityCard/VisibilityCard.json
|
#: build/locale/src/components/VisibilityCard/VisibilityCard.json
|
||||||
#. [src.components.VisibilityCard.643174786]
|
#. [src.components.VisibilityCard.643174786]
|
||||||
#. defaultMessage is:
|
#. defaultMessage is:
|
||||||
|
@ -8211,6 +8351,14 @@ msgctxt "description"
|
||||||
msgid "Visible"
|
msgid "Visible"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: build/locale/src/products/components/ProductListFilter/ProductListFilter.json
|
||||||
|
#. [src.products.components.ProductListFilter.643174786] - product is visible
|
||||||
|
#. defaultMessage is:
|
||||||
|
#. Visible
|
||||||
|
msgctxt "product is visible"
|
||||||
|
msgid "Visible"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: build/locale/src/attributes/components/AttributeProperties/AttributeProperties.json
|
#: build/locale/src/attributes/components/AttributeProperties/AttributeProperties.json
|
||||||
#. [src.attributes.components.AttributeProperties.3876764312] - attribute
|
#. [src.attributes.components.AttributeProperties.3876764312] - attribute
|
||||||
#. defaultMessage is:
|
#. defaultMessage is:
|
||||||
|
@ -8359,18 +8507,6 @@ msgctxt "order does not require shipping"
|
||||||
msgid "does not apply"
|
msgid "does not apply"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/locale/src/attributes/components/ProductListFilter/ProductListFilter.json
|
|
||||||
#. [src.attributes.components.ProductListFilter.3477667254] - product price
|
|
||||||
#. defaultMessage is:
|
|
||||||
#. equals
|
|
||||||
#: build/locale/src/products/components/ProductListFilter/ProductListFilter.json
|
|
||||||
#. [src.products.components.ProductListFilter.3477667254] - product price
|
|
||||||
#. defaultMessage is:
|
|
||||||
#. equals
|
|
||||||
msgctxt "product price"
|
|
||||||
msgid "equals"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: build/locale/src/orders/components/OrderListFilter/OrderListFilter.json
|
#: build/locale/src/orders/components/OrderListFilter/OrderListFilter.json
|
||||||
#. [src.orders.components.OrderListFilter.3477667254]
|
#. [src.orders.components.OrderListFilter.3477667254]
|
||||||
#. defaultMessage is:
|
#. defaultMessage is:
|
||||||
|
@ -8379,6 +8515,14 @@ msgctxt "description"
|
||||||
msgid "equals"
|
msgid "equals"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: build/locale/src/products/components/ProductListFilter/ProductListFilter.json
|
||||||
|
#. [src.products.components.ProductListFilter.3477667254] - product price
|
||||||
|
#. defaultMessage is:
|
||||||
|
#. equals
|
||||||
|
msgctxt "product price"
|
||||||
|
msgid "equals"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: build/locale/src/components/Filter/FilterElement.json
|
#: build/locale/src/components/Filter/FilterElement.json
|
||||||
#. [src.components.Filter.2755325844]
|
#. [src.components.Filter.2755325844]
|
||||||
#. defaultMessage is:
|
#. defaultMessage is:
|
||||||
|
@ -8403,18 +8547,6 @@ msgctxt "weight"
|
||||||
msgid "from {value} {unit}"
|
msgid "from {value} {unit}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/locale/src/attributes/components/ProductListFilter/ProductListFilter.json
|
|
||||||
#. [src.attributes.components.ProductListFilter.1438173764] - product status is set as
|
|
||||||
#. defaultMessage is:
|
|
||||||
#. is set as
|
|
||||||
#: build/locale/src/products/components/ProductListFilter/ProductListFilter.json
|
|
||||||
#. [src.products.components.ProductListFilter.1438173764] - product status is set as
|
|
||||||
#. defaultMessage is:
|
|
||||||
#. is set as
|
|
||||||
msgctxt "product status is set as"
|
|
||||||
msgid "is set as"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: build/locale/src/orders/components/OrderListFilter/OrderListFilter.json
|
#: build/locale/src/orders/components/OrderListFilter/OrderListFilter.json
|
||||||
#. [src.orders.components.OrderListFilter.1438173764] - date is set as
|
#. [src.orders.components.OrderListFilter.1438173764] - date is set as
|
||||||
#. defaultMessage is:
|
#. defaultMessage is:
|
||||||
|
@ -8423,6 +8555,14 @@ msgctxt "date is set as"
|
||||||
msgid "is set as"
|
msgid "is set as"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: build/locale/src/products/components/ProductListFilter/ProductListFilter.json
|
||||||
|
#. [src.products.components.ProductListFilter.1438173764] - product status is set as
|
||||||
|
#. defaultMessage is:
|
||||||
|
#. is set as
|
||||||
|
msgctxt "product status is set as"
|
||||||
|
msgid "is set as"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: build/locale/src/staff/views/StaffDetails.json
|
#: build/locale/src/staff/views/StaffDetails.json
|
||||||
#. [src.staff.views.2240444792] - dialog header
|
#. [src.staff.views.2240444792] - dialog header
|
||||||
#. defaultMessage is:
|
#. defaultMessage is:
|
||||||
|
|
108
schema.graphql
108
schema.graphql
|
@ -466,6 +466,10 @@ type CategoryDelete {
|
||||||
category: Category
|
category: Category
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input CategoryFilterInput {
|
||||||
|
search: String
|
||||||
|
}
|
||||||
|
|
||||||
input CategoryInput {
|
input CategoryInput {
|
||||||
description: String
|
description: String
|
||||||
descriptionJson: JSONString
|
descriptionJson: JSONString
|
||||||
|
@ -1627,6 +1631,10 @@ type MenuDelete {
|
||||||
menu: Menu
|
menu: Menu
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input MenuFilterInput {
|
||||||
|
search: String
|
||||||
|
}
|
||||||
|
|
||||||
input MenuInput {
|
input MenuInput {
|
||||||
name: String
|
name: String
|
||||||
}
|
}
|
||||||
|
@ -1682,6 +1690,10 @@ type MenuItemDelete {
|
||||||
menuItem: MenuItem
|
menuItem: MenuItem
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input MenuItemFilterInput {
|
||||||
|
search: String
|
||||||
|
}
|
||||||
|
|
||||||
input MenuItemInput {
|
input MenuItemInput {
|
||||||
name: String
|
name: String
|
||||||
url: String
|
url: String
|
||||||
|
@ -1980,6 +1992,11 @@ type Mutations {
|
||||||
userBulkSetActive(ids: [ID]!, isActive: Boolean!): UserBulkSetActive
|
userBulkSetActive(ids: [ID]!, isActive: Boolean!): UserBulkSetActive
|
||||||
userUpdatePrivateMetadata(id: ID!, input: MetaInput!): UserUpdatePrivateMeta
|
userUpdatePrivateMetadata(id: ID!, input: MetaInput!): UserUpdatePrivateMeta
|
||||||
userClearStoredPrivateMetadata(id: ID!, input: MetaPath!): UserClearStoredPrivateMeta
|
userClearStoredPrivateMetadata(id: ID!, input: MetaPath!): UserClearStoredPrivateMeta
|
||||||
|
serviceAccountCreate(input: ServiceAccountInput!): ServiceAccountCreate
|
||||||
|
serviceAccountUpdate(id: ID!, input: ServiceAccountInput!): ServiceAccountUpdate
|
||||||
|
serviceAccountDelete(id: ID!): ServiceAccountDelete
|
||||||
|
serviceAccountUpdatePrivateMetadata(id: ID!, input: MetaInput!): ServiceAccountUpdatePrivateMeta
|
||||||
|
serviceAccountClearStoredPrivateMetadata(id: ID!, input: MetaPath!): ServiceAccountClearStoredPrivateMeta
|
||||||
passwordReset(email: String!): PasswordReset
|
passwordReset(email: String!): PasswordReset
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2095,6 +2112,7 @@ enum OrderDirection {
|
||||||
input OrderDraftFilterInput {
|
input OrderDraftFilterInput {
|
||||||
customer: String
|
customer: String
|
||||||
created: DateRangeInput
|
created: DateRangeInput
|
||||||
|
search: String
|
||||||
}
|
}
|
||||||
|
|
||||||
type OrderEvent implements Node {
|
type OrderEvent implements Node {
|
||||||
|
@ -2171,12 +2189,13 @@ input OrderFilterInput {
|
||||||
status: [OrderStatusFilter]
|
status: [OrderStatusFilter]
|
||||||
customer: String
|
customer: String
|
||||||
created: DateRangeInput
|
created: DateRangeInput
|
||||||
|
search: String
|
||||||
}
|
}
|
||||||
|
|
||||||
type OrderLine implements Node {
|
type OrderLine implements Node {
|
||||||
id: ID!
|
id: ID!
|
||||||
productName: String!
|
productName: String!
|
||||||
translatedProductName: String!
|
variantName: String!
|
||||||
productSku: String!
|
productSku: String!
|
||||||
isShippingRequired: Boolean!
|
isShippingRequired: Boolean!
|
||||||
quantity: Int!
|
quantity: Int!
|
||||||
|
@ -2186,6 +2205,8 @@ type OrderLine implements Node {
|
||||||
thumbnail(size: Int): Image
|
thumbnail(size: Int): Image
|
||||||
unitPrice: TaxedMoney
|
unitPrice: TaxedMoney
|
||||||
variant: ProductVariant
|
variant: ProductVariant
|
||||||
|
translatedProductName: String!
|
||||||
|
translatedVariantName: String!
|
||||||
}
|
}
|
||||||
|
|
||||||
input OrderLineCreateInput {
|
input OrderLineCreateInput {
|
||||||
|
@ -2294,6 +2315,10 @@ type PageDelete {
|
||||||
page: Page
|
page: Page
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input PageFilterInput {
|
||||||
|
search: String
|
||||||
|
}
|
||||||
|
|
||||||
type PageInfo {
|
type PageInfo {
|
||||||
hasNextPage: Boolean!
|
hasNextPage: Boolean!
|
||||||
hasPreviousPage: Boolean!
|
hasPreviousPage: Boolean!
|
||||||
|
@ -2430,6 +2455,7 @@ type PermissionDisplay {
|
||||||
enum PermissionEnum {
|
enum PermissionEnum {
|
||||||
MANAGE_USERS
|
MANAGE_USERS
|
||||||
MANAGE_STAFF
|
MANAGE_STAFF
|
||||||
|
MANAGE_SERVICE_ACCOUNTS
|
||||||
IMPERSONATE_USERS
|
IMPERSONATE_USERS
|
||||||
MANAGE_DISCOUNTS
|
MANAGE_DISCOUNTS
|
||||||
MANAGE_GIFT_CARD
|
MANAGE_GIFT_CARD
|
||||||
|
@ -2462,6 +2488,11 @@ type PluginCountableEdge {
|
||||||
cursor: String!
|
cursor: String!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input PluginFilterInput {
|
||||||
|
active: Boolean
|
||||||
|
search: String
|
||||||
|
}
|
||||||
|
|
||||||
type PluginUpdate {
|
type PluginUpdate {
|
||||||
errors: [Error!]
|
errors: [Error!]
|
||||||
plugin: Plugin
|
plugin: Plugin
|
||||||
|
@ -2661,6 +2692,8 @@ enum ProductOrderField {
|
||||||
PRICE
|
PRICE
|
||||||
MINIMAL_PRICE
|
MINIMAL_PRICE
|
||||||
DATE
|
DATE
|
||||||
|
TYPE
|
||||||
|
PUBLISHED
|
||||||
}
|
}
|
||||||
|
|
||||||
type ProductPricingInfo {
|
type ProductPricingInfo {
|
||||||
|
@ -2922,7 +2955,7 @@ type Query {
|
||||||
digitalContents(query: String, level: Int, before: String, after: String, first: Int, last: Int): DigitalContentCountableConnection
|
digitalContents(query: String, level: Int, before: String, after: String, first: Int, last: Int): DigitalContentCountableConnection
|
||||||
attributes(query: String, inCategory: ID, inCollection: ID, filter: AttributeFilterInput, sortBy: AttributeSortingInput, before: String, after: String, first: Int, last: Int): AttributeCountableConnection
|
attributes(query: String, inCategory: ID, inCollection: ID, filter: AttributeFilterInput, sortBy: AttributeSortingInput, before: String, after: String, first: Int, last: Int): AttributeCountableConnection
|
||||||
attribute(id: ID!): Attribute
|
attribute(id: ID!): Attribute
|
||||||
categories(query: String, level: Int, before: String, after: String, first: Int, last: Int): CategoryCountableConnection
|
categories(query: String, filter: CategoryFilterInput, level: Int, before: String, after: String, first: Int, last: Int): CategoryCountableConnection
|
||||||
category(id: ID!): Category
|
category(id: ID!): Category
|
||||||
collection(id: ID!): Collection
|
collection(id: ID!): Collection
|
||||||
collections(filter: CollectionFilterInput, query: String, before: String, after: String, first: Int, last: Int): CollectionCountableConnection
|
collections(filter: CollectionFilterInput, query: String, before: String, after: String, first: Int, last: Int): CollectionCountableConnection
|
||||||
|
@ -2937,7 +2970,7 @@ type Query {
|
||||||
payments(before: String, after: String, first: Int, last: Int): PaymentCountableConnection
|
payments(before: String, after: String, first: Int, last: Int): PaymentCountableConnection
|
||||||
paymentClientToken(gateway: GatewaysEnum): String
|
paymentClientToken(gateway: GatewaysEnum): String
|
||||||
page(id: ID, slug: String): Page
|
page(id: ID, slug: String): Page
|
||||||
pages(query: String, before: String, after: String, first: Int, last: Int): PageCountableConnection
|
pages(query: String, filter: PageFilterInput, before: String, after: String, first: Int, last: Int): PageCountableConnection
|
||||||
homepageEvents(before: String, after: String, first: Int, last: Int): OrderEventCountableConnection
|
homepageEvents(before: String, after: String, first: Int, last: Int): OrderEventCountableConnection
|
||||||
order(id: ID!): Order
|
order(id: ID!): Order
|
||||||
orders(filter: OrderFilterInput, query: String, created: ReportingPeriod, status: OrderStatusFilter, before: String, after: String, first: Int, last: Int): OrderCountableConnection
|
orders(filter: OrderFilterInput, query: String, created: ReportingPeriod, status: OrderStatusFilter, before: String, after: String, first: Int, last: Int): OrderCountableConnection
|
||||||
|
@ -2945,13 +2978,13 @@ type Query {
|
||||||
ordersTotal(period: ReportingPeriod): TaxedMoney
|
ordersTotal(period: ReportingPeriod): TaxedMoney
|
||||||
orderByToken(token: String!): Order
|
orderByToken(token: String!): Order
|
||||||
menu(id: ID, name: String): Menu
|
menu(id: ID, name: String): Menu
|
||||||
menus(query: String, before: String, after: String, first: Int, last: Int): MenuCountableConnection
|
menus(query: String, filter: MenuFilterInput, before: String, after: String, first: Int, last: Int): MenuCountableConnection
|
||||||
menuItem(id: ID!): MenuItem
|
menuItem(id: ID!): MenuItem
|
||||||
menuItems(query: String, before: String, after: String, first: Int, last: Int): MenuItemCountableConnection
|
menuItems(query: String, filter: MenuItemFilterInput, before: String, after: String, first: Int, last: Int): MenuItemCountableConnection
|
||||||
giftCard(id: ID!): GiftCard
|
giftCard(id: ID!): GiftCard
|
||||||
giftCards(before: String, after: String, first: Int, last: Int): GiftCardCountableConnection
|
giftCards(before: String, after: String, first: Int, last: Int): GiftCardCountableConnection
|
||||||
plugin(id: ID!): Plugin
|
plugin(id: ID!): Plugin
|
||||||
plugins(before: String, after: String, first: Int, last: Int): PluginCountableConnection
|
plugins(filter: PluginFilterInput, before: String, after: String, first: Int, last: Int): PluginCountableConnection
|
||||||
sale(id: ID!): Sale
|
sale(id: ID!): Sale
|
||||||
sales(filter: SaleFilterInput, query: String, before: String, after: String, first: Int, last: Int): SaleCountableConnection
|
sales(filter: SaleFilterInput, query: String, before: String, after: String, first: Int, last: Int): SaleCountableConnection
|
||||||
voucher(id: ID!): Voucher
|
voucher(id: ID!): Voucher
|
||||||
|
@ -2965,6 +2998,8 @@ type Query {
|
||||||
customers(filter: CustomerFilterInput, query: String, before: String, after: String, first: Int, last: Int): UserCountableConnection
|
customers(filter: CustomerFilterInput, query: String, before: String, after: String, first: Int, last: Int): UserCountableConnection
|
||||||
me: User
|
me: User
|
||||||
staffUsers(filter: StaffUserInput, query: String, before: String, after: String, first: Int, last: Int): UserCountableConnection
|
staffUsers(filter: StaffUserInput, query: String, before: String, after: String, first: Int, last: Int): UserCountableConnection
|
||||||
|
serviceAccounts(filter: ServiceAccountFilterInput, before: String, after: String, first: Int, last: Int): ServiceAccountCountableConnection
|
||||||
|
serviceAccount(id: ID!): ServiceAccount
|
||||||
user(id: ID!): User
|
user(id: ID!): User
|
||||||
node(id: ID!): Node
|
node(id: ID!): Node
|
||||||
}
|
}
|
||||||
|
@ -3092,6 +3127,65 @@ input SeoInput {
|
||||||
description: String
|
description: String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ServiceAccount implements Node {
|
||||||
|
id: ID!
|
||||||
|
authToken: String
|
||||||
|
created: DateTime
|
||||||
|
isActive: Boolean
|
||||||
|
privateMeta: [MetaStore]!
|
||||||
|
meta: [MetaStore]!
|
||||||
|
permissions: [PermissionDisplay]
|
||||||
|
name: String
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServiceAccountClearStoredPrivateMeta {
|
||||||
|
errors: [Error!]
|
||||||
|
serviceAccount: ServiceAccount
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServiceAccountCountableConnection {
|
||||||
|
pageInfo: PageInfo!
|
||||||
|
edges: [ServiceAccountCountableEdge!]!
|
||||||
|
totalCount: Int
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServiceAccountCountableEdge {
|
||||||
|
node: ServiceAccount!
|
||||||
|
cursor: String!
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServiceAccountCreate {
|
||||||
|
errors: [Error!]
|
||||||
|
authToken: String
|
||||||
|
serviceAccount: ServiceAccount
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServiceAccountDelete {
|
||||||
|
errors: [Error!]
|
||||||
|
serviceAccount: ServiceAccount
|
||||||
|
}
|
||||||
|
|
||||||
|
input ServiceAccountFilterInput {
|
||||||
|
search: String
|
||||||
|
isActive: Boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
input ServiceAccountInput {
|
||||||
|
name: String
|
||||||
|
isActive: Boolean
|
||||||
|
permissions: [PermissionEnum]
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServiceAccountUpdate {
|
||||||
|
errors: [Error!]
|
||||||
|
serviceAccount: ServiceAccount
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServiceAccountUpdatePrivateMeta {
|
||||||
|
errors: [Error!]
|
||||||
|
serviceAccount: ServiceAccount
|
||||||
|
}
|
||||||
|
|
||||||
type SetPassword {
|
type SetPassword {
|
||||||
token: String
|
token: String
|
||||||
errors: [Error]!
|
errors: [Error]!
|
||||||
|
@ -3307,6 +3401,7 @@ input StaffCreateInput {
|
||||||
note: String
|
note: String
|
||||||
permissions: [PermissionEnum]
|
permissions: [PermissionEnum]
|
||||||
sendPasswordEmail: Boolean
|
sendPasswordEmail: Boolean
|
||||||
|
redirectUrl: String
|
||||||
}
|
}
|
||||||
|
|
||||||
type StaffDelete {
|
type StaffDelete {
|
||||||
|
@ -3534,6 +3629,7 @@ input UserCreateInput {
|
||||||
isActive: Boolean
|
isActive: Boolean
|
||||||
note: String
|
note: String
|
||||||
sendPasswordEmail: Boolean
|
sendPasswordEmail: Boolean
|
||||||
|
redirectUrl: String
|
||||||
}
|
}
|
||||||
|
|
||||||
type UserUpdateMeta {
|
type UserUpdateMeta {
|
||||||
|
|
|
@ -4,19 +4,37 @@ import Card from "@material-ui/core/Card";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
|
|
||||||
|
import SearchBar from "@saleor/components/SearchBar";
|
||||||
import { sectionNames } from "@saleor/intl";
|
import { sectionNames } from "@saleor/intl";
|
||||||
import Container from "../../../components/Container";
|
import Container from "../../../components/Container";
|
||||||
import PageHeader from "../../../components/PageHeader";
|
import PageHeader from "../../../components/PageHeader";
|
||||||
import { ListActions, PageListProps } from "../../../types";
|
import {
|
||||||
|
ListActions,
|
||||||
|
PageListProps,
|
||||||
|
SearchPageProps,
|
||||||
|
TabPageProps
|
||||||
|
} from "../../../types";
|
||||||
import { AttributeList_attributes_edges_node } from "../../types/AttributeList";
|
import { AttributeList_attributes_edges_node } from "../../types/AttributeList";
|
||||||
import AttributeList from "../AttributeList/AttributeList";
|
import AttributeList from "../AttributeList/AttributeList";
|
||||||
|
|
||||||
export interface AttributeListPageProps extends PageListProps, ListActions {
|
export interface AttributeListPageProps
|
||||||
|
extends PageListProps,
|
||||||
|
ListActions,
|
||||||
|
SearchPageProps,
|
||||||
|
TabPageProps {
|
||||||
attributes: AttributeList_attributes_edges_node[];
|
attributes: AttributeList_attributes_edges_node[];
|
||||||
}
|
}
|
||||||
|
|
||||||
const AttributeListPage: React.FC<AttributeListPageProps> = ({
|
const AttributeListPage: React.FC<AttributeListPageProps> = ({
|
||||||
onAdd,
|
onAdd,
|
||||||
|
initialSearch,
|
||||||
|
onSearchChange,
|
||||||
|
currentTab,
|
||||||
|
onAll,
|
||||||
|
onTabChange,
|
||||||
|
onTabDelete,
|
||||||
|
onTabSave,
|
||||||
|
tabs,
|
||||||
...listProps
|
...listProps
|
||||||
}) => {
|
}) => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
@ -32,6 +50,23 @@ const AttributeListPage: React.FC<AttributeListPageProps> = ({
|
||||||
</Button>
|
</Button>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
<Card>
|
<Card>
|
||||||
|
<SearchBar
|
||||||
|
allTabLabel={intl.formatMessage({
|
||||||
|
defaultMessage: "All Attributes",
|
||||||
|
description: "tab name"
|
||||||
|
})}
|
||||||
|
currentTab={currentTab}
|
||||||
|
initialSearch={initialSearch}
|
||||||
|
searchPlaceholder={intl.formatMessage({
|
||||||
|
defaultMessage: "Search Attribute"
|
||||||
|
})}
|
||||||
|
tabs={tabs}
|
||||||
|
onAll={onAll}
|
||||||
|
onSearchChange={onSearchChange}
|
||||||
|
onTabChange={onTabChange}
|
||||||
|
onTabDelete={onTabDelete}
|
||||||
|
onTabSave={onTabSave}
|
||||||
|
/>
|
||||||
<AttributeList {...listProps} />
|
<AttributeList {...listProps} />
|
||||||
</Card>
|
</Card>
|
||||||
</Container>
|
</Container>
|
||||||
|
|
|
@ -52,7 +52,7 @@ const attributeList = gql`
|
||||||
${attributeFragment}
|
${attributeFragment}
|
||||||
${pageInfoFragment}
|
${pageInfoFragment}
|
||||||
query AttributeList(
|
query AttributeList(
|
||||||
$query: String
|
$filter: AttributeFilterInput
|
||||||
$inCategory: ID
|
$inCategory: ID
|
||||||
$inCollection: ID
|
$inCollection: ID
|
||||||
$before: String
|
$before: String
|
||||||
|
@ -61,7 +61,7 @@ const attributeList = gql`
|
||||||
$last: Int
|
$last: Int
|
||||||
) {
|
) {
|
||||||
attributes(
|
attributes(
|
||||||
query: $query
|
filter: $filter
|
||||||
inCategory: $inCategory
|
inCategory: $inCategory
|
||||||
inCollection: $inCollection
|
inCollection: $inCollection
|
||||||
before: $before
|
before: $before
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
// This file was automatically generated and should not be edited.
|
// This file was automatically generated and should not be edited.
|
||||||
|
|
||||||
|
import { AttributeFilterInput } from "./../../types/globalTypes";
|
||||||
|
|
||||||
// ====================================================
|
// ====================================================
|
||||||
// GraphQL query operation: AttributeList
|
// GraphQL query operation: AttributeList
|
||||||
// ====================================================
|
// ====================================================
|
||||||
|
@ -40,7 +42,7 @@ export interface AttributeList {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AttributeListVariables {
|
export interface AttributeListVariables {
|
||||||
query?: string | null;
|
filter?: AttributeFilterInput | null;
|
||||||
inCategory?: string | null;
|
inCategory?: string | null;
|
||||||
inCollection?: string | null;
|
inCollection?: string | null;
|
||||||
before?: string | null;
|
before?: string | null;
|
||||||
|
|
|
@ -1,12 +1,26 @@
|
||||||
import { stringify as stringifyQs } from "qs";
|
import { stringify as stringifyQs } from "qs";
|
||||||
import urlJoin from "url-join";
|
import urlJoin from "url-join";
|
||||||
|
|
||||||
import { BulkAction, Dialog, Pagination, SingleAction } from "../types";
|
import {
|
||||||
|
ActiveTab,
|
||||||
|
BulkAction,
|
||||||
|
Dialog,
|
||||||
|
Filters,
|
||||||
|
Pagination,
|
||||||
|
SingleAction,
|
||||||
|
TabActionDialog
|
||||||
|
} from "../types";
|
||||||
|
|
||||||
export const attributeSection = "/attributes/";
|
export const attributeSection = "/attributes/";
|
||||||
|
|
||||||
export type AttributeListUrlDialog = "remove";
|
export enum AttributeListUrlFiltersEnum {
|
||||||
export type AttributeListUrlQueryParams = BulkAction &
|
query = "query"
|
||||||
|
}
|
||||||
|
export type AttributeListUrlFilters = Filters<AttributeListUrlFiltersEnum>;
|
||||||
|
export type AttributeListUrlDialog = "remove" | TabActionDialog;
|
||||||
|
export type AttributeListUrlQueryParams = ActiveTab &
|
||||||
|
AttributeListUrlFilters &
|
||||||
|
BulkAction &
|
||||||
Dialog<AttributeListUrlDialog> &
|
Dialog<AttributeListUrlDialog> &
|
||||||
Pagination;
|
Pagination;
|
||||||
export const attributeListPath = attributeSection;
|
export const attributeListPath = attributeSection;
|
||||||
|
|
|
@ -3,6 +3,18 @@ import DeleteIcon from "@material-ui/icons/Delete";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useIntl } from "react-intl";
|
import { useIntl } from "react-intl";
|
||||||
|
|
||||||
|
import {
|
||||||
|
areFiltersApplied,
|
||||||
|
deleteFilterTab,
|
||||||
|
getActiveFilters,
|
||||||
|
getFilterTabs,
|
||||||
|
getFilterVariables,
|
||||||
|
saveFilterTab
|
||||||
|
} from "@saleor/attributes/views/AttributeList/filters";
|
||||||
|
import DeleteFilterTabDialog from "@saleor/components/DeleteFilterTabDialog";
|
||||||
|
import SaveFilterTabDialog, {
|
||||||
|
SaveFilterTabDialogFormData
|
||||||
|
} from "@saleor/components/SaveFilterTabDialog";
|
||||||
import useNavigator from "@saleor/hooks/useNavigator";
|
import useNavigator from "@saleor/hooks/useNavigator";
|
||||||
import useNotifier from "@saleor/hooks/useNotifier";
|
import useNotifier from "@saleor/hooks/useNotifier";
|
||||||
import usePaginator, {
|
import usePaginator, {
|
||||||
|
@ -20,6 +32,7 @@ import {
|
||||||
attributeAddUrl,
|
attributeAddUrl,
|
||||||
attributeListUrl,
|
attributeListUrl,
|
||||||
AttributeListUrlDialog,
|
AttributeListUrlDialog,
|
||||||
|
AttributeListUrlFilters,
|
||||||
AttributeListUrlQueryParams,
|
AttributeListUrlQueryParams,
|
||||||
attributeUrl
|
attributeUrl
|
||||||
} from "../../urls";
|
} from "../../urls";
|
||||||
|
@ -37,6 +50,15 @@ const AttributeList: React.FC<AttributeListProps> = ({ params }) => {
|
||||||
);
|
);
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
|
const tabs = getFilterTabs();
|
||||||
|
|
||||||
|
const currentTab =
|
||||||
|
params.activeTab === undefined
|
||||||
|
? areFiltersApplied(params)
|
||||||
|
? tabs.length + 1
|
||||||
|
: 0
|
||||||
|
: parseInt(params.activeTab, 0);
|
||||||
|
|
||||||
const closeModal = () =>
|
const closeModal = () =>
|
||||||
navigate(
|
navigate(
|
||||||
attributeListUrl({
|
attributeListUrl({
|
||||||
|
@ -56,8 +78,46 @@ const AttributeList: React.FC<AttributeListProps> = ({ params }) => {
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const changeFilterField = (filter: AttributeListUrlFilters) => {
|
||||||
|
reset();
|
||||||
|
navigate(
|
||||||
|
attributeListUrl({
|
||||||
|
...getActiveFilters(params),
|
||||||
|
...filter,
|
||||||
|
activeTab: undefined
|
||||||
|
})
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleTabChange = (tab: number) => {
|
||||||
|
reset();
|
||||||
|
navigate(
|
||||||
|
attributeListUrl({
|
||||||
|
activeTab: tab.toString(),
|
||||||
|
...getFilterTabs()[tab - 1].data
|
||||||
|
})
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleTabDelete = () => {
|
||||||
|
deleteFilterTab(currentTab);
|
||||||
|
reset();
|
||||||
|
navigate(attributeListUrl());
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleTabSave = (data: SaveFilterTabDialogFormData) => {
|
||||||
|
saveFilterTab(data.name, getActiveFilters(params));
|
||||||
|
handleTabChange(tabs.length + 1);
|
||||||
|
};
|
||||||
|
|
||||||
const paginationState = createPaginationState(PAGINATE_BY, params);
|
const paginationState = createPaginationState(PAGINATE_BY, params);
|
||||||
const queryVariables = React.useMemo(() => paginationState, [params]);
|
const queryVariables = React.useMemo(
|
||||||
|
() => ({
|
||||||
|
...paginationState,
|
||||||
|
filter: getFilterVariables(params)
|
||||||
|
}),
|
||||||
|
[params]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AttributeListQuery variables={queryVariables}>
|
<AttributeListQuery variables={queryVariables}>
|
||||||
|
@ -99,14 +159,22 @@ const AttributeList: React.FC<AttributeListProps> = ({ params }) => {
|
||||||
attributes={maybe(() =>
|
attributes={maybe(() =>
|
||||||
data.attributes.edges.map(edge => edge.node)
|
data.attributes.edges.map(edge => edge.node)
|
||||||
)}
|
)}
|
||||||
|
currentTab={currentTab}
|
||||||
disabled={loading || attributeBulkDeleteOpts.loading}
|
disabled={loading || attributeBulkDeleteOpts.loading}
|
||||||
|
initialSearch={params.query || ""}
|
||||||
isChecked={isSelected}
|
isChecked={isSelected}
|
||||||
onAdd={() => navigate(attributeAddUrl())}
|
onAdd={() => navigate(attributeAddUrl())}
|
||||||
|
onAll={() => navigate(attributeListUrl())}
|
||||||
onNextPage={loadNextPage}
|
onNextPage={loadNextPage}
|
||||||
onPreviousPage={loadPreviousPage}
|
onPreviousPage={loadPreviousPage}
|
||||||
onRowClick={id => () => navigate(attributeUrl(id))}
|
onRowClick={id => () => navigate(attributeUrl(id))}
|
||||||
|
onSearchChange={query => changeFilterField({ query })}
|
||||||
|
onTabChange={handleTabChange}
|
||||||
|
onTabDelete={() => openModal("delete-search")}
|
||||||
|
onTabSave={() => openModal("save-search")}
|
||||||
pageInfo={pageInfo}
|
pageInfo={pageInfo}
|
||||||
selected={listElements.length}
|
selected={listElements.length}
|
||||||
|
tabs={tabs.map(tab => tab.name)}
|
||||||
toggle={toggle}
|
toggle={toggle}
|
||||||
toggleAll={toggleAll}
|
toggleAll={toggleAll}
|
||||||
toolbar={
|
toolbar={
|
||||||
|
@ -130,6 +198,19 @@ const AttributeList: React.FC<AttributeListProps> = ({ params }) => {
|
||||||
onClose={closeModal}
|
onClose={closeModal}
|
||||||
quantity={maybe(() => params.ids.length)}
|
quantity={maybe(() => params.ids.length)}
|
||||||
/>
|
/>
|
||||||
|
<SaveFilterTabDialog
|
||||||
|
open={params.action === "save-search"}
|
||||||
|
confirmButtonState="default"
|
||||||
|
onClose={closeModal}
|
||||||
|
onSubmit={handleTabSave}
|
||||||
|
/>
|
||||||
|
<DeleteFilterTabDialog
|
||||||
|
open={params.action === "delete-search"}
|
||||||
|
confirmButtonState="default"
|
||||||
|
onClose={closeModal}
|
||||||
|
onSubmit={handleTabDelete}
|
||||||
|
tabName={maybe(() => tabs[currentTab - 1].name, "...")}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
|
|
31
src/attributes/views/AttributeList/filters.ts
Normal file
31
src/attributes/views/AttributeList/filters.ts
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
import { AttributeFilterInput } from "@saleor/types/globalTypes";
|
||||||
|
import {
|
||||||
|
createFilterTabUtils,
|
||||||
|
createFilterUtils
|
||||||
|
} from "../../../utils/filters";
|
||||||
|
import {
|
||||||
|
AttributeListUrlFilters,
|
||||||
|
AttributeListUrlFiltersEnum,
|
||||||
|
AttributeListUrlQueryParams
|
||||||
|
} from "../../urls";
|
||||||
|
|
||||||
|
export const PRODUCT_FILTERS_KEY = "productFilters";
|
||||||
|
|
||||||
|
export function getFilterVariables(
|
||||||
|
params: AttributeListUrlFilters
|
||||||
|
): AttributeFilterInput {
|
||||||
|
return {
|
||||||
|
search: params.query
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export const {
|
||||||
|
deleteFilterTab,
|
||||||
|
getFilterTabs,
|
||||||
|
saveFilterTab
|
||||||
|
} = createFilterTabUtils<AttributeListUrlFilters>(PRODUCT_FILTERS_KEY);
|
||||||
|
|
||||||
|
export const { areFiltersApplied, getActiveFilters } = createFilterUtils<
|
||||||
|
AttributeListUrlQueryParams,
|
||||||
|
AttributeListUrlFilters
|
||||||
|
>(AttributeListUrlFiltersEnum);
|
|
@ -1,5 +1,3 @@
|
||||||
import Button from "@material-ui/core/Button";
|
|
||||||
import Card from "@material-ui/core/Card";
|
|
||||||
import {
|
import {
|
||||||
createStyles,
|
createStyles,
|
||||||
Theme,
|
Theme,
|
||||||
|
@ -12,9 +10,9 @@ import TableCell from "@material-ui/core/TableCell";
|
||||||
import TableFooter from "@material-ui/core/TableFooter";
|
import TableFooter from "@material-ui/core/TableFooter";
|
||||||
import TableRow from "@material-ui/core/TableRow";
|
import TableRow from "@material-ui/core/TableRow";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
import { FormattedMessage } from "react-intl";
|
||||||
|
|
||||||
import CardTitle from "@saleor/components/CardTitle";
|
import { CategoryFragment } from "@saleor/categories/types/CategoryFragment";
|
||||||
import Checkbox from "@saleor/components/Checkbox";
|
import Checkbox from "@saleor/components/Checkbox";
|
||||||
import Skeleton from "@saleor/components/Skeleton";
|
import Skeleton from "@saleor/components/Skeleton";
|
||||||
import TableHead from "@saleor/components/TableHead";
|
import TableHead from "@saleor/components/TableHead";
|
||||||
|
@ -49,20 +47,8 @@ const styles = (theme: Theme) =>
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
interface CategoryListProps
|
interface CategoryListProps extends ListProps, ListActions {
|
||||||
extends ListProps,
|
categories?: CategoryFragment[];
|
||||||
ListActions,
|
|
||||||
WithStyles<typeof styles> {
|
|
||||||
categories?: Array<{
|
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
children: {
|
|
||||||
totalCount: number;
|
|
||||||
};
|
|
||||||
products: {
|
|
||||||
totalCount: number;
|
|
||||||
};
|
|
||||||
}>;
|
|
||||||
isRoot: boolean;
|
isRoot: boolean;
|
||||||
onAdd?();
|
onAdd?();
|
||||||
}
|
}
|
||||||
|
@ -75,39 +61,18 @@ const CategoryList = withStyles(styles, { name: "CategoryList" })(
|
||||||
classes,
|
classes,
|
||||||
disabled,
|
disabled,
|
||||||
settings,
|
settings,
|
||||||
isRoot,
|
|
||||||
pageInfo,
|
pageInfo,
|
||||||
isChecked,
|
isChecked,
|
||||||
|
isRoot,
|
||||||
selected,
|
selected,
|
||||||
toggle,
|
toggle,
|
||||||
toggleAll,
|
toggleAll,
|
||||||
toolbar,
|
toolbar,
|
||||||
onAdd,
|
|
||||||
onNextPage,
|
onNextPage,
|
||||||
onPreviousPage,
|
onPreviousPage,
|
||||||
onUpdateListSettings,
|
onUpdateListSettings,
|
||||||
onRowClick
|
onRowClick
|
||||||
}: CategoryListProps) => {
|
}: CategoryListProps & WithStyles<typeof styles>) => (
|
||||||
const intl = useIntl();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Card>
|
|
||||||
{!isRoot && (
|
|
||||||
<CardTitle
|
|
||||||
title={intl.formatMessage({
|
|
||||||
defaultMessage: "All Subcategories",
|
|
||||||
description: "section header"
|
|
||||||
})}
|
|
||||||
toolbar={
|
|
||||||
<Button color="primary" variant="text" onClick={onAdd}>
|
|
||||||
<FormattedMessage
|
|
||||||
defaultMessage="Create subcategory"
|
|
||||||
description="button"
|
|
||||||
/>
|
|
||||||
</Button>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<Table>
|
<Table>
|
||||||
<TableHead
|
<TableHead
|
||||||
colSpan={numberOfColumns}
|
colSpan={numberOfColumns}
|
||||||
|
@ -138,9 +103,7 @@ const CategoryList = withStyles(styles, { name: "CategoryList" })(
|
||||||
<TablePagination
|
<TablePagination
|
||||||
colSpan={numberOfColumns}
|
colSpan={numberOfColumns}
|
||||||
settings={settings}
|
settings={settings}
|
||||||
hasNextPage={
|
hasNextPage={pageInfo && !disabled ? pageInfo.hasNextPage : false}
|
||||||
pageInfo && !disabled ? pageInfo.hasNextPage : false
|
|
||||||
}
|
|
||||||
onNextPage={onNextPage}
|
onNextPage={onNextPage}
|
||||||
onUpdateListSettings={onUpdateListSettings}
|
onUpdateListSettings={onUpdateListSettings}
|
||||||
hasPreviousPage={
|
hasPreviousPage={
|
||||||
|
@ -210,9 +173,7 @@ const CategoryList = withStyles(styles, { name: "CategoryList" })(
|
||||||
)}
|
)}
|
||||||
</TableBody>
|
</TableBody>
|
||||||
</Table>
|
</Table>
|
||||||
</Card>
|
)
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
CategoryList.displayName = "CategoryList";
|
CategoryList.displayName = "CategoryList";
|
||||||
export default CategoryList;
|
export default CategoryList;
|
||||||
|
|
|
@ -1,44 +1,55 @@
|
||||||
import Button from "@material-ui/core/Button";
|
import Button from "@material-ui/core/Button";
|
||||||
|
import Card from "@material-ui/core/Card";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
|
|
||||||
|
import { CategoryFragment } from "@saleor/categories/types/CategoryFragment";
|
||||||
import Container from "@saleor/components/Container";
|
import Container from "@saleor/components/Container";
|
||||||
import PageHeader from "@saleor/components/PageHeader";
|
import PageHeader from "@saleor/components/PageHeader";
|
||||||
|
import SearchBar from "@saleor/components/SearchBar";
|
||||||
import { sectionNames } from "@saleor/intl";
|
import { sectionNames } from "@saleor/intl";
|
||||||
import { ListActions, PageListProps } from "@saleor/types";
|
import {
|
||||||
|
ListActions,
|
||||||
|
PageListProps,
|
||||||
|
SearchPageProps,
|
||||||
|
TabPageProps
|
||||||
|
} from "@saleor/types";
|
||||||
import CategoryList from "../CategoryList";
|
import CategoryList from "../CategoryList";
|
||||||
|
|
||||||
export interface CategoryTableProps extends PageListProps, ListActions {
|
export interface CategoryTableProps
|
||||||
categories: Array<{
|
extends PageListProps,
|
||||||
id: string;
|
ListActions,
|
||||||
name: string;
|
SearchPageProps,
|
||||||
children: {
|
TabPageProps {
|
||||||
totalCount: number;
|
categories: CategoryFragment[];
|
||||||
};
|
|
||||||
products: {
|
|
||||||
totalCount: number;
|
|
||||||
};
|
|
||||||
}>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CategoryListPage: React.StatelessComponent<CategoryTableProps> = ({
|
export const CategoryListPage: React.StatelessComponent<CategoryTableProps> = ({
|
||||||
categories,
|
categories,
|
||||||
|
currentTab,
|
||||||
disabled,
|
disabled,
|
||||||
settings,
|
initialSearch,
|
||||||
onAdd,
|
|
||||||
onNextPage,
|
|
||||||
onPreviousPage,
|
|
||||||
onUpdateListSettings,
|
|
||||||
onRowClick,
|
|
||||||
pageInfo,
|
|
||||||
isChecked,
|
isChecked,
|
||||||
|
pageInfo,
|
||||||
selected,
|
selected,
|
||||||
|
settings,
|
||||||
|
tabs,
|
||||||
toggle,
|
toggle,
|
||||||
toggleAll,
|
toggleAll,
|
||||||
toolbar
|
toolbar,
|
||||||
|
onAdd,
|
||||||
|
onAll,
|
||||||
|
onNextPage,
|
||||||
|
onPreviousPage,
|
||||||
|
onRowClick,
|
||||||
|
onSearchChange,
|
||||||
|
onTabChange,
|
||||||
|
onTabDelete,
|
||||||
|
onTabSave,
|
||||||
|
onUpdateListSettings
|
||||||
}) => {
|
}) => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container>
|
<Container>
|
||||||
<PageHeader title={intl.formatMessage(sectionNames.categories)}>
|
<PageHeader title={intl.formatMessage(sectionNames.categories)}>
|
||||||
|
@ -49,23 +60,42 @@ export const CategoryListPage: React.StatelessComponent<CategoryTableProps> = ({
|
||||||
/>
|
/>
|
||||||
</Button>
|
</Button>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
|
<Card>
|
||||||
|
<SearchBar
|
||||||
|
allTabLabel={intl.formatMessage({
|
||||||
|
defaultMessage: "All Categories",
|
||||||
|
description: "tab name"
|
||||||
|
})}
|
||||||
|
currentTab={currentTab}
|
||||||
|
initialSearch={initialSearch}
|
||||||
|
searchPlaceholder={intl.formatMessage({
|
||||||
|
defaultMessage: "Search Category"
|
||||||
|
})}
|
||||||
|
tabs={tabs}
|
||||||
|
onAll={onAll}
|
||||||
|
onSearchChange={onSearchChange}
|
||||||
|
onTabChange={onTabChange}
|
||||||
|
onTabDelete={onTabDelete}
|
||||||
|
onTabSave={onTabSave}
|
||||||
|
/>
|
||||||
<CategoryList
|
<CategoryList
|
||||||
categories={categories}
|
categories={categories}
|
||||||
onAdd={onAdd}
|
|
||||||
onRowClick={onRowClick}
|
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
settings={settings}
|
|
||||||
isRoot={true}
|
|
||||||
onNextPage={onNextPage}
|
|
||||||
onPreviousPage={onPreviousPage}
|
|
||||||
onUpdateListSettings={onUpdateListSettings}
|
|
||||||
pageInfo={pageInfo}
|
|
||||||
isChecked={isChecked}
|
isChecked={isChecked}
|
||||||
|
isRoot={true}
|
||||||
|
pageInfo={pageInfo}
|
||||||
selected={selected}
|
selected={selected}
|
||||||
|
settings={settings}
|
||||||
toggle={toggle}
|
toggle={toggle}
|
||||||
toggleAll={toggleAll}
|
toggleAll={toggleAll}
|
||||||
toolbar={toolbar}
|
toolbar={toolbar}
|
||||||
|
onAdd={onAdd}
|
||||||
|
onNextPage={onNextPage}
|
||||||
|
onPreviousPage={onPreviousPage}
|
||||||
|
onRowClick={onRowClick}
|
||||||
|
onUpdateListSettings={onUpdateListSettings}
|
||||||
/>
|
/>
|
||||||
|
</Card>
|
||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
|
import Button from "@material-ui/core/Button";
|
||||||
|
import Card from "@material-ui/core/Card";
|
||||||
import { RawDraftContentState } from "draft-js";
|
import { RawDraftContentState } from "draft-js";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
|
|
||||||
import AppHeader from "@saleor/components/AppHeader";
|
import AppHeader from "@saleor/components/AppHeader";
|
||||||
import { CardSpacer } from "@saleor/components/CardSpacer";
|
import { CardSpacer } from "@saleor/components/CardSpacer";
|
||||||
|
import CardTitle from "@saleor/components/CardTitle";
|
||||||
import { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton";
|
import { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton";
|
||||||
import Container from "@saleor/components/Container";
|
import Container from "@saleor/components/Container";
|
||||||
import Form from "@saleor/components/Form";
|
import Form from "@saleor/components/Form";
|
||||||
|
@ -178,21 +181,40 @@ export const CategoryUpdatePage: React.StatelessComponent<
|
||||||
</TabContainer>
|
</TabContainer>
|
||||||
<CardSpacer />
|
<CardSpacer />
|
||||||
{currentTab === CategoryPageTab.categories && (
|
{currentTab === CategoryPageTab.categories && (
|
||||||
|
<Card>
|
||||||
|
<CardTitle
|
||||||
|
title={intl.formatMessage({
|
||||||
|
defaultMessage: "All Subcategories",
|
||||||
|
description: "section header"
|
||||||
|
})}
|
||||||
|
toolbar={
|
||||||
|
<Button
|
||||||
|
color="primary"
|
||||||
|
variant="text"
|
||||||
|
onClick={onAddCategory}
|
||||||
|
>
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage="Create subcategory"
|
||||||
|
description="button"
|
||||||
|
/>
|
||||||
|
</Button>
|
||||||
|
}
|
||||||
|
/>
|
||||||
<CategoryList
|
<CategoryList
|
||||||
disabled={disabled}
|
|
||||||
isRoot={false}
|
|
||||||
categories={subcategories}
|
categories={subcategories}
|
||||||
onAdd={onAddCategory}
|
disabled={disabled}
|
||||||
onRowClick={onCategoryClick}
|
isChecked={isChecked}
|
||||||
onNextPage={onNextPage}
|
isRoot={false}
|
||||||
onPreviousPage={onPreviousPage}
|
|
||||||
pageInfo={pageInfo}
|
pageInfo={pageInfo}
|
||||||
|
selected={selected}
|
||||||
toggle={toggle}
|
toggle={toggle}
|
||||||
toggleAll={toggleAll}
|
toggleAll={toggleAll}
|
||||||
selected={selected}
|
|
||||||
isChecked={isChecked}
|
|
||||||
toolbar={subcategoryListToolbar}
|
toolbar={subcategoryListToolbar}
|
||||||
|
onNextPage={onNextPage}
|
||||||
|
onPreviousPage={onPreviousPage}
|
||||||
|
onRowClick={onCategoryClick}
|
||||||
/>
|
/>
|
||||||
|
</Card>
|
||||||
)}
|
)}
|
||||||
{currentTab === CategoryPageTab.products && (
|
{currentTab === CategoryPageTab.products && (
|
||||||
<CategoryProducts
|
<CategoryProducts
|
||||||
|
|
|
@ -1,64 +1,83 @@
|
||||||
import { content } from "../storybook/stories/components/RichTextEditor";
|
import { content } from "../storybook/stories/components/RichTextEditor";
|
||||||
import { CategoryDetails_category } from "./types/CategoryDetails";
|
import { CategoryDetails_category } from "./types/CategoryDetails";
|
||||||
|
import { CategoryFragment } from "./types/CategoryFragment";
|
||||||
|
|
||||||
export const categories = [
|
export const categories: CategoryFragment[] = [
|
||||||
{
|
{
|
||||||
|
__typename: "Category",
|
||||||
children: {
|
children: {
|
||||||
|
__typename: "CategoryCountableConnection",
|
||||||
totalCount: 2
|
totalCount: 2
|
||||||
},
|
},
|
||||||
id: "123123",
|
id: "123123",
|
||||||
name: "Lorem ipsum dolor",
|
name: "Lorem ipsum dolor",
|
||||||
products: {
|
products: {
|
||||||
|
__typename: "ProductCountableConnection",
|
||||||
totalCount: 4
|
totalCount: 4
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
__typename: "Category",
|
||||||
children: {
|
children: {
|
||||||
|
__typename: "CategoryCountableConnection",
|
||||||
totalCount: 54
|
totalCount: 54
|
||||||
},
|
},
|
||||||
id: "876752",
|
id: "876752",
|
||||||
name: "Mauris vehicula tortor vulputate",
|
name: "Mauris vehicula tortor vulputate",
|
||||||
products: {
|
products: {
|
||||||
|
__typename: "ProductCountableConnection",
|
||||||
totalCount: 3
|
totalCount: 3
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
__typename: "Category",
|
||||||
children: {
|
children: {
|
||||||
|
__typename: "CategoryCountableConnection",
|
||||||
totalCount: 2
|
totalCount: 2
|
||||||
},
|
},
|
||||||
id: "876542",
|
id: "876542",
|
||||||
name: "Excepteur sint occaecat cupidatat non proident",
|
name: "Excepteur sint occaecat cupidatat non proident",
|
||||||
products: {
|
products: {
|
||||||
|
__typename: "ProductCountableConnection",
|
||||||
totalCount: 6
|
totalCount: 6
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
__typename: "Category",
|
||||||
children: {
|
children: {
|
||||||
|
__typename: "CategoryCountableConnection",
|
||||||
totalCount: 6
|
totalCount: 6
|
||||||
},
|
},
|
||||||
id: "875352",
|
id: "875352",
|
||||||
name: "Ut enim ad minim veniam",
|
name: "Ut enim ad minim veniam",
|
||||||
products: {
|
products: {
|
||||||
|
__typename: "ProductCountableConnection",
|
||||||
totalCount: 12
|
totalCount: 12
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
__typename: "Category",
|
||||||
children: {
|
children: {
|
||||||
|
__typename: "CategoryCountableConnection",
|
||||||
totalCount: 76
|
totalCount: 76
|
||||||
},
|
},
|
||||||
id: "865752",
|
id: "865752",
|
||||||
name: "Duis aute irure dolor in reprehenderit",
|
name: "Duis aute irure dolor in reprehenderit",
|
||||||
products: {
|
products: {
|
||||||
|
__typename: "ProductCountableConnection",
|
||||||
totalCount: 43
|
totalCount: 43
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
__typename: "Category",
|
||||||
children: {
|
children: {
|
||||||
|
__typename: "CategoryCountableConnection",
|
||||||
totalCount: 11
|
totalCount: 11
|
||||||
},
|
},
|
||||||
id: "878752",
|
id: "878752",
|
||||||
name: "Neque porro quisquam est",
|
name: "Neque porro quisquam est",
|
||||||
products: {
|
products: {
|
||||||
|
__typename: "ProductCountableConnection",
|
||||||
totalCount: 21
|
totalCount: 21
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,18 @@ import {
|
||||||
} from "./types/CategoryDetails";
|
} from "./types/CategoryDetails";
|
||||||
import { RootCategories } from "./types/RootCategories";
|
import { RootCategories } from "./types/RootCategories";
|
||||||
|
|
||||||
|
export const categoryFragment = gql`
|
||||||
|
fragment CategoryFragment on Category {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
children {
|
||||||
|
totalCount
|
||||||
|
}
|
||||||
|
products {
|
||||||
|
totalCount
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
export const categoryDetailsFragment = gql`
|
export const categoryDetailsFragment = gql`
|
||||||
fragment CategoryDetailsFragment on Category {
|
fragment CategoryDetailsFragment on Category {
|
||||||
id
|
id
|
||||||
|
@ -25,11 +37,13 @@ export const categoryDetailsFragment = gql`
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const rootCategories = gql`
|
export const rootCategories = gql`
|
||||||
|
${categoryFragment}
|
||||||
query RootCategories(
|
query RootCategories(
|
||||||
$first: Int
|
$first: Int
|
||||||
$after: String
|
$after: String
|
||||||
$last: Int
|
$last: Int
|
||||||
$before: String
|
$before: String
|
||||||
|
$filter: CategoryFilterInput
|
||||||
) {
|
) {
|
||||||
categories(
|
categories(
|
||||||
level: 0
|
level: 0
|
||||||
|
@ -37,17 +51,11 @@ export const rootCategories = gql`
|
||||||
after: $after
|
after: $after
|
||||||
last: $last
|
last: $last
|
||||||
before: $before
|
before: $before
|
||||||
|
filter: $filter
|
||||||
) {
|
) {
|
||||||
edges {
|
edges {
|
||||||
node {
|
node {
|
||||||
id
|
...CategoryFragment
|
||||||
name
|
|
||||||
children {
|
|
||||||
totalCount
|
|
||||||
}
|
|
||||||
products {
|
|
||||||
totalCount
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pageInfo {
|
pageInfo {
|
||||||
|
@ -64,6 +72,7 @@ export const TypedRootCategoriesQuery = TypedQuery<RootCategories, {}>(
|
||||||
);
|
);
|
||||||
|
|
||||||
export const categoryDetails = gql`
|
export const categoryDetails = gql`
|
||||||
|
${categoryFragment}
|
||||||
${categoryDetailsFragment}
|
${categoryDetailsFragment}
|
||||||
query CategoryDetails(
|
query CategoryDetails(
|
||||||
$id: ID!
|
$id: ID!
|
||||||
|
@ -77,14 +86,7 @@ export const categoryDetails = gql`
|
||||||
children(first: 20) {
|
children(first: 20) {
|
||||||
edges {
|
edges {
|
||||||
node {
|
node {
|
||||||
id
|
...CategoryFragment
|
||||||
name
|
|
||||||
children {
|
|
||||||
totalCount
|
|
||||||
}
|
|
||||||
products {
|
|
||||||
totalCount
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
25
src/categories/types/CategoryFragment.ts
Normal file
25
src/categories/types/CategoryFragment.ts
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
// This file was automatically generated and should not be edited.
|
||||||
|
|
||||||
|
// ====================================================
|
||||||
|
// GraphQL fragment: CategoryFragment
|
||||||
|
// ====================================================
|
||||||
|
|
||||||
|
export interface CategoryFragment_children {
|
||||||
|
__typename: "CategoryCountableConnection";
|
||||||
|
totalCount: number | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CategoryFragment_products {
|
||||||
|
__typename: "ProductCountableConnection";
|
||||||
|
totalCount: number | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CategoryFragment {
|
||||||
|
__typename: "Category";
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
children: CategoryFragment_children | null;
|
||||||
|
products: CategoryFragment_products | null;
|
||||||
|
}
|
|
@ -2,6 +2,8 @@
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
// This file was automatically generated and should not be edited.
|
// This file was automatically generated and should not be edited.
|
||||||
|
|
||||||
|
import { CategoryFilterInput } from "./../../types/globalTypes";
|
||||||
|
|
||||||
// ====================================================
|
// ====================================================
|
||||||
// GraphQL query operation: RootCategories
|
// GraphQL query operation: RootCategories
|
||||||
// ====================================================
|
// ====================================================
|
||||||
|
@ -52,4 +54,5 @@ export interface RootCategoriesVariables {
|
||||||
after?: string | null;
|
after?: string | null;
|
||||||
last?: number | null;
|
last?: number | null;
|
||||||
before?: string | null;
|
before?: string | null;
|
||||||
|
filter?: CategoryFilterInput | null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,27 @@
|
||||||
import { stringify as stringifyQs } from "qs";
|
import { stringify as stringifyQs } from "qs";
|
||||||
import urlJoin from "url-join";
|
import urlJoin from "url-join";
|
||||||
|
|
||||||
import { ActiveTab, BulkAction, Dialog, Pagination } from "../types";
|
import {
|
||||||
|
ActiveTab,
|
||||||
|
BulkAction,
|
||||||
|
Dialog,
|
||||||
|
Filters,
|
||||||
|
Pagination,
|
||||||
|
TabActionDialog
|
||||||
|
} from "../types";
|
||||||
import { CategoryPageTab } from "./components/CategoryUpdatePage";
|
import { CategoryPageTab } from "./components/CategoryUpdatePage";
|
||||||
|
|
||||||
const categorySectionUrl = "/categories/";
|
const categorySectionUrl = "/categories/";
|
||||||
|
|
||||||
export const categoryListPath = categorySectionUrl;
|
export const categoryListPath = categorySectionUrl;
|
||||||
export type CategoryListUrlDialog = "delete";
|
export enum CategoryListUrlFiltersEnum {
|
||||||
export type CategoryListUrlQueryParams = BulkAction &
|
query = "query"
|
||||||
|
}
|
||||||
|
export type CategoryListUrlFilters = Filters<CategoryListUrlFiltersEnum>;
|
||||||
|
export type CategoryListUrlDialog = "delete" | TabActionDialog;
|
||||||
|
export type CategoryListUrlQueryParams = ActiveTab &
|
||||||
|
BulkAction &
|
||||||
|
CategoryListUrlFilters &
|
||||||
Dialog<CategoryListUrlDialog> &
|
Dialog<CategoryListUrlDialog> &
|
||||||
Pagination;
|
Pagination;
|
||||||
export const categoryListUrl = (params?: CategoryListUrlQueryParams) =>
|
export const categoryListUrl = (params?: CategoryListUrlQueryParams) =>
|
||||||
|
|
|
@ -5,6 +5,10 @@ import React from "react";
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
|
|
||||||
import ActionDialog from "@saleor/components/ActionDialog";
|
import ActionDialog from "@saleor/components/ActionDialog";
|
||||||
|
import DeleteFilterTabDialog from "@saleor/components/DeleteFilterTabDialog";
|
||||||
|
import SaveFilterTabDialog, {
|
||||||
|
SaveFilterTabDialogFormData
|
||||||
|
} from "@saleor/components/SaveFilterTabDialog";
|
||||||
import useBulkActions from "@saleor/hooks/useBulkActions";
|
import useBulkActions from "@saleor/hooks/useBulkActions";
|
||||||
import useListSettings from "@saleor/hooks/useListSettings";
|
import useListSettings from "@saleor/hooks/useListSettings";
|
||||||
import useNavigator from "@saleor/hooks/useNavigator";
|
import useNavigator from "@saleor/hooks/useNavigator";
|
||||||
|
@ -13,16 +17,26 @@ import usePaginator, {
|
||||||
} from "@saleor/hooks/usePaginator";
|
} from "@saleor/hooks/usePaginator";
|
||||||
import { getMutationState, maybe } from "@saleor/misc";
|
import { getMutationState, maybe } from "@saleor/misc";
|
||||||
import { ListViews } from "@saleor/types";
|
import { ListViews } from "@saleor/types";
|
||||||
import { CategoryListPage } from "../components/CategoryListPage/CategoryListPage";
|
import { CategoryListPage } from "../../components/CategoryListPage/CategoryListPage";
|
||||||
import { TypedCategoryBulkDeleteMutation } from "../mutations";
|
import { TypedCategoryBulkDeleteMutation } from "../../mutations";
|
||||||
import { TypedRootCategoriesQuery } from "../queries";
|
import { TypedRootCategoriesQuery } from "../../queries";
|
||||||
import { CategoryBulkDelete } from "../types/CategoryBulkDelete";
|
import { CategoryBulkDelete } from "../../types/CategoryBulkDelete";
|
||||||
import {
|
import {
|
||||||
categoryAddUrl,
|
categoryAddUrl,
|
||||||
categoryListUrl,
|
categoryListUrl,
|
||||||
|
CategoryListUrlDialog,
|
||||||
|
CategoryListUrlFilters,
|
||||||
CategoryListUrlQueryParams,
|
CategoryListUrlQueryParams,
|
||||||
categoryUrl
|
categoryUrl
|
||||||
} from "../urls";
|
} from "../../urls";
|
||||||
|
import {
|
||||||
|
areFiltersApplied,
|
||||||
|
deleteFilterTab,
|
||||||
|
getActiveFilters,
|
||||||
|
getFilterTabs,
|
||||||
|
getFilterVariables,
|
||||||
|
saveFilterTab
|
||||||
|
} from "./filter";
|
||||||
|
|
||||||
interface CategoryListProps {
|
interface CategoryListProps {
|
||||||
params: CategoryListUrlQueryParams;
|
params: CategoryListUrlQueryParams;
|
||||||
|
@ -41,9 +55,77 @@ export const CategoryList: React.StatelessComponent<CategoryListProps> = ({
|
||||||
);
|
);
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
|
const tabs = getFilterTabs();
|
||||||
|
|
||||||
|
const currentTab =
|
||||||
|
params.activeTab === undefined
|
||||||
|
? areFiltersApplied(params)
|
||||||
|
? tabs.length + 1
|
||||||
|
: 0
|
||||||
|
: parseInt(params.activeTab, 0);
|
||||||
|
|
||||||
|
const changeFilterField = (filter: CategoryListUrlFilters) => {
|
||||||
|
reset();
|
||||||
|
navigate(
|
||||||
|
categoryListUrl({
|
||||||
|
...getActiveFilters(params),
|
||||||
|
...filter,
|
||||||
|
activeTab: undefined
|
||||||
|
})
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const closeModal = () =>
|
||||||
|
navigate(
|
||||||
|
categoryListUrl({
|
||||||
|
...params,
|
||||||
|
action: undefined,
|
||||||
|
ids: undefined
|
||||||
|
}),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
const openModal = (action: CategoryListUrlDialog, ids?: string[]) =>
|
||||||
|
navigate(
|
||||||
|
categoryListUrl({
|
||||||
|
...params,
|
||||||
|
action,
|
||||||
|
ids
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleTabChange = (tab: number) => {
|
||||||
|
reset();
|
||||||
|
navigate(
|
||||||
|
categoryListUrl({
|
||||||
|
activeTab: tab.toString(),
|
||||||
|
...getFilterTabs()[tab - 1].data
|
||||||
|
})
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleTabDelete = () => {
|
||||||
|
deleteFilterTab(currentTab);
|
||||||
|
reset();
|
||||||
|
navigate(categoryListUrl());
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleTabSave = (data: SaveFilterTabDialogFormData) => {
|
||||||
|
saveFilterTab(data.name, getActiveFilters(params));
|
||||||
|
handleTabChange(tabs.length + 1);
|
||||||
|
};
|
||||||
|
|
||||||
const paginationState = createPaginationState(settings.rowNumber, params);
|
const paginationState = createPaginationState(settings.rowNumber, params);
|
||||||
|
const queryVariables = React.useMemo(
|
||||||
|
() => ({
|
||||||
|
...paginationState,
|
||||||
|
filter: getFilterVariables(params)
|
||||||
|
}),
|
||||||
|
[params]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TypedRootCategoriesQuery displayLoader variables={paginationState}>
|
<TypedRootCategoriesQuery displayLoader variables={queryVariables}>
|
||||||
{({ data, loading, refetch }) => {
|
{({ data, loading, refetch }) => {
|
||||||
const { loadNextPage, loadPreviousPage, pageInfo } = paginate(
|
const { loadNextPage, loadPreviousPage, pageInfo } = paginate(
|
||||||
maybe(() => data.categories.pageInfo),
|
maybe(() => data.categories.pageInfo),
|
||||||
|
@ -78,6 +160,14 @@ export const CategoryList: React.StatelessComponent<CategoryListProps> = ({
|
||||||
() => data.categories.edges.map(edge => edge.node),
|
() => data.categories.edges.map(edge => edge.node),
|
||||||
[]
|
[]
|
||||||
)}
|
)}
|
||||||
|
currentTab={currentTab}
|
||||||
|
initialSearch={params.query || ""}
|
||||||
|
onSearchChange={query => changeFilterField({ query })}
|
||||||
|
onAll={() => navigate(categoryListUrl())}
|
||||||
|
onTabChange={handleTabChange}
|
||||||
|
onTabDelete={() => openModal("delete-search")}
|
||||||
|
onTabSave={() => openModal("save-search")}
|
||||||
|
tabs={tabs.map(tab => tab.name)}
|
||||||
settings={settings}
|
settings={settings}
|
||||||
onAdd={() => navigate(categoryAddUrl())}
|
onAdd={() => navigate(categoryAddUrl())}
|
||||||
onRowClick={id => () => navigate(categoryUrl(id))}
|
onRowClick={id => () => navigate(categoryUrl(id))}
|
||||||
|
@ -134,7 +224,7 @@ export const CategoryList: React.StatelessComponent<CategoryListProps> = ({
|
||||||
>
|
>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
defaultMessage="Are you sure you want to delete {counter, plural,
|
defaultMessage="Are you sure you want to delete {counter, plural,
|
||||||
one {this attribute}
|
one {this category}
|
||||||
other {{displayQuantity} categories}
|
other {{displayQuantity} categories}
|
||||||
}?"
|
}?"
|
||||||
values={{
|
values={{
|
||||||
|
@ -148,6 +238,19 @@ export const CategoryList: React.StatelessComponent<CategoryListProps> = ({
|
||||||
<FormattedMessage defaultMessage="Remember this will also delete all products assigned to this category." />
|
<FormattedMessage defaultMessage="Remember this will also delete all products assigned to this category." />
|
||||||
</DialogContentText>
|
</DialogContentText>
|
||||||
</ActionDialog>
|
</ActionDialog>
|
||||||
|
<SaveFilterTabDialog
|
||||||
|
open={params.action === "save-search"}
|
||||||
|
confirmButtonState="default"
|
||||||
|
onClose={closeModal}
|
||||||
|
onSubmit={handleTabSave}
|
||||||
|
/>
|
||||||
|
<DeleteFilterTabDialog
|
||||||
|
open={params.action === "delete-search"}
|
||||||
|
confirmButtonState="default"
|
||||||
|
onClose={closeModal}
|
||||||
|
onSubmit={handleTabDelete}
|
||||||
|
tabName={maybe(() => tabs[currentTab - 1].name, "...")}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
31
src/categories/views/CategoryList/filter.ts
Normal file
31
src/categories/views/CategoryList/filter.ts
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
import { CategoryFilterInput } from "@saleor/types/globalTypes";
|
||||||
|
import {
|
||||||
|
createFilterTabUtils,
|
||||||
|
createFilterUtils
|
||||||
|
} from "../../../utils/filters";
|
||||||
|
import {
|
||||||
|
CategoryListUrlFilters,
|
||||||
|
CategoryListUrlFiltersEnum,
|
||||||
|
CategoryListUrlQueryParams
|
||||||
|
} from "../../urls";
|
||||||
|
|
||||||
|
export const CATEGORY_FILTERS_KEY = "categoryFilters";
|
||||||
|
|
||||||
|
export function getFilterVariables(
|
||||||
|
params: CategoryListUrlFilters
|
||||||
|
): CategoryFilterInput {
|
||||||
|
return {
|
||||||
|
search: params.query
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export const {
|
||||||
|
deleteFilterTab,
|
||||||
|
getFilterTabs,
|
||||||
|
saveFilterTab
|
||||||
|
} = createFilterTabUtils<CategoryListUrlFilters>(CATEGORY_FILTERS_KEY);
|
||||||
|
|
||||||
|
export const { areFiltersApplied, getActiveFilters } = createFilterUtils<
|
||||||
|
CategoryListUrlQueryParams,
|
||||||
|
CategoryListUrlFilters
|
||||||
|
>(CategoryListUrlFiltersEnum);
|
2
src/categories/views/CategoryList/index.ts
Normal file
2
src/categories/views/CategoryList/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
export { default } from "./CategoryList";
|
||||||
|
export * from "./CategoryList";
|
|
@ -1,4 +1,3 @@
|
||||||
import Card from "@material-ui/core/Card";
|
|
||||||
import {
|
import {
|
||||||
createStyles,
|
createStyles,
|
||||||
Theme,
|
Theme,
|
||||||
|
@ -74,7 +73,6 @@ const CollectionList = withStyles(styles, { name: "CollectionList" })(
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card>
|
|
||||||
<Table>
|
<Table>
|
||||||
<TableHead
|
<TableHead
|
||||||
colSpan={numberOfColumns}
|
colSpan={numberOfColumns}
|
||||||
|
@ -102,9 +100,7 @@ const CollectionList = withStyles(styles, { name: "CollectionList" })(
|
||||||
<TablePagination
|
<TablePagination
|
||||||
colSpan={numberOfColumns}
|
colSpan={numberOfColumns}
|
||||||
settings={settings}
|
settings={settings}
|
||||||
hasNextPage={
|
hasNextPage={pageInfo && !disabled ? pageInfo.hasNextPage : false}
|
||||||
pageInfo && !disabled ? pageInfo.hasNextPage : false
|
|
||||||
}
|
|
||||||
onNextPage={onNextPage}
|
onNextPage={onNextPage}
|
||||||
onUpdateListSettings={onUpdateListSettings}
|
onUpdateListSettings={onUpdateListSettings}
|
||||||
hasPreviousPage={
|
hasPreviousPage={
|
||||||
|
@ -118,9 +114,7 @@ const CollectionList = withStyles(styles, { name: "CollectionList" })(
|
||||||
{renderCollection(
|
{renderCollection(
|
||||||
collections,
|
collections,
|
||||||
collection => {
|
collection => {
|
||||||
const isSelected = collection
|
const isSelected = collection ? isChecked(collection.id) : false;
|
||||||
? isChecked(collection.id)
|
|
||||||
: false;
|
|
||||||
return (
|
return (
|
||||||
<TableRow
|
<TableRow
|
||||||
className={classes.tableRow}
|
className={classes.tableRow}
|
||||||
|
@ -153,9 +147,7 @@ const CollectionList = withStyles(styles, { name: "CollectionList" })(
|
||||||
{maybe(
|
{maybe(
|
||||||
() => (
|
() => (
|
||||||
<StatusLabel
|
<StatusLabel
|
||||||
status={
|
status={collection.isPublished ? "success" : "error"}
|
||||||
collection.isPublished ? "success" : "error"
|
|
||||||
}
|
|
||||||
label={
|
label={
|
||||||
collection.isPublished
|
collection.isPublished
|
||||||
? intl.formatMessage({
|
? intl.formatMessage({
|
||||||
|
@ -185,7 +177,6 @@ const CollectionList = withStyles(styles, { name: "CollectionList" })(
|
||||||
)}
|
)}
|
||||||
</TableBody>
|
</TableBody>
|
||||||
</Table>
|
</Table>
|
||||||
</Card>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,22 +1,40 @@
|
||||||
import Button from "@material-ui/core/Button";
|
import Button from "@material-ui/core/Button";
|
||||||
|
import Card from "@material-ui/core/Card";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
|
|
||||||
import { Container } from "@saleor/components/Container";
|
import { Container } from "@saleor/components/Container";
|
||||||
import PageHeader from "@saleor/components/PageHeader";
|
import PageHeader from "@saleor/components/PageHeader";
|
||||||
|
import SearchBar from "@saleor/components/SearchBar";
|
||||||
import { sectionNames } from "@saleor/intl";
|
import { sectionNames } from "@saleor/intl";
|
||||||
import { ListActions, PageListProps } from "@saleor/types";
|
import {
|
||||||
|
ListActions,
|
||||||
|
PageListProps,
|
||||||
|
SearchPageProps,
|
||||||
|
TabPageProps
|
||||||
|
} from "@saleor/types";
|
||||||
import { CollectionList_collections_edges_node } from "../../types/CollectionList";
|
import { CollectionList_collections_edges_node } from "../../types/CollectionList";
|
||||||
import CollectionList from "../CollectionList/CollectionList";
|
import CollectionList from "../CollectionList/CollectionList";
|
||||||
|
|
||||||
export interface CollectionListPageProps extends PageListProps, ListActions {
|
export interface CollectionListPageProps
|
||||||
|
extends PageListProps,
|
||||||
|
ListActions,
|
||||||
|
SearchPageProps,
|
||||||
|
TabPageProps {
|
||||||
collections: CollectionList_collections_edges_node[];
|
collections: CollectionList_collections_edges_node[];
|
||||||
}
|
}
|
||||||
|
|
||||||
const CollectionListPage: React.StatelessComponent<CollectionListPageProps> = ({
|
const CollectionListPage: React.StatelessComponent<CollectionListPageProps> = ({
|
||||||
|
currentTab,
|
||||||
disabled,
|
disabled,
|
||||||
|
initialSearch,
|
||||||
onAdd,
|
onAdd,
|
||||||
|
onAll,
|
||||||
|
onSearchChange,
|
||||||
|
onTabChange,
|
||||||
|
onTabDelete,
|
||||||
|
onTabSave,
|
||||||
|
tabs,
|
||||||
...listProps
|
...listProps
|
||||||
}) => {
|
}) => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
@ -36,7 +54,26 @@ const CollectionListPage: React.StatelessComponent<CollectionListPageProps> = ({
|
||||||
/>
|
/>
|
||||||
</Button>
|
</Button>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
|
<Card>
|
||||||
|
<SearchBar
|
||||||
|
allTabLabel={intl.formatMessage({
|
||||||
|
defaultMessage: "All Collections",
|
||||||
|
description: "tab name"
|
||||||
|
})}
|
||||||
|
currentTab={currentTab}
|
||||||
|
initialSearch={initialSearch}
|
||||||
|
searchPlaceholder={intl.formatMessage({
|
||||||
|
defaultMessage: "Search Collection"
|
||||||
|
})}
|
||||||
|
tabs={tabs}
|
||||||
|
onAll={onAll}
|
||||||
|
onSearchChange={onSearchChange}
|
||||||
|
onTabChange={onTabChange}
|
||||||
|
onTabDelete={onTabDelete}
|
||||||
|
onTabSave={onTabSave}
|
||||||
|
/>
|
||||||
<CollectionList disabled={disabled} {...listProps} />
|
<CollectionList disabled={disabled} {...listProps} />
|
||||||
|
</Card>
|
||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -60,8 +60,15 @@ export const collectionList = gql`
|
||||||
$after: String
|
$after: String
|
||||||
$last: Int
|
$last: Int
|
||||||
$before: String
|
$before: String
|
||||||
|
$filter: CollectionFilterInput
|
||||||
|
) {
|
||||||
|
collections(
|
||||||
|
first: $first
|
||||||
|
after: $after
|
||||||
|
before: $before
|
||||||
|
last: $last
|
||||||
|
filter: $filter
|
||||||
) {
|
) {
|
||||||
collections(first: $first, after: $after, before: $before, last: $last) {
|
|
||||||
edges {
|
edges {
|
||||||
node {
|
node {
|
||||||
...CollectionFragment
|
...CollectionFragment
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
// This file was automatically generated and should not be edited.
|
// This file was automatically generated and should not be edited.
|
||||||
|
|
||||||
|
import { CollectionFilterInput } from "./../../types/globalTypes";
|
||||||
|
|
||||||
// ====================================================
|
// ====================================================
|
||||||
// GraphQL query operation: CollectionList
|
// GraphQL query operation: CollectionList
|
||||||
// ====================================================
|
// ====================================================
|
||||||
|
@ -47,4 +49,5 @@ export interface CollectionListVariables {
|
||||||
after?: string | null;
|
after?: string | null;
|
||||||
last?: number | null;
|
last?: number | null;
|
||||||
before?: string | null;
|
before?: string | null;
|
||||||
|
filter?: CollectionFilterInput | null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,30 @@
|
||||||
import { stringify as stringifyQs } from "qs";
|
import { stringify as stringifyQs } from "qs";
|
||||||
import urlJoin from "url-join";
|
import urlJoin from "url-join";
|
||||||
|
|
||||||
import { BulkAction, Dialog, Pagination } from "../types";
|
import {
|
||||||
|
ActiveTab,
|
||||||
|
BulkAction,
|
||||||
|
Dialog,
|
||||||
|
Filters,
|
||||||
|
Pagination,
|
||||||
|
TabActionDialog
|
||||||
|
} from "../types";
|
||||||
|
|
||||||
const collectionSectionUrl = "/collections/";
|
const collectionSectionUrl = "/collections/";
|
||||||
|
|
||||||
export const collectionListPath = collectionSectionUrl;
|
export const collectionListPath = collectionSectionUrl;
|
||||||
export type CollectionListUrlDialog = "publish" | "unpublish" | "remove";
|
export enum CollectionListUrlFiltersEnum {
|
||||||
export type CollectionListUrlQueryParams = BulkAction &
|
query = "query"
|
||||||
|
}
|
||||||
|
export type CollectionListUrlFilters = Filters<CollectionListUrlFiltersEnum>;
|
||||||
|
export type CollectionListUrlDialog =
|
||||||
|
| "publish"
|
||||||
|
| "unpublish"
|
||||||
|
| "remove"
|
||||||
|
| TabActionDialog;
|
||||||
|
export type CollectionListUrlQueryParams = ActiveTab &
|
||||||
|
BulkAction &
|
||||||
|
CollectionListUrlFilters &
|
||||||
Dialog<CollectionListUrlDialog> &
|
Dialog<CollectionListUrlDialog> &
|
||||||
Pagination;
|
Pagination;
|
||||||
export const collectionListUrl = (params?: CollectionListUrlQueryParams) =>
|
export const collectionListUrl = (params?: CollectionListUrlQueryParams) =>
|
||||||
|
|
|
@ -6,6 +6,10 @@ import React from "react";
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
|
|
||||||
import ActionDialog from "@saleor/components/ActionDialog";
|
import ActionDialog from "@saleor/components/ActionDialog";
|
||||||
|
import DeleteFilterTabDialog from "@saleor/components/DeleteFilterTabDialog";
|
||||||
|
import SaveFilterTabDialog, {
|
||||||
|
SaveFilterTabDialogFormData
|
||||||
|
} from "@saleor/components/SaveFilterTabDialog";
|
||||||
import useBulkActions from "@saleor/hooks/useBulkActions";
|
import useBulkActions from "@saleor/hooks/useBulkActions";
|
||||||
import useListSettings from "@saleor/hooks/useListSettings";
|
import useListSettings from "@saleor/hooks/useListSettings";
|
||||||
import useNavigator from "@saleor/hooks/useNavigator";
|
import useNavigator from "@saleor/hooks/useNavigator";
|
||||||
|
@ -16,21 +20,30 @@ import usePaginator, {
|
||||||
import { commonMessages } from "@saleor/intl";
|
import { commonMessages } from "@saleor/intl";
|
||||||
import { getMutationState, maybe } from "@saleor/misc";
|
import { getMutationState, maybe } from "@saleor/misc";
|
||||||
import { ListViews } from "@saleor/types";
|
import { ListViews } from "@saleor/types";
|
||||||
import CollectionListPage from "../components/CollectionListPage/CollectionListPage";
|
import CollectionListPage from "../../components/CollectionListPage/CollectionListPage";
|
||||||
import {
|
import {
|
||||||
TypedCollectionBulkDelete,
|
TypedCollectionBulkDelete,
|
||||||
TypedCollectionBulkPublish
|
TypedCollectionBulkPublish
|
||||||
} from "../mutations";
|
} from "../../mutations";
|
||||||
import { TypedCollectionListQuery } from "../queries";
|
import { TypedCollectionListQuery } from "../../queries";
|
||||||
import { CollectionBulkDelete } from "../types/CollectionBulkDelete";
|
import { CollectionBulkDelete } from "../../types/CollectionBulkDelete";
|
||||||
import { CollectionBulkPublish } from "../types/CollectionBulkPublish";
|
import { CollectionBulkPublish } from "../../types/CollectionBulkPublish";
|
||||||
import {
|
import {
|
||||||
collectionAddUrl,
|
collectionAddUrl,
|
||||||
collectionListUrl,
|
collectionListUrl,
|
||||||
CollectionListUrlDialog,
|
CollectionListUrlDialog,
|
||||||
|
CollectionListUrlFilters,
|
||||||
CollectionListUrlQueryParams,
|
CollectionListUrlQueryParams,
|
||||||
collectionUrl
|
collectionUrl
|
||||||
} from "../urls";
|
} from "../../urls";
|
||||||
|
import {
|
||||||
|
areFiltersApplied,
|
||||||
|
deleteFilterTab,
|
||||||
|
getActiveFilters,
|
||||||
|
getFilterTabs,
|
||||||
|
getFilterVariables,
|
||||||
|
saveFilterTab
|
||||||
|
} from "./filter";
|
||||||
|
|
||||||
interface CollectionListProps {
|
interface CollectionListProps {
|
||||||
params: CollectionListUrlQueryParams;
|
params: CollectionListUrlQueryParams;
|
||||||
|
@ -50,6 +63,26 @@ export const CollectionList: React.StatelessComponent<CollectionListProps> = ({
|
||||||
);
|
);
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
|
const tabs = getFilterTabs();
|
||||||
|
|
||||||
|
const currentTab =
|
||||||
|
params.activeTab === undefined
|
||||||
|
? areFiltersApplied(params)
|
||||||
|
? tabs.length + 1
|
||||||
|
: 0
|
||||||
|
: parseInt(params.activeTab, 0);
|
||||||
|
|
||||||
|
const changeFilterField = (filter: CollectionListUrlFilters) => {
|
||||||
|
reset();
|
||||||
|
navigate(
|
||||||
|
collectionListUrl({
|
||||||
|
...getActiveFilters(params),
|
||||||
|
...filter,
|
||||||
|
activeTab: undefined
|
||||||
|
})
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const closeModal = () =>
|
const closeModal = () =>
|
||||||
navigate(
|
navigate(
|
||||||
collectionListUrl({
|
collectionListUrl({
|
||||||
|
@ -60,17 +93,47 @@ export const CollectionList: React.StatelessComponent<CollectionListProps> = ({
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
|
|
||||||
const openModal = (action: CollectionListUrlDialog, ids: string[]) =>
|
const openModal = (action: CollectionListUrlDialog, ids?: string[]) =>
|
||||||
navigate(
|
navigate(
|
||||||
collectionListUrl({
|
collectionListUrl({
|
||||||
|
...params,
|
||||||
action,
|
action,
|
||||||
ids
|
ids
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const handleTabChange = (tab: number) => {
|
||||||
|
reset();
|
||||||
|
navigate(
|
||||||
|
collectionListUrl({
|
||||||
|
activeTab: tab.toString(),
|
||||||
|
...getFilterTabs()[tab - 1].data
|
||||||
|
})
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleTabDelete = () => {
|
||||||
|
deleteFilterTab(currentTab);
|
||||||
|
reset();
|
||||||
|
navigate(collectionListUrl());
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleTabSave = (data: SaveFilterTabDialogFormData) => {
|
||||||
|
saveFilterTab(data.name, getActiveFilters(params));
|
||||||
|
handleTabChange(tabs.length + 1);
|
||||||
|
};
|
||||||
|
|
||||||
const paginationState = createPaginationState(settings.rowNumber, params);
|
const paginationState = createPaginationState(settings.rowNumber, params);
|
||||||
|
const queryVariables = React.useMemo(
|
||||||
|
() => ({
|
||||||
|
...paginationState,
|
||||||
|
filter: getFilterVariables(params)
|
||||||
|
}),
|
||||||
|
[params]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TypedCollectionListQuery displayLoader variables={paginationState}>
|
<TypedCollectionListQuery displayLoader variables={queryVariables}>
|
||||||
{({ data, loading, refetch }) => {
|
{({ data, loading, refetch }) => {
|
||||||
const { loadNextPage, loadPreviousPage, pageInfo } = paginate(
|
const { loadNextPage, loadPreviousPage, pageInfo } = paginate(
|
||||||
maybe(() => data.collections.pageInfo),
|
maybe(() => data.collections.pageInfo),
|
||||||
|
@ -130,7 +193,15 @@ export const CollectionList: React.StatelessComponent<CollectionListProps> = ({
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<CollectionListPage
|
<CollectionListPage
|
||||||
|
currentTab={currentTab}
|
||||||
|
initialSearch={params.query || ""}
|
||||||
|
onSearchChange={query => changeFilterField({ query })}
|
||||||
onAdd={() => navigate(collectionAddUrl)}
|
onAdd={() => navigate(collectionAddUrl)}
|
||||||
|
onAll={() => navigate(collectionListUrl())}
|
||||||
|
onTabChange={handleTabChange}
|
||||||
|
onTabDelete={() => openModal("delete-search")}
|
||||||
|
onTabSave={() => openModal("save-search")}
|
||||||
|
tabs={tabs.map(tab => tab.name)}
|
||||||
disabled={loading}
|
disabled={loading}
|
||||||
collections={maybe(() =>
|
collections={maybe(() =>
|
||||||
data.collections.edges.map(edge => edge.node)
|
data.collections.edges.map(edge => edge.node)
|
||||||
|
@ -289,6 +360,19 @@ export const CollectionList: React.StatelessComponent<CollectionListProps> = ({
|
||||||
/>
|
/>
|
||||||
</DialogContentText>
|
</DialogContentText>
|
||||||
</ActionDialog>
|
</ActionDialog>
|
||||||
|
<SaveFilterTabDialog
|
||||||
|
open={params.action === "save-search"}
|
||||||
|
confirmButtonState="default"
|
||||||
|
onClose={closeModal}
|
||||||
|
onSubmit={handleTabSave}
|
||||||
|
/>
|
||||||
|
<DeleteFilterTabDialog
|
||||||
|
open={params.action === "delete-search"}
|
||||||
|
confirmButtonState="default"
|
||||||
|
onClose={closeModal}
|
||||||
|
onSubmit={handleTabDelete}
|
||||||
|
tabName={maybe(() => tabs[currentTab - 1].name, "...")}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
31
src/collections/views/CollectionList/filter.ts
Normal file
31
src/collections/views/CollectionList/filter.ts
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
import { CollectionFilterInput } from "@saleor/types/globalTypes";
|
||||||
|
import {
|
||||||
|
createFilterTabUtils,
|
||||||
|
createFilterUtils
|
||||||
|
} from "../../../utils/filters";
|
||||||
|
import {
|
||||||
|
CollectionListUrlFilters,
|
||||||
|
CollectionListUrlFiltersEnum,
|
||||||
|
CollectionListUrlQueryParams
|
||||||
|
} from "../../urls";
|
||||||
|
|
||||||
|
export const COLLECTION_FILTERS_KEY = "collectionFilters";
|
||||||
|
|
||||||
|
export function getFilterVariables(
|
||||||
|
params: CollectionListUrlFilters
|
||||||
|
): CollectionFilterInput {
|
||||||
|
return {
|
||||||
|
search: params.query
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export const {
|
||||||
|
deleteFilterTab,
|
||||||
|
getFilterTabs,
|
||||||
|
saveFilterTab
|
||||||
|
} = createFilterTabUtils<CollectionListUrlFilters>(COLLECTION_FILTERS_KEY);
|
||||||
|
|
||||||
|
export const { areFiltersApplied, getActiveFilters } = createFilterUtils<
|
||||||
|
CollectionListUrlQueryParams,
|
||||||
|
CollectionListUrlFilters
|
||||||
|
>(CollectionListUrlFiltersEnum);
|
2
src/collections/views/CollectionList/index.ts
Normal file
2
src/collections/views/CollectionList/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
export { default } from "./CollectionList";
|
||||||
|
export * from "./CollectionList";
|
109
src/components/Filter/FilterActions.tsx
Normal file
109
src/components/Filter/FilterActions.tsx
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
import { Theme } from "@material-ui/core/styles";
|
||||||
|
import TextField, { TextFieldProps } from "@material-ui/core/TextField";
|
||||||
|
import { makeStyles } from "@material-ui/styles";
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
import { FilterContentSubmitData, IFilter } from "../Filter";
|
||||||
|
import Filter from "./Filter";
|
||||||
|
|
||||||
|
const useInputStyles = makeStyles({
|
||||||
|
input: {
|
||||||
|
padding: "10px 12px"
|
||||||
|
},
|
||||||
|
root: {
|
||||||
|
flex: 1
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const Search: React.FC<TextFieldProps> = props => {
|
||||||
|
const classes = useInputStyles({});
|
||||||
|
return (
|
||||||
|
<TextField
|
||||||
|
{...props}
|
||||||
|
className={classes.root}
|
||||||
|
inputProps={{
|
||||||
|
className: classes.input
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const useStyles = makeStyles(
|
||||||
|
(theme: Theme) => ({
|
||||||
|
actionContainer: {
|
||||||
|
display: "flex",
|
||||||
|
flexWrap: "wrap",
|
||||||
|
padding: `${theme.spacing.unit * 1.5}px ${theme.spacing.unit * 3}px ${
|
||||||
|
theme.spacing.unit
|
||||||
|
}px`
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
name: "FilterActions"
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export interface FilterActionsPropsSearch {
|
||||||
|
placeholder: string;
|
||||||
|
search: string;
|
||||||
|
onSearchChange: (event: React.ChangeEvent<any>) => void;
|
||||||
|
}
|
||||||
|
export interface FilterActionsPropsFilters<TKeys = string> {
|
||||||
|
currencySymbol: string;
|
||||||
|
menu: IFilter<TKeys>;
|
||||||
|
filterLabel: string;
|
||||||
|
onFilterAdd: (filter: FilterContentSubmitData<TKeys>) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const FilterActionsOnlySearch: React.FC<
|
||||||
|
FilterActionsPropsSearch
|
||||||
|
> = props => {
|
||||||
|
const { onSearchChange, placeholder, search } = props;
|
||||||
|
const classes = useStyles(props);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={classes.actionContainer}>
|
||||||
|
<Search
|
||||||
|
fullWidth
|
||||||
|
placeholder={placeholder}
|
||||||
|
value={search}
|
||||||
|
onChange={onSearchChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export type FilterActionsProps = FilterActionsPropsSearch &
|
||||||
|
FilterActionsPropsFilters;
|
||||||
|
const FilterActions: React.FC<FilterActionsProps> = props => {
|
||||||
|
const {
|
||||||
|
currencySymbol,
|
||||||
|
filterLabel,
|
||||||
|
menu,
|
||||||
|
onFilterAdd,
|
||||||
|
onSearchChange,
|
||||||
|
placeholder,
|
||||||
|
search
|
||||||
|
} = props;
|
||||||
|
const classes = useStyles(props);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={classes.actionContainer}>
|
||||||
|
<Filter
|
||||||
|
currencySymbol={currencySymbol}
|
||||||
|
menu={menu}
|
||||||
|
filterLabel={filterLabel}
|
||||||
|
onFilterAdd={onFilterAdd}
|
||||||
|
/>
|
||||||
|
<Search
|
||||||
|
fullWidth
|
||||||
|
placeholder={placeholder}
|
||||||
|
value={search}
|
||||||
|
onChange={onSearchChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
FilterActions.displayName = "FilterActions";
|
||||||
|
export default FilterActions;
|
98
src/components/Filter/FilterSearch.tsx
Normal file
98
src/components/Filter/FilterSearch.tsx
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
import { Theme } from "@material-ui/core/styles";
|
||||||
|
import { makeStyles } from "@material-ui/styles";
|
||||||
|
import React from "react";
|
||||||
|
import { FormattedMessage } from "react-intl";
|
||||||
|
|
||||||
|
import { SearchPageProps } from "../../types";
|
||||||
|
import Debounce from "../Debounce";
|
||||||
|
import { FilterActionsOnlySearch } from "../Filter/FilterActions";
|
||||||
|
import Hr from "../Hr";
|
||||||
|
import Link from "../Link";
|
||||||
|
|
||||||
|
export interface FilterSearchProps extends SearchPageProps {
|
||||||
|
displaySearchAction: "save" | "delete" | null;
|
||||||
|
searchPlaceholder: string;
|
||||||
|
onSearchDelete?: () => void;
|
||||||
|
onSearchSave?: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const useStyles = makeStyles(
|
||||||
|
(theme: Theme) => ({
|
||||||
|
tabAction: {
|
||||||
|
display: "inline-block"
|
||||||
|
},
|
||||||
|
tabActionContainer: {
|
||||||
|
borderBottom: `1px solid ${theme.palette.divider}`,
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "flex-end",
|
||||||
|
marginTop: theme.spacing.unit,
|
||||||
|
padding: `0 ${theme.spacing.unit * 3}px ${theme.spacing.unit}px`
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
name: "FilterSearch"
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const FilterSearch: React.FC<FilterSearchProps> = props => {
|
||||||
|
const {
|
||||||
|
displaySearchAction,
|
||||||
|
initialSearch,
|
||||||
|
onSearchChange,
|
||||||
|
onSearchDelete,
|
||||||
|
onSearchSave,
|
||||||
|
searchPlaceholder
|
||||||
|
} = props;
|
||||||
|
const classes = useStyles(props);
|
||||||
|
const [search, setSearch] = React.useState(initialSearch);
|
||||||
|
React.useEffect(() => setSearch(initialSearch), [initialSearch]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Debounce debounceFn={onSearchChange}>
|
||||||
|
{debounceSearchChange => {
|
||||||
|
const handleSearchChange = (event: React.ChangeEvent<any>) => {
|
||||||
|
const value = event.target.value;
|
||||||
|
setSearch(value);
|
||||||
|
debounceSearchChange(value);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<FilterActionsOnlySearch
|
||||||
|
{...props}
|
||||||
|
placeholder={searchPlaceholder}
|
||||||
|
search={search}
|
||||||
|
onSearchChange={handleSearchChange}
|
||||||
|
/>
|
||||||
|
{!!displaySearchAction ? (
|
||||||
|
<div className={classes.tabActionContainer}>
|
||||||
|
<div className={classes.tabAction}>
|
||||||
|
{displaySearchAction === "save" ? (
|
||||||
|
<Link onClick={onSearchSave}>
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage="Save Custom Search"
|
||||||
|
description="button"
|
||||||
|
/>
|
||||||
|
</Link>
|
||||||
|
) : (
|
||||||
|
<Link onClick={onSearchDelete}>
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage="Delete Search"
|
||||||
|
description="button"
|
||||||
|
/>
|
||||||
|
</Link>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<Hr />
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
</Debounce>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
FilterSearch.displayName = "FilterSearch";
|
||||||
|
export default FilterSearch;
|
|
@ -6,9 +6,8 @@ import Debounce from "../Debounce";
|
||||||
import { IFilter } from "../Filter/types";
|
import { IFilter } from "../Filter/types";
|
||||||
import FilterTabs, { FilterChips, FilterTab } from "../TableFilter";
|
import FilterTabs, { FilterChips, FilterTab } from "../TableFilter";
|
||||||
|
|
||||||
export interface FilterBarProps<TUrlFilters = object, TFilterKeys = any>
|
export interface FilterBarProps<TKeys = string> extends FilterProps {
|
||||||
extends FilterProps<TUrlFilters, TFilterKeys> {
|
filterMenu: IFilter<TKeys>;
|
||||||
filterMenu: IFilter<TFilterKeys>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const FilterBar: React.FC<FilterBarProps> = ({
|
const FilterBar: React.FC<FilterBarProps> = ({
|
||||||
|
@ -16,32 +15,32 @@ const FilterBar: React.FC<FilterBarProps> = ({
|
||||||
currencySymbol,
|
currencySymbol,
|
||||||
filterLabel,
|
filterLabel,
|
||||||
filtersList,
|
filtersList,
|
||||||
filterTabs,
|
|
||||||
filterMenu,
|
filterMenu,
|
||||||
currentTab,
|
currentTab,
|
||||||
initialSearch,
|
initialSearch,
|
||||||
searchPlaceholder,
|
searchPlaceholder,
|
||||||
|
tabs,
|
||||||
onAll,
|
onAll,
|
||||||
onSearchChange,
|
onSearchChange,
|
||||||
onFilterAdd,
|
onFilterAdd,
|
||||||
onFilterSave,
|
|
||||||
onTabChange,
|
onTabChange,
|
||||||
onFilterDelete
|
onTabDelete,
|
||||||
|
onTabSave
|
||||||
}) => {
|
}) => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const [search, setSearch] = React.useState(initialSearch);
|
const [search, setSearch] = React.useState(initialSearch);
|
||||||
React.useEffect(() => setSearch(initialSearch), [currentTab, initialSearch]);
|
React.useEffect(() => setSearch(initialSearch), [currentTab, initialSearch]);
|
||||||
|
|
||||||
const isCustom = currentTab === filterTabs.length + 1;
|
const isCustom = currentTab === tabs.length + 1;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<FilterTabs currentTab={currentTab}>
|
<FilterTabs currentTab={currentTab}>
|
||||||
<FilterTab label={allTabLabel} onClick={onAll} />
|
<FilterTab label={allTabLabel} onClick={onAll} />
|
||||||
{filterTabs.map((tab, tabIndex) => (
|
{tabs.map((tab, tabIndex) => (
|
||||||
<FilterTab
|
<FilterTab
|
||||||
onClick={() => onTabChange(tabIndex + 1)}
|
onClick={() => onTabChange(tabIndex + 1)}
|
||||||
label={tab.name}
|
label={tab}
|
||||||
key={tabIndex}
|
key={tabIndex}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
|
@ -65,6 +64,9 @@ const FilterBar: React.FC<FilterBarProps> = ({
|
||||||
return (
|
return (
|
||||||
<FilterChips
|
<FilterChips
|
||||||
currencySymbol={currencySymbol}
|
currencySymbol={currencySymbol}
|
||||||
|
displayTabAction={
|
||||||
|
!!initialSearch ? (isCustom ? "save" : "delete") : null
|
||||||
|
}
|
||||||
menu={filterMenu}
|
menu={filterMenu}
|
||||||
filtersList={filtersList}
|
filtersList={filtersList}
|
||||||
filterLabel={filterLabel}
|
filterLabel={filterLabel}
|
||||||
|
@ -72,9 +74,9 @@ const FilterBar: React.FC<FilterBarProps> = ({
|
||||||
search={search}
|
search={search}
|
||||||
onSearchChange={handleSearchChange}
|
onSearchChange={handleSearchChange}
|
||||||
onFilterAdd={onFilterAdd}
|
onFilterAdd={onFilterAdd}
|
||||||
onFilterSave={onFilterSave}
|
onFilterSave={onTabSave}
|
||||||
isCustomSearch={isCustom}
|
isCustomSearch={isCustom}
|
||||||
onFilterDelete={onFilterDelete}
|
onFilterDelete={onTabDelete}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
|
|
|
@ -56,6 +56,7 @@ const SaveFilterTabDialog: React.FC<SaveFilterTabDialogProps> = ({
|
||||||
<>
|
<>
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
<TextField
|
<TextField
|
||||||
|
autoFocus
|
||||||
fullWidth
|
fullWidth
|
||||||
label={intl.formatMessage({
|
label={intl.formatMessage({
|
||||||
defaultMessage: "Search Name",
|
defaultMessage: "Search Name",
|
||||||
|
|
65
src/components/SearchBar/SearchBar.tsx
Normal file
65
src/components/SearchBar/SearchBar.tsx
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
import React from "react";
|
||||||
|
import { useIntl } from "react-intl";
|
||||||
|
|
||||||
|
import { SearchPageProps, TabPageProps } from "@saleor/types";
|
||||||
|
import FilterSearch from "../Filter/FilterSearch";
|
||||||
|
import FilterTabs, { FilterTab } from "../TableFilter";
|
||||||
|
|
||||||
|
export interface SearchBarProps extends SearchPageProps, TabPageProps {
|
||||||
|
allTabLabel: string;
|
||||||
|
searchPlaceholder: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SearchBar: React.FC<SearchBarProps> = props => {
|
||||||
|
const {
|
||||||
|
allTabLabel,
|
||||||
|
currentTab,
|
||||||
|
initialSearch,
|
||||||
|
onSearchChange,
|
||||||
|
searchPlaceholder,
|
||||||
|
tabs,
|
||||||
|
onAll,
|
||||||
|
onTabChange,
|
||||||
|
onTabDelete,
|
||||||
|
onTabSave
|
||||||
|
} = props;
|
||||||
|
const intl = useIntl();
|
||||||
|
|
||||||
|
const isCustom = currentTab === tabs.length + 1;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<FilterTabs currentTab={currentTab}>
|
||||||
|
<FilterTab label={allTabLabel} onClick={onAll} />
|
||||||
|
{tabs.map((tab, tabIndex) => (
|
||||||
|
<FilterTab
|
||||||
|
onClick={() => onTabChange(tabIndex + 1)}
|
||||||
|
label={tab}
|
||||||
|
key={tabIndex}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
{isCustom && (
|
||||||
|
<FilterTab
|
||||||
|
onClick={() => undefined}
|
||||||
|
label={intl.formatMessage({
|
||||||
|
defaultMessage: "Custom Filter"
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</FilterTabs>
|
||||||
|
<FilterSearch
|
||||||
|
displaySearchAction={
|
||||||
|
!!initialSearch ? (isCustom ? "save" : "delete") : null
|
||||||
|
}
|
||||||
|
initialSearch={initialSearch}
|
||||||
|
searchPlaceholder={searchPlaceholder}
|
||||||
|
onSearchChange={onSearchChange}
|
||||||
|
onSearchDelete={onTabDelete}
|
||||||
|
onSearchSave={onTabSave}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
SearchBar.displayName = "SearchBar";
|
||||||
|
export default SearchBar;
|
2
src/components/SearchBar/index.ts
Normal file
2
src/components/SearchBar/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
export { default } from "./SearchBar";
|
||||||
|
export * from "./SearchBar";
|
|
@ -1,14 +1,14 @@
|
||||||
import ButtonBase from "@material-ui/core/ButtonBase";
|
import ButtonBase from "@material-ui/core/ButtonBase";
|
||||||
import { Theme } from "@material-ui/core/styles";
|
import { Theme } from "@material-ui/core/styles";
|
||||||
import { fade } from "@material-ui/core/styles/colorManipulator";
|
import { fade } from "@material-ui/core/styles/colorManipulator";
|
||||||
import TextField, { TextFieldProps } from "@material-ui/core/TextField";
|
|
||||||
import Typography from "@material-ui/core/Typography";
|
import Typography from "@material-ui/core/Typography";
|
||||||
import ClearIcon from "@material-ui/icons/Clear";
|
import ClearIcon from "@material-ui/icons/Clear";
|
||||||
import { createStyles, makeStyles, useTheme } from "@material-ui/styles";
|
import { makeStyles, useTheme } from "@material-ui/styles";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { FormattedMessage } from "react-intl";
|
import { FormattedMessage } from "react-intl";
|
||||||
|
|
||||||
import Filter, { FilterContentSubmitData, IFilter } from "../Filter";
|
import Filter from "../Filter";
|
||||||
|
import FilterActions, { FilterActionsProps } from "../Filter/FilterActions";
|
||||||
import Hr from "../Hr";
|
import Hr from "../Hr";
|
||||||
import Link from "../Link";
|
import Link from "../Link";
|
||||||
|
|
||||||
|
@ -17,38 +17,8 @@ export interface Filter {
|
||||||
onClick: () => void;
|
onClick: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const useInputStyles = makeStyles({
|
|
||||||
input: {
|
|
||||||
padding: "10px 12px"
|
|
||||||
},
|
|
||||||
root: {
|
|
||||||
flex: 1
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const Search: React.FC<TextFieldProps> = props => {
|
|
||||||
const classes = useInputStyles({});
|
|
||||||
return (
|
|
||||||
<TextField
|
|
||||||
{...props}
|
|
||||||
className={classes.root}
|
|
||||||
inputProps={{
|
|
||||||
className: classes.input
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const useStyles = makeStyles(
|
const useStyles = makeStyles(
|
||||||
(theme: Theme) =>
|
(theme: Theme) => ({
|
||||||
createStyles({
|
|
||||||
actionContainer: {
|
|
||||||
display: "flex",
|
|
||||||
flexWrap: "wrap",
|
|
||||||
padding: `${theme.spacing.unit * 2}px ${theme.spacing.unit * 3}px ${
|
|
||||||
theme.spacing.unit
|
|
||||||
}px ${theme.spacing.unit * 3}px`
|
|
||||||
},
|
|
||||||
filterButton: {
|
filterButton: {
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
backgroundColor: fade(theme.palette.primary.main, 0.8),
|
backgroundColor: fade(theme.palette.primary.main, 0.8),
|
||||||
|
@ -58,7 +28,7 @@ const useStyles = makeStyles(
|
||||||
justifyContent: "space-around",
|
justifyContent: "space-around",
|
||||||
margin: `0 ${theme.spacing.unit * 2}px ${theme.spacing.unit}px`,
|
margin: `0 ${theme.spacing.unit * 2}px ${theme.spacing.unit}px`,
|
||||||
marginLeft: 0,
|
marginLeft: 0,
|
||||||
padding: "0 16px"
|
padding: `0 ${theme.spacing.unit * 2}px`
|
||||||
},
|
},
|
||||||
filterChipContainer: {
|
filterChipContainer: {
|
||||||
display: "flex",
|
display: "flex",
|
||||||
|
@ -105,22 +75,18 @@ const useStyles = makeStyles(
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
interface FilterChipProps<TFilterKeys = string> {
|
interface FilterChipProps extends FilterActionsProps {
|
||||||
currencySymbol: string;
|
displayTabAction: "save" | "delete" | null;
|
||||||
menu: IFilter<TFilterKeys>;
|
|
||||||
filtersList: Filter[];
|
filtersList: Filter[];
|
||||||
filterLabel: string;
|
|
||||||
placeholder: string;
|
|
||||||
search: string;
|
search: string;
|
||||||
isCustomSearch: boolean;
|
isCustomSearch: boolean;
|
||||||
onSearchChange: (event: React.ChangeEvent<any>) => void;
|
|
||||||
onFilterAdd: (filter: FilterContentSubmitData<TFilterKeys>) => void;
|
|
||||||
onFilterDelete: () => void;
|
onFilterDelete: () => void;
|
||||||
onFilterSave: () => void;
|
onFilterSave: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const FilterChips: React.FC<FilterChipProps> = ({
|
export const FilterChips: React.FC<FilterChipProps> = ({
|
||||||
currencySymbol,
|
currencySymbol,
|
||||||
|
displayTabAction,
|
||||||
filtersList,
|
filtersList,
|
||||||
menu,
|
menu,
|
||||||
filterLabel,
|
filterLabel,
|
||||||
|
@ -129,29 +95,23 @@ export const FilterChips: React.FC<FilterChipProps> = ({
|
||||||
search,
|
search,
|
||||||
onFilterAdd,
|
onFilterAdd,
|
||||||
onFilterSave,
|
onFilterSave,
|
||||||
onFilterDelete,
|
onFilterDelete
|
||||||
isCustomSearch
|
|
||||||
}) => {
|
}) => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const classes = useStyles({ theme });
|
const classes = useStyles({ theme });
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className={classes.actionContainer}>
|
<FilterActions
|
||||||
<Filter
|
|
||||||
currencySymbol={currencySymbol}
|
currencySymbol={currencySymbol}
|
||||||
menu={menu}
|
menu={menu}
|
||||||
filterLabel={filterLabel}
|
filterLabel={filterLabel}
|
||||||
|
placeholder={placeholder}
|
||||||
|
search={search}
|
||||||
|
onSearchChange={onSearchChange}
|
||||||
onFilterAdd={onFilterAdd}
|
onFilterAdd={onFilterAdd}
|
||||||
/>
|
/>
|
||||||
<Search
|
{search || (filtersList && filtersList.length > 0) ? (
|
||||||
fullWidth
|
|
||||||
placeholder={placeholder}
|
|
||||||
value={search}
|
|
||||||
onChange={onSearchChange}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
{search || (filtersList && filtersList.length) ? (
|
|
||||||
<div className={classes.filterContainer}>
|
<div className={classes.filterContainer}>
|
||||||
<div className={classes.filterChipContainer}>
|
<div className={classes.filterChipContainer}>
|
||||||
{filtersList.map(filter => (
|
{filtersList.map(filter => (
|
||||||
|
@ -168,7 +128,7 @@ export const FilterChips: React.FC<FilterChipProps> = ({
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
{isCustomSearch ? (
|
{displayTabAction === "save" ? (
|
||||||
<Link onClick={onFilterSave}>
|
<Link onClick={onFilterSave}>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
defaultMessage="Save Custom Search"
|
defaultMessage="Save Custom Search"
|
||||||
|
@ -176,12 +136,14 @@ export const FilterChips: React.FC<FilterChipProps> = ({
|
||||||
/>
|
/>
|
||||||
</Link>
|
</Link>
|
||||||
) : (
|
) : (
|
||||||
|
displayTabAction === "delete" && (
|
||||||
<Link onClick={onFilterDelete}>
|
<Link onClick={onFilterDelete}>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
defaultMessage="Delete Search"
|
defaultMessage="Delete Search"
|
||||||
description="button"
|
description="button"
|
||||||
/>
|
/>
|
||||||
</Link>
|
</Link>
|
||||||
|
)
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import Card from "@material-ui/core/Card";
|
|
||||||
import {
|
import {
|
||||||
createStyles,
|
createStyles,
|
||||||
Theme,
|
Theme,
|
||||||
|
@ -68,7 +67,6 @@ const CustomerList = withStyles(styles, { name: "CustomerList" })(
|
||||||
selected,
|
selected,
|
||||||
isChecked
|
isChecked
|
||||||
}: CustomerListProps) => (
|
}: CustomerListProps) => (
|
||||||
<Card>
|
|
||||||
<Table>
|
<Table>
|
||||||
<TableHead
|
<TableHead
|
||||||
colSpan={numberOfColumns}
|
colSpan={numberOfColumns}
|
||||||
|
@ -150,7 +148,6 @@ const CustomerList = withStyles(styles, { name: "CustomerList" })(
|
||||||
)}
|
)}
|
||||||
</TableBody>
|
</TableBody>
|
||||||
</Table>
|
</Table>
|
||||||
</Card>
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
CustomerList.displayName = "CustomerList";
|
CustomerList.displayName = "CustomerList";
|
||||||
|
|
|
@ -1,23 +1,41 @@
|
||||||
import Button from "@material-ui/core/Button";
|
import Button from "@material-ui/core/Button";
|
||||||
|
import Card from "@material-ui/core/Card";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
|
|
||||||
import Container from "@saleor/components/Container";
|
import Container from "@saleor/components/Container";
|
||||||
import PageHeader from "@saleor/components/PageHeader";
|
import PageHeader from "@saleor/components/PageHeader";
|
||||||
|
import SearchBar from "@saleor/components/SearchBar";
|
||||||
import { sectionNames } from "@saleor/intl";
|
import { sectionNames } from "@saleor/intl";
|
||||||
import { ListActions, PageListProps } from "@saleor/types";
|
import {
|
||||||
|
ListActions,
|
||||||
|
PageListProps,
|
||||||
|
SearchPageProps,
|
||||||
|
TabPageProps
|
||||||
|
} from "@saleor/types";
|
||||||
import { ListCustomers_customers_edges_node } from "../../types/ListCustomers";
|
import { ListCustomers_customers_edges_node } from "../../types/ListCustomers";
|
||||||
import CustomerList from "../CustomerList/CustomerList";
|
import CustomerList from "../CustomerList/CustomerList";
|
||||||
|
|
||||||
export interface CustomerListPageProps extends PageListProps, ListActions {
|
export interface CustomerListPageProps
|
||||||
|
extends PageListProps,
|
||||||
|
ListActions,
|
||||||
|
SearchPageProps,
|
||||||
|
TabPageProps {
|
||||||
customers: ListCustomers_customers_edges_node[];
|
customers: ListCustomers_customers_edges_node[];
|
||||||
}
|
}
|
||||||
|
|
||||||
const CustomerListPage: React.StatelessComponent<CustomerListPageProps> = ({
|
const CustomerListPage: React.StatelessComponent<CustomerListPageProps> = ({
|
||||||
|
currentTab,
|
||||||
customers,
|
customers,
|
||||||
disabled,
|
disabled,
|
||||||
|
initialSearch,
|
||||||
onAdd,
|
onAdd,
|
||||||
|
onAll,
|
||||||
|
onSearchChange,
|
||||||
|
onTabChange,
|
||||||
|
onTabDelete,
|
||||||
|
onTabSave,
|
||||||
|
tabs,
|
||||||
...customerListProps
|
...customerListProps
|
||||||
}) => {
|
}) => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
@ -37,11 +55,30 @@ const CustomerListPage: React.StatelessComponent<CustomerListPageProps> = ({
|
||||||
/>
|
/>
|
||||||
</Button>
|
</Button>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
|
<Card>
|
||||||
|
<SearchBar
|
||||||
|
allTabLabel={intl.formatMessage({
|
||||||
|
defaultMessage: "All Customers",
|
||||||
|
description: "tab name"
|
||||||
|
})}
|
||||||
|
currentTab={currentTab}
|
||||||
|
initialSearch={initialSearch}
|
||||||
|
searchPlaceholder={intl.formatMessage({
|
||||||
|
defaultMessage: "Search Customer"
|
||||||
|
})}
|
||||||
|
tabs={tabs}
|
||||||
|
onAll={onAll}
|
||||||
|
onSearchChange={onSearchChange}
|
||||||
|
onTabChange={onTabChange}
|
||||||
|
onTabDelete={onTabDelete}
|
||||||
|
onTabSave={onTabSave}
|
||||||
|
/>
|
||||||
<CustomerList
|
<CustomerList
|
||||||
customers={customers}
|
customers={customers}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
{...customerListProps}
|
{...customerListProps}
|
||||||
/>
|
/>
|
||||||
|
</Card>
|
||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -64,8 +64,15 @@ const customerList = gql`
|
||||||
$before: String
|
$before: String
|
||||||
$first: Int
|
$first: Int
|
||||||
$last: Int
|
$last: Int
|
||||||
|
$filter: CustomerFilterInput
|
||||||
|
) {
|
||||||
|
customers(
|
||||||
|
after: $after
|
||||||
|
before: $before
|
||||||
|
first: $first
|
||||||
|
last: $last
|
||||||
|
filter: $filter
|
||||||
) {
|
) {
|
||||||
customers(after: $after, before: $before, first: $first, last: $last) {
|
|
||||||
edges {
|
edges {
|
||||||
node {
|
node {
|
||||||
...CustomerFragment
|
...CustomerFragment
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
// This file was automatically generated and should not be edited.
|
// This file was automatically generated and should not be edited.
|
||||||
|
|
||||||
|
import { CustomerFilterInput } from "./../../types/globalTypes";
|
||||||
|
|
||||||
// ====================================================
|
// ====================================================
|
||||||
// GraphQL query operation: ListCustomers
|
// GraphQL query operation: ListCustomers
|
||||||
// ====================================================
|
// ====================================================
|
||||||
|
@ -48,4 +50,5 @@ export interface ListCustomersVariables {
|
||||||
before?: string | null;
|
before?: string | null;
|
||||||
first?: number | null;
|
first?: number | null;
|
||||||
last?: number | null;
|
last?: number | null;
|
||||||
|
filter?: CustomerFilterInput | null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,27 @@
|
||||||
import { stringify as stringifyQs } from "qs";
|
import { stringify as stringifyQs } from "qs";
|
||||||
import urlJoin from "url-join";
|
import urlJoin from "url-join";
|
||||||
|
|
||||||
import { BulkAction, Dialog, Pagination, SingleAction } from "../types";
|
import {
|
||||||
|
ActiveTab,
|
||||||
|
BulkAction,
|
||||||
|
Dialog,
|
||||||
|
Filters,
|
||||||
|
Pagination,
|
||||||
|
SingleAction,
|
||||||
|
TabActionDialog
|
||||||
|
} from "../types";
|
||||||
|
|
||||||
export const customerSection = "/customers/";
|
export const customerSection = "/customers/";
|
||||||
|
|
||||||
export const customerListPath = customerSection;
|
export const customerListPath = customerSection;
|
||||||
export type CustomerListUrlDialog = "remove";
|
export enum CustomerListUrlFiltersEnum {
|
||||||
export type CustomerListUrlQueryParams = BulkAction &
|
query = "query"
|
||||||
|
}
|
||||||
|
export type CustomerListUrlFilters = Filters<CustomerListUrlFiltersEnum>;
|
||||||
|
export type CustomerListUrlDialog = "remove" | TabActionDialog;
|
||||||
|
export type CustomerListUrlQueryParams = ActiveTab &
|
||||||
|
BulkAction &
|
||||||
|
CustomerListUrlFilters &
|
||||||
Dialog<CustomerListUrlDialog> &
|
Dialog<CustomerListUrlDialog> &
|
||||||
Pagination;
|
Pagination;
|
||||||
export const customerListUrl = (params?: CustomerListUrlQueryParams) =>
|
export const customerListUrl = (params?: CustomerListUrlQueryParams) =>
|
||||||
|
|
|
@ -5,6 +5,10 @@ import React from "react";
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
|
|
||||||
import ActionDialog from "@saleor/components/ActionDialog";
|
import ActionDialog from "@saleor/components/ActionDialog";
|
||||||
|
import DeleteFilterTabDialog from "@saleor/components/DeleteFilterTabDialog";
|
||||||
|
import SaveFilterTabDialog, {
|
||||||
|
SaveFilterTabDialogFormData
|
||||||
|
} from "@saleor/components/SaveFilterTabDialog";
|
||||||
import useBulkActions from "@saleor/hooks/useBulkActions";
|
import useBulkActions from "@saleor/hooks/useBulkActions";
|
||||||
import useListSettings from "@saleor/hooks/useListSettings";
|
import useListSettings from "@saleor/hooks/useListSettings";
|
||||||
import useNavigator from "@saleor/hooks/useNavigator";
|
import useNavigator from "@saleor/hooks/useNavigator";
|
||||||
|
@ -15,16 +19,26 @@ import usePaginator, {
|
||||||
import { commonMessages } from "@saleor/intl";
|
import { commonMessages } from "@saleor/intl";
|
||||||
import { getMutationState, maybe } from "@saleor/misc";
|
import { getMutationState, maybe } from "@saleor/misc";
|
||||||
import { ListViews } from "@saleor/types";
|
import { ListViews } from "@saleor/types";
|
||||||
import CustomerListPage from "../components/CustomerListPage";
|
import CustomerListPage from "../../components/CustomerListPage";
|
||||||
import { TypedBulkRemoveCustomers } from "../mutations";
|
import { TypedBulkRemoveCustomers } from "../../mutations";
|
||||||
import { TypedCustomerListQuery } from "../queries";
|
import { TypedCustomerListQuery } from "../../queries";
|
||||||
import { BulkRemoveCustomers } from "../types/BulkRemoveCustomers";
|
import { BulkRemoveCustomers } from "../../types/BulkRemoveCustomers";
|
||||||
import {
|
import {
|
||||||
customerAddUrl,
|
customerAddUrl,
|
||||||
customerListUrl,
|
customerListUrl,
|
||||||
|
CustomerListUrlDialog,
|
||||||
|
CustomerListUrlFilters,
|
||||||
CustomerListUrlQueryParams,
|
CustomerListUrlQueryParams,
|
||||||
customerUrl
|
customerUrl
|
||||||
} from "../urls";
|
} from "../../urls";
|
||||||
|
import {
|
||||||
|
areFiltersApplied,
|
||||||
|
deleteFilterTab,
|
||||||
|
getActiveFilters,
|
||||||
|
getFilterTabs,
|
||||||
|
getFilterVariables,
|
||||||
|
saveFilterTab
|
||||||
|
} from "./filter";
|
||||||
|
|
||||||
interface CustomerListProps {
|
interface CustomerListProps {
|
||||||
params: CustomerListUrlQueryParams;
|
params: CustomerListUrlQueryParams;
|
||||||
|
@ -44,6 +58,26 @@ export const CustomerList: React.StatelessComponent<CustomerListProps> = ({
|
||||||
);
|
);
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
|
const tabs = getFilterTabs();
|
||||||
|
|
||||||
|
const currentTab =
|
||||||
|
params.activeTab === undefined
|
||||||
|
? areFiltersApplied(params)
|
||||||
|
? tabs.length + 1
|
||||||
|
: 0
|
||||||
|
: parseInt(params.activeTab, 0);
|
||||||
|
|
||||||
|
const changeFilterField = (filter: CustomerListUrlFilters) => {
|
||||||
|
reset();
|
||||||
|
navigate(
|
||||||
|
customerListUrl({
|
||||||
|
...getActiveFilters(params),
|
||||||
|
...filter,
|
||||||
|
activeTab: undefined
|
||||||
|
})
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const closeModal = () =>
|
const closeModal = () =>
|
||||||
navigate(
|
navigate(
|
||||||
customerListUrl({
|
customerListUrl({
|
||||||
|
@ -54,10 +88,47 @@ export const CustomerList: React.StatelessComponent<CustomerListProps> = ({
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const openModal = (action: CustomerListUrlDialog, ids?: string[]) =>
|
||||||
|
navigate(
|
||||||
|
customerListUrl({
|
||||||
|
...params,
|
||||||
|
action,
|
||||||
|
ids
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleTabChange = (tab: number) => {
|
||||||
|
reset();
|
||||||
|
navigate(
|
||||||
|
customerListUrl({
|
||||||
|
activeTab: tab.toString(),
|
||||||
|
...getFilterTabs()[tab - 1].data
|
||||||
|
})
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleTabDelete = () => {
|
||||||
|
deleteFilterTab(currentTab);
|
||||||
|
reset();
|
||||||
|
navigate(customerListUrl());
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleTabSave = (data: SaveFilterTabDialogFormData) => {
|
||||||
|
saveFilterTab(data.name, getActiveFilters(params));
|
||||||
|
handleTabChange(tabs.length + 1);
|
||||||
|
};
|
||||||
|
|
||||||
const paginationState = createPaginationState(settings.rowNumber, params);
|
const paginationState = createPaginationState(settings.rowNumber, params);
|
||||||
|
const queryVariables = React.useMemo(
|
||||||
|
() => ({
|
||||||
|
...paginationState,
|
||||||
|
filter: getFilterVariables(params)
|
||||||
|
}),
|
||||||
|
[params]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TypedCustomerListQuery displayLoader variables={paginationState}>
|
<TypedCustomerListQuery displayLoader variables={queryVariables}>
|
||||||
{({ data, loading, refetch }) => {
|
{({ data, loading, refetch }) => {
|
||||||
const { loadNextPage, loadPreviousPage, pageInfo } = paginate(
|
const { loadNextPage, loadPreviousPage, pageInfo } = paginate(
|
||||||
maybe(() => data.customers.pageInfo),
|
maybe(() => data.customers.pageInfo),
|
||||||
|
@ -90,6 +161,14 @@ export const CustomerList: React.StatelessComponent<CustomerListProps> = ({
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<CustomerListPage
|
<CustomerListPage
|
||||||
|
currentTab={currentTab}
|
||||||
|
initialSearch={params.query || ""}
|
||||||
|
onSearchChange={query => changeFilterField({ query })}
|
||||||
|
onAll={() => navigate(customerListUrl())}
|
||||||
|
onTabChange={handleTabChange}
|
||||||
|
onTabDelete={() => openModal("delete-search")}
|
||||||
|
onTabSave={() => openModal("save-search")}
|
||||||
|
tabs={tabs.map(tab => tab.name)}
|
||||||
customers={maybe(() =>
|
customers={maybe(() =>
|
||||||
data.customers.edges.map(edge => edge.node)
|
data.customers.edges.map(edge => edge.node)
|
||||||
)}
|
)}
|
||||||
|
@ -156,6 +235,19 @@ export const CustomerList: React.StatelessComponent<CustomerListProps> = ({
|
||||||
/>
|
/>
|
||||||
</DialogContentText>
|
</DialogContentText>
|
||||||
</ActionDialog>
|
</ActionDialog>
|
||||||
|
<SaveFilterTabDialog
|
||||||
|
open={params.action === "save-search"}
|
||||||
|
confirmButtonState="default"
|
||||||
|
onClose={closeModal}
|
||||||
|
onSubmit={handleTabSave}
|
||||||
|
/>
|
||||||
|
<DeleteFilterTabDialog
|
||||||
|
open={params.action === "delete-search"}
|
||||||
|
confirmButtonState="default"
|
||||||
|
onClose={closeModal}
|
||||||
|
onSubmit={handleTabDelete}
|
||||||
|
tabName={maybe(() => tabs[currentTab - 1].name, "...")}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
31
src/customers/views/CustomerList/filter.ts
Normal file
31
src/customers/views/CustomerList/filter.ts
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
import { CustomerFilterInput } from "@saleor/types/globalTypes";
|
||||||
|
import {
|
||||||
|
createFilterTabUtils,
|
||||||
|
createFilterUtils
|
||||||
|
} from "../../../utils/filters";
|
||||||
|
import {
|
||||||
|
CustomerListUrlFilters,
|
||||||
|
CustomerListUrlFiltersEnum,
|
||||||
|
CustomerListUrlQueryParams
|
||||||
|
} from "../../urls";
|
||||||
|
|
||||||
|
export const CUSTOMER_FILTERS_KEY = "customerFilters";
|
||||||
|
|
||||||
|
export function getFilterVariables(
|
||||||
|
params: CustomerListUrlFilters
|
||||||
|
): CustomerFilterInput {
|
||||||
|
return {
|
||||||
|
search: params.query
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export const {
|
||||||
|
deleteFilterTab,
|
||||||
|
getFilterTabs,
|
||||||
|
saveFilterTab
|
||||||
|
} = createFilterTabUtils<CustomerListUrlFilters>(CUSTOMER_FILTERS_KEY);
|
||||||
|
|
||||||
|
export const { areFiltersApplied, getActiveFilters } = createFilterUtils<
|
||||||
|
CustomerListUrlQueryParams,
|
||||||
|
CustomerListUrlFilters
|
||||||
|
>(CustomerListUrlFiltersEnum);
|
2
src/customers/views/CustomerList/index.ts
Normal file
2
src/customers/views/CustomerList/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
export { default } from "./CustomerList";
|
||||||
|
export * from "./CustomerList";
|
|
@ -1,4 +1,3 @@
|
||||||
import Card from "@material-ui/core/Card";
|
|
||||||
import {
|
import {
|
||||||
createStyles,
|
createStyles,
|
||||||
Theme,
|
Theme,
|
||||||
|
@ -83,7 +82,6 @@ const SaleList = withStyles(styles, {
|
||||||
toggleAll,
|
toggleAll,
|
||||||
toolbar
|
toolbar
|
||||||
}: SaleListProps & WithStyles<typeof styles>) => (
|
}: SaleListProps & WithStyles<typeof styles>) => (
|
||||||
<Card>
|
|
||||||
<Table>
|
<Table>
|
||||||
<TableHead
|
<TableHead
|
||||||
colSpan={numberOfColumns}
|
colSpan={numberOfColumns}
|
||||||
|
@ -103,10 +101,7 @@ const SaleList = withStyles(styles, {
|
||||||
/>
|
/>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell className={classes.colEnd}>
|
<TableCell className={classes.colEnd}>
|
||||||
<FormattedMessage
|
<FormattedMessage defaultMessage="Ends" description="sale end date" />
|
||||||
defaultMessage="Ends"
|
|
||||||
description="sale end date"
|
|
||||||
/>
|
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell className={classes.colValue}>
|
<TableCell className={classes.colValue}>
|
||||||
<FormattedMessage defaultMessage="Value" description="sale value" />
|
<FormattedMessage defaultMessage="Value" description="sale value" />
|
||||||
|
@ -200,7 +195,6 @@ const SaleList = withStyles(styles, {
|
||||||
)}
|
)}
|
||||||
</TableBody>
|
</TableBody>
|
||||||
</Table>
|
</Table>
|
||||||
</Card>
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
SaleList.displayName = "SaleList";
|
SaleList.displayName = "SaleList";
|
||||||
|
|
|
@ -1,22 +1,40 @@
|
||||||
import Button from "@material-ui/core/Button";
|
import Button from "@material-ui/core/Button";
|
||||||
|
import Card from "@material-ui/core/Card";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
|
|
||||||
import Container from "@saleor/components/Container";
|
import Container from "@saleor/components/Container";
|
||||||
import PageHeader from "@saleor/components/PageHeader";
|
import PageHeader from "@saleor/components/PageHeader";
|
||||||
|
import SearchBar from "@saleor/components/SearchBar";
|
||||||
import { sectionNames } from "@saleor/intl";
|
import { sectionNames } from "@saleor/intl";
|
||||||
import { ListActions, PageListProps } from "@saleor/types";
|
import {
|
||||||
|
ListActions,
|
||||||
|
PageListProps,
|
||||||
|
SearchPageProps,
|
||||||
|
TabPageProps
|
||||||
|
} from "@saleor/types";
|
||||||
import { SaleList_sales_edges_node } from "../../types/SaleList";
|
import { SaleList_sales_edges_node } from "../../types/SaleList";
|
||||||
import SaleList from "../SaleList";
|
import SaleList from "../SaleList";
|
||||||
|
|
||||||
export interface SaleListPageProps extends PageListProps, ListActions {
|
export interface SaleListPageProps
|
||||||
|
extends PageListProps,
|
||||||
|
ListActions,
|
||||||
|
SearchPageProps,
|
||||||
|
TabPageProps {
|
||||||
defaultCurrency: string;
|
defaultCurrency: string;
|
||||||
sales: SaleList_sales_edges_node[];
|
sales: SaleList_sales_edges_node[];
|
||||||
}
|
}
|
||||||
|
|
||||||
const SaleListPage: React.StatelessComponent<SaleListPageProps> = ({
|
const SaleListPage: React.StatelessComponent<SaleListPageProps> = ({
|
||||||
|
currentTab,
|
||||||
|
initialSearch,
|
||||||
onAdd,
|
onAdd,
|
||||||
|
onAll,
|
||||||
|
onSearchChange,
|
||||||
|
onTabChange,
|
||||||
|
onTabDelete,
|
||||||
|
onTabSave,
|
||||||
|
tabs,
|
||||||
...listProps
|
...listProps
|
||||||
}) => {
|
}) => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
@ -28,7 +46,26 @@ const SaleListPage: React.StatelessComponent<SaleListPageProps> = ({
|
||||||
<FormattedMessage defaultMessage="Create Sale" description="button" />
|
<FormattedMessage defaultMessage="Create Sale" description="button" />
|
||||||
</Button>
|
</Button>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
|
<Card>
|
||||||
|
<SearchBar
|
||||||
|
allTabLabel={intl.formatMessage({
|
||||||
|
defaultMessage: "All Sales",
|
||||||
|
description: "tab name"
|
||||||
|
})}
|
||||||
|
currentTab={currentTab}
|
||||||
|
initialSearch={initialSearch}
|
||||||
|
searchPlaceholder={intl.formatMessage({
|
||||||
|
defaultMessage: "Search Sale"
|
||||||
|
})}
|
||||||
|
tabs={tabs}
|
||||||
|
onAll={onAll}
|
||||||
|
onSearchChange={onSearchChange}
|
||||||
|
onTabChange={onTabChange}
|
||||||
|
onTabDelete={onTabDelete}
|
||||||
|
onTabSave={onTabSave}
|
||||||
|
/>
|
||||||
<SaleList {...listProps} />
|
<SaleList {...listProps} />
|
||||||
|
</Card>
|
||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import Card from "@material-ui/core/Card";
|
|
||||||
import {
|
import {
|
||||||
createStyles,
|
createStyles,
|
||||||
Theme,
|
Theme,
|
||||||
|
@ -98,7 +97,6 @@ const VoucherList = withStyles(styles, {
|
||||||
toggleAll,
|
toggleAll,
|
||||||
toolbar
|
toolbar
|
||||||
}: VoucherListProps & WithStyles<typeof styles>) => (
|
}: VoucherListProps & WithStyles<typeof styles>) => (
|
||||||
<Card>
|
|
||||||
<Table>
|
<Table>
|
||||||
<TableHead
|
<TableHead
|
||||||
colSpan={numberOfColumns}
|
colSpan={numberOfColumns}
|
||||||
|
@ -109,10 +107,7 @@ const VoucherList = withStyles(styles, {
|
||||||
toolbar={toolbar}
|
toolbar={toolbar}
|
||||||
>
|
>
|
||||||
<TableCell className={classes.colName}>
|
<TableCell className={classes.colName}>
|
||||||
<FormattedMessage
|
<FormattedMessage defaultMessage="Code" description="voucher code" />
|
||||||
defaultMessage="Code"
|
|
||||||
description="voucher code"
|
|
||||||
/>
|
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell className={classes.colMinSpent}>
|
<TableCell className={classes.colMinSpent}>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
|
@ -139,10 +134,7 @@ const VoucherList = withStyles(styles, {
|
||||||
/>
|
/>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell className={classes.colUses}>
|
<TableCell className={classes.colUses}>
|
||||||
<FormattedMessage
|
<FormattedMessage defaultMessage="Uses" description="voucher uses" />
|
||||||
defaultMessage="Uses"
|
|
||||||
description="voucher uses"
|
|
||||||
/>
|
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableHead>
|
</TableHead>
|
||||||
<TableFooter>
|
<TableFooter>
|
||||||
|
@ -254,7 +246,6 @@ const VoucherList = withStyles(styles, {
|
||||||
)}
|
)}
|
||||||
</TableBody>
|
</TableBody>
|
||||||
</Table>
|
</Table>
|
||||||
</Card>
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
VoucherList.displayName = "VoucherList";
|
VoucherList.displayName = "VoucherList";
|
||||||
|
|
|
@ -1,36 +1,41 @@
|
||||||
import Button from "@material-ui/core/Button";
|
import Button from "@material-ui/core/Button";
|
||||||
|
import Card from "@material-ui/core/Card";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
|
|
||||||
import Container from "@saleor/components/Container";
|
import Container from "@saleor/components/Container";
|
||||||
import PageHeader from "@saleor/components/PageHeader";
|
import PageHeader from "@saleor/components/PageHeader";
|
||||||
|
import SearchBar from "@saleor/components/SearchBar";
|
||||||
import { sectionNames } from "@saleor/intl";
|
import { sectionNames } from "@saleor/intl";
|
||||||
import { ListActions, PageListProps } from "@saleor/types";
|
import {
|
||||||
|
ListActions,
|
||||||
|
PageListProps,
|
||||||
|
SearchPageProps,
|
||||||
|
TabPageProps
|
||||||
|
} from "@saleor/types";
|
||||||
import { VoucherList_vouchers_edges_node } from "../../types/VoucherList";
|
import { VoucherList_vouchers_edges_node } from "../../types/VoucherList";
|
||||||
import VoucherList from "../VoucherList";
|
import VoucherList from "../VoucherList";
|
||||||
|
|
||||||
export interface VoucherListPageProps extends PageListProps, ListActions {
|
export interface VoucherListPageProps
|
||||||
|
extends PageListProps,
|
||||||
|
ListActions,
|
||||||
|
SearchPageProps,
|
||||||
|
TabPageProps {
|
||||||
defaultCurrency: string;
|
defaultCurrency: string;
|
||||||
vouchers: VoucherList_vouchers_edges_node[];
|
vouchers: VoucherList_vouchers_edges_node[];
|
||||||
}
|
}
|
||||||
|
|
||||||
const VoucherListPage: React.StatelessComponent<VoucherListPageProps> = ({
|
const VoucherListPage: React.StatelessComponent<VoucherListPageProps> = ({
|
||||||
defaultCurrency,
|
currentTab,
|
||||||
disabled,
|
initialSearch,
|
||||||
settings,
|
|
||||||
onAdd,
|
onAdd,
|
||||||
onNextPage,
|
onAll,
|
||||||
onPreviousPage,
|
onSearchChange,
|
||||||
onUpdateListSettings,
|
onTabChange,
|
||||||
onRowClick,
|
onTabDelete,
|
||||||
pageInfo,
|
onTabSave,
|
||||||
vouchers,
|
tabs,
|
||||||
isChecked,
|
...listProps
|
||||||
selected,
|
|
||||||
toggle,
|
|
||||||
toggleAll,
|
|
||||||
toolbar
|
|
||||||
}) => {
|
}) => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
|
@ -44,22 +49,26 @@ const VoucherListPage: React.StatelessComponent<VoucherListPageProps> = ({
|
||||||
/>
|
/>
|
||||||
</Button>
|
</Button>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
<VoucherList
|
<Card>
|
||||||
defaultCurrency={defaultCurrency}
|
<SearchBar
|
||||||
settings={settings}
|
allTabLabel={intl.formatMessage({
|
||||||
disabled={disabled}
|
defaultMessage: "All Vouchers",
|
||||||
onNextPage={onNextPage}
|
description: "tab name"
|
||||||
onPreviousPage={onPreviousPage}
|
})}
|
||||||
onUpdateListSettings={onUpdateListSettings}
|
currentTab={currentTab}
|
||||||
onRowClick={onRowClick}
|
initialSearch={initialSearch}
|
||||||
pageInfo={pageInfo}
|
searchPlaceholder={intl.formatMessage({
|
||||||
vouchers={vouchers}
|
defaultMessage: "Search Voucher"
|
||||||
isChecked={isChecked}
|
})}
|
||||||
selected={selected}
|
tabs={tabs}
|
||||||
toggle={toggle}
|
onAll={onAll}
|
||||||
toggleAll={toggleAll}
|
onSearchChange={onSearchChange}
|
||||||
toolbar={toolbar}
|
onTabChange={onTabChange}
|
||||||
|
onTabDelete={onTabDelete}
|
||||||
|
onTabSave={onTabSave}
|
||||||
/>
|
/>
|
||||||
|
<VoucherList {...listProps} />
|
||||||
|
</Card>
|
||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -166,8 +166,20 @@ export const voucherDetailsFragment = gql`
|
||||||
export const saleList = gql`
|
export const saleList = gql`
|
||||||
${pageInfoFragment}
|
${pageInfoFragment}
|
||||||
${saleFragment}
|
${saleFragment}
|
||||||
query SaleList($after: String, $before: String, $first: Int, $last: Int) {
|
query SaleList(
|
||||||
sales(after: $after, before: $before, first: $first, last: $last) {
|
$after: String
|
||||||
|
$before: String
|
||||||
|
$first: Int
|
||||||
|
$last: Int
|
||||||
|
$filter: SaleFilterInput
|
||||||
|
) {
|
||||||
|
sales(
|
||||||
|
after: $after
|
||||||
|
before: $before
|
||||||
|
first: $first
|
||||||
|
last: $last
|
||||||
|
filter: $filter
|
||||||
|
) {
|
||||||
edges {
|
edges {
|
||||||
node {
|
node {
|
||||||
...SaleFragment
|
...SaleFragment
|
||||||
|
@ -184,8 +196,20 @@ export const TypedSaleList = TypedQuery<SaleList, SaleListVariables>(saleList);
|
||||||
export const voucherList = gql`
|
export const voucherList = gql`
|
||||||
${pageInfoFragment}
|
${pageInfoFragment}
|
||||||
${voucherFragment}
|
${voucherFragment}
|
||||||
query VoucherList($after: String, $before: String, $first: Int, $last: Int) {
|
query VoucherList(
|
||||||
vouchers(after: $after, before: $before, first: $first, last: $last) {
|
$after: String
|
||||||
|
$before: String
|
||||||
|
$first: Int
|
||||||
|
$last: Int
|
||||||
|
$filter: VoucherFilterInput
|
||||||
|
) {
|
||||||
|
vouchers(
|
||||||
|
after: $after
|
||||||
|
before: $before
|
||||||
|
first: $first
|
||||||
|
last: $last
|
||||||
|
filter: $filter
|
||||||
|
) {
|
||||||
edges {
|
edges {
|
||||||
node {
|
node {
|
||||||
...VoucherFragment
|
...VoucherFragment
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
// This file was automatically generated and should not be edited.
|
// This file was automatically generated and should not be edited.
|
||||||
|
|
||||||
import { SaleType } from "./../../types/globalTypes";
|
import { SaleFilterInput, SaleType } from "./../../types/globalTypes";
|
||||||
|
|
||||||
// ====================================================
|
// ====================================================
|
||||||
// GraphQL query operation: SaleList
|
// GraphQL query operation: SaleList
|
||||||
|
@ -46,4 +46,5 @@ export interface SaleListVariables {
|
||||||
before?: string | null;
|
before?: string | null;
|
||||||
first?: number | null;
|
first?: number | null;
|
||||||
last?: number | null;
|
last?: number | null;
|
||||||
|
filter?: SaleFilterInput | null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
// This file was automatically generated and should not be edited.
|
// This file was automatically generated and should not be edited.
|
||||||
|
|
||||||
import { DiscountValueTypeEnum } from "./../../types/globalTypes";
|
import { VoucherFilterInput, DiscountValueTypeEnum } from "./../../types/globalTypes";
|
||||||
|
|
||||||
// ====================================================
|
// ====================================================
|
||||||
// GraphQL query operation: VoucherList
|
// GraphQL query operation: VoucherList
|
||||||
|
@ -62,4 +62,5 @@ export interface VoucherListVariables {
|
||||||
before?: string | null;
|
before?: string | null;
|
||||||
first?: number | null;
|
first?: number | null;
|
||||||
last?: number | null;
|
last?: number | null;
|
||||||
|
filter?: VoucherFilterInput | null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,14 @@
|
||||||
import { stringify as stringifyQs } from "qs";
|
import { stringify as stringifyQs } from "qs";
|
||||||
import urlJoin from "url-join";
|
import urlJoin from "url-join";
|
||||||
|
|
||||||
import { ActiveTab, BulkAction, Dialog, Pagination } from "../types";
|
import {
|
||||||
|
ActiveTab,
|
||||||
|
BulkAction,
|
||||||
|
Dialog,
|
||||||
|
Filters,
|
||||||
|
Pagination,
|
||||||
|
TabActionDialog
|
||||||
|
} from "../types";
|
||||||
import { SaleDetailsPageTab } from "./components/SaleDetailsPage";
|
import { SaleDetailsPageTab } from "./components/SaleDetailsPage";
|
||||||
import { VoucherDetailsPageTab } from "./components/VoucherDetailsPage";
|
import { VoucherDetailsPageTab } from "./components/VoucherDetailsPage";
|
||||||
|
|
||||||
|
@ -9,10 +16,16 @@ export const discountSection = "/discounts/";
|
||||||
|
|
||||||
export const saleSection = urlJoin(discountSection, "sales");
|
export const saleSection = urlJoin(discountSection, "sales");
|
||||||
export const saleListPath = saleSection;
|
export const saleListPath = saleSection;
|
||||||
export type SaleListUrlDialog = "remove";
|
export enum SaleListUrlFiltersEnum {
|
||||||
export type SaleListUrlQueryParams = BulkAction &
|
query = "query"
|
||||||
|
}
|
||||||
|
export type SaleListUrlFilters = Filters<SaleListUrlFiltersEnum>;
|
||||||
|
export type SaleListUrlDialog = "remove" | TabActionDialog;
|
||||||
|
export type SaleListUrlQueryParams = ActiveTab &
|
||||||
|
BulkAction &
|
||||||
Dialog<SaleListUrlDialog> &
|
Dialog<SaleListUrlDialog> &
|
||||||
Pagination;
|
Pagination &
|
||||||
|
SaleListUrlFilters;
|
||||||
export const saleListUrl = (params?: SaleListUrlQueryParams) =>
|
export const saleListUrl = (params?: SaleListUrlQueryParams) =>
|
||||||
saleListPath + "?" + stringifyQs(params);
|
saleListPath + "?" + stringifyQs(params);
|
||||||
export const salePath = (id: string) => urlJoin(saleSection, id);
|
export const salePath = (id: string) => urlJoin(saleSection, id);
|
||||||
|
@ -35,10 +48,16 @@ export const saleAddUrl = saleAddPath;
|
||||||
|
|
||||||
export const voucherSection = urlJoin(discountSection, "vouchers");
|
export const voucherSection = urlJoin(discountSection, "vouchers");
|
||||||
export const voucherListPath = voucherSection;
|
export const voucherListPath = voucherSection;
|
||||||
export type VoucherListUrlDialog = "remove";
|
export enum VoucherListUrlFiltersEnum {
|
||||||
export type VoucherListUrlQueryParams = BulkAction &
|
query = "query"
|
||||||
|
}
|
||||||
|
export type VoucherListUrlFilters = Filters<VoucherListUrlFiltersEnum>;
|
||||||
|
export type VoucherListUrlDialog = "remove" | TabActionDialog;
|
||||||
|
export type VoucherListUrlQueryParams = ActiveTab &
|
||||||
|
BulkAction &
|
||||||
Dialog<VoucherListUrlDialog> &
|
Dialog<VoucherListUrlDialog> &
|
||||||
Pagination;
|
Pagination &
|
||||||
|
VoucherListUrlFilters;
|
||||||
export const voucherListUrl = (params?: VoucherListUrlQueryParams) =>
|
export const voucherListUrl = (params?: VoucherListUrlQueryParams) =>
|
||||||
voucherListPath + "?" + stringifyQs(params);
|
voucherListPath + "?" + stringifyQs(params);
|
||||||
export const voucherPath = (id: string) => urlJoin(voucherSection, id);
|
export const voucherPath = (id: string) => urlJoin(voucherSection, id);
|
||||||
|
|
|
@ -5,6 +5,10 @@ import React from "react";
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
|
|
||||||
import ActionDialog from "@saleor/components/ActionDialog";
|
import ActionDialog from "@saleor/components/ActionDialog";
|
||||||
|
import DeleteFilterTabDialog from "@saleor/components/DeleteFilterTabDialog";
|
||||||
|
import SaveFilterTabDialog, {
|
||||||
|
SaveFilterTabDialogFormData
|
||||||
|
} from "@saleor/components/SaveFilterTabDialog";
|
||||||
import { WindowTitle } from "@saleor/components/WindowTitle";
|
import { WindowTitle } from "@saleor/components/WindowTitle";
|
||||||
import useBulkActions from "@saleor/hooks/useBulkActions";
|
import useBulkActions from "@saleor/hooks/useBulkActions";
|
||||||
import useListSettings from "@saleor/hooks/useListSettings";
|
import useListSettings from "@saleor/hooks/useListSettings";
|
||||||
|
@ -17,16 +21,26 @@ import useShop from "@saleor/hooks/useShop";
|
||||||
import { commonMessages, sectionNames } from "@saleor/intl";
|
import { commonMessages, sectionNames } from "@saleor/intl";
|
||||||
import { getMutationState, maybe } from "@saleor/misc";
|
import { getMutationState, maybe } from "@saleor/misc";
|
||||||
import { ListViews } from "@saleor/types";
|
import { ListViews } from "@saleor/types";
|
||||||
import SaleListPage from "../components/SaleListPage";
|
import SaleListPage from "../../components/SaleListPage";
|
||||||
import { TypedSaleBulkDelete } from "../mutations";
|
import { TypedSaleBulkDelete } from "../../mutations";
|
||||||
import { TypedSaleList } from "../queries";
|
import { TypedSaleList } from "../../queries";
|
||||||
import { SaleBulkDelete } from "../types/SaleBulkDelete";
|
import { SaleBulkDelete } from "../../types/SaleBulkDelete";
|
||||||
import {
|
import {
|
||||||
saleAddUrl,
|
saleAddUrl,
|
||||||
saleListUrl,
|
saleListUrl,
|
||||||
|
SaleListUrlDialog,
|
||||||
|
SaleListUrlFilters,
|
||||||
SaleListUrlQueryParams,
|
SaleListUrlQueryParams,
|
||||||
saleUrl
|
saleUrl
|
||||||
} from "../urls";
|
} from "../../urls";
|
||||||
|
import {
|
||||||
|
areFiltersApplied,
|
||||||
|
deleteFilterTab,
|
||||||
|
getActiveFilters,
|
||||||
|
getFilterTabs,
|
||||||
|
getFilterVariables,
|
||||||
|
saveFilterTab
|
||||||
|
} from "./filter";
|
||||||
|
|
||||||
interface SaleListProps {
|
interface SaleListProps {
|
||||||
params: SaleListUrlQueryParams;
|
params: SaleListUrlQueryParams;
|
||||||
|
@ -47,13 +61,79 @@ export const SaleList: React.StatelessComponent<SaleListProps> = ({
|
||||||
);
|
);
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
const closeModal = () => navigate(saleListUrl(), true);
|
const tabs = getFilterTabs();
|
||||||
|
|
||||||
|
const currentTab =
|
||||||
|
params.activeTab === undefined
|
||||||
|
? areFiltersApplied(params)
|
||||||
|
? tabs.length + 1
|
||||||
|
: 0
|
||||||
|
: parseInt(params.activeTab, 0);
|
||||||
|
|
||||||
|
const changeFilterField = (filter: SaleListUrlFilters) => {
|
||||||
|
reset();
|
||||||
|
navigate(
|
||||||
|
saleListUrl({
|
||||||
|
...getActiveFilters(params),
|
||||||
|
...filter,
|
||||||
|
activeTab: undefined
|
||||||
|
})
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const closeModal = () =>
|
||||||
|
navigate(
|
||||||
|
saleListUrl({
|
||||||
|
...params,
|
||||||
|
action: undefined,
|
||||||
|
ids: undefined
|
||||||
|
}),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
const openModal = (action: SaleListUrlDialog, ids?: string[]) =>
|
||||||
|
navigate(
|
||||||
|
saleListUrl({
|
||||||
|
...params,
|
||||||
|
action,
|
||||||
|
ids
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleTabChange = (tab: number) => {
|
||||||
|
reset();
|
||||||
|
navigate(
|
||||||
|
saleListUrl({
|
||||||
|
activeTab: tab.toString(),
|
||||||
|
...getFilterTabs()[tab - 1].data
|
||||||
|
})
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleTabDelete = () => {
|
||||||
|
deleteFilterTab(currentTab);
|
||||||
|
reset();
|
||||||
|
navigate(saleListUrl());
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleTabSave = (data: SaveFilterTabDialogFormData) => {
|
||||||
|
saveFilterTab(data.name, getActiveFilters(params));
|
||||||
|
handleTabChange(tabs.length + 1);
|
||||||
|
};
|
||||||
|
|
||||||
const paginationState = createPaginationState(settings.rowNumber, params);
|
const paginationState = createPaginationState(settings.rowNumber, params);
|
||||||
|
const queryVariables = React.useMemo(
|
||||||
|
() => ({
|
||||||
|
...paginationState,
|
||||||
|
filter: getFilterVariables(params)
|
||||||
|
}),
|
||||||
|
[params]
|
||||||
|
);
|
||||||
|
|
||||||
const canOpenBulkActionDialog = maybe(() => params.ids.length > 0);
|
const canOpenBulkActionDialog = maybe(() => params.ids.length > 0);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TypedSaleList displayLoader variables={paginationState}>
|
<TypedSaleList displayLoader variables={queryVariables}>
|
||||||
{({ data, loading, refetch }) => {
|
{({ data, loading, refetch }) => {
|
||||||
const { loadNextPage, loadPreviousPage, pageInfo } = paginate(
|
const { loadNextPage, loadPreviousPage, pageInfo } = paginate(
|
||||||
maybe(() => data.sales.pageInfo),
|
maybe(() => data.sales.pageInfo),
|
||||||
|
@ -91,6 +171,14 @@ export const SaleList: React.StatelessComponent<SaleListProps> = ({
|
||||||
<>
|
<>
|
||||||
<WindowTitle title={intl.formatMessage(sectionNames.sales)} />
|
<WindowTitle title={intl.formatMessage(sectionNames.sales)} />
|
||||||
<SaleListPage
|
<SaleListPage
|
||||||
|
currentTab={currentTab}
|
||||||
|
initialSearch={params.query || ""}
|
||||||
|
onSearchChange={query => changeFilterField({ query })}
|
||||||
|
onAll={() => navigate(saleListUrl())}
|
||||||
|
onTabChange={handleTabChange}
|
||||||
|
onTabDelete={() => openModal("delete-search")}
|
||||||
|
onTabSave={() => openModal("save-search")}
|
||||||
|
tabs={tabs.map(tab => tab.name)}
|
||||||
defaultCurrency={maybe(() => shop.defaultCurrency)}
|
defaultCurrency={maybe(() => shop.defaultCurrency)}
|
||||||
sales={maybe(() => data.sales.edges.map(edge => edge.node))}
|
sales={maybe(() => data.sales.edges.map(edge => edge.node))}
|
||||||
settings={settings}
|
settings={settings}
|
||||||
|
@ -150,6 +238,19 @@ export const SaleList: React.StatelessComponent<SaleListProps> = ({
|
||||||
</DialogContentText>
|
</DialogContentText>
|
||||||
)}
|
)}
|
||||||
</ActionDialog>
|
</ActionDialog>
|
||||||
|
<SaveFilterTabDialog
|
||||||
|
open={params.action === "save-search"}
|
||||||
|
confirmButtonState="default"
|
||||||
|
onClose={closeModal}
|
||||||
|
onSubmit={handleTabSave}
|
||||||
|
/>
|
||||||
|
<DeleteFilterTabDialog
|
||||||
|
open={params.action === "delete-search"}
|
||||||
|
confirmButtonState="default"
|
||||||
|
onClose={closeModal}
|
||||||
|
onSubmit={handleTabDelete}
|
||||||
|
tabName={maybe(() => tabs[currentTab - 1].name, "...")}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
31
src/discounts/views/SaleList/filter.ts
Normal file
31
src/discounts/views/SaleList/filter.ts
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
import { SaleFilterInput } from "@saleor/types/globalTypes";
|
||||||
|
import {
|
||||||
|
createFilterTabUtils,
|
||||||
|
createFilterUtils
|
||||||
|
} from "../../../utils/filters";
|
||||||
|
import {
|
||||||
|
SaleListUrlFilters,
|
||||||
|
SaleListUrlFiltersEnum,
|
||||||
|
SaleListUrlQueryParams
|
||||||
|
} from "../../urls";
|
||||||
|
|
||||||
|
export const SALE_FILTERS_KEY = "saleFilters";
|
||||||
|
|
||||||
|
export function getFilterVariables(
|
||||||
|
params: SaleListUrlFilters
|
||||||
|
): SaleFilterInput {
|
||||||
|
return {
|
||||||
|
search: params.query
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export const {
|
||||||
|
deleteFilterTab,
|
||||||
|
getFilterTabs,
|
||||||
|
saveFilterTab
|
||||||
|
} = createFilterTabUtils<SaleListUrlFilters>(SALE_FILTERS_KEY);
|
||||||
|
|
||||||
|
export const { areFiltersApplied, getActiveFilters } = createFilterUtils<
|
||||||
|
SaleListUrlQueryParams,
|
||||||
|
SaleListUrlFilters
|
||||||
|
>(SaleListUrlFiltersEnum);
|
2
src/discounts/views/SaleList/index.ts
Normal file
2
src/discounts/views/SaleList/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
export { default } from "./SaleList";
|
||||||
|
export * from "./SaleList";
|
|
@ -5,6 +5,10 @@ import React from "react";
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
|
|
||||||
import ActionDialog from "@saleor/components/ActionDialog";
|
import ActionDialog from "@saleor/components/ActionDialog";
|
||||||
|
import DeleteFilterTabDialog from "@saleor/components/DeleteFilterTabDialog";
|
||||||
|
import SaveFilterTabDialog, {
|
||||||
|
SaveFilterTabDialogFormData
|
||||||
|
} from "@saleor/components/SaveFilterTabDialog";
|
||||||
import { WindowTitle } from "@saleor/components/WindowTitle";
|
import { WindowTitle } from "@saleor/components/WindowTitle";
|
||||||
import useBulkActions from "@saleor/hooks/useBulkActions";
|
import useBulkActions from "@saleor/hooks/useBulkActions";
|
||||||
import useListSettings from "@saleor/hooks/useListSettings";
|
import useListSettings from "@saleor/hooks/useListSettings";
|
||||||
|
@ -17,16 +21,26 @@ import useShop from "@saleor/hooks/useShop";
|
||||||
import { commonMessages, sectionNames } from "@saleor/intl";
|
import { commonMessages, sectionNames } from "@saleor/intl";
|
||||||
import { getMutationState, maybe } from "@saleor/misc";
|
import { getMutationState, maybe } from "@saleor/misc";
|
||||||
import { ListViews } from "@saleor/types";
|
import { ListViews } from "@saleor/types";
|
||||||
import VoucherListPage from "../components/VoucherListPage";
|
import VoucherListPage from "../../components/VoucherListPage";
|
||||||
import { TypedVoucherBulkDelete } from "../mutations";
|
import { TypedVoucherBulkDelete } from "../../mutations";
|
||||||
import { TypedVoucherList } from "../queries";
|
import { TypedVoucherList } from "../../queries";
|
||||||
import { VoucherBulkDelete } from "../types/VoucherBulkDelete";
|
import { VoucherBulkDelete } from "../../types/VoucherBulkDelete";
|
||||||
import {
|
import {
|
||||||
voucherAddUrl,
|
voucherAddUrl,
|
||||||
voucherListUrl,
|
voucherListUrl,
|
||||||
|
VoucherListUrlDialog,
|
||||||
|
VoucherListUrlFilters,
|
||||||
VoucherListUrlQueryParams,
|
VoucherListUrlQueryParams,
|
||||||
voucherUrl
|
voucherUrl
|
||||||
} from "../urls";
|
} from "../../urls";
|
||||||
|
import {
|
||||||
|
areFiltersApplied,
|
||||||
|
deleteFilterTab,
|
||||||
|
getActiveFilters,
|
||||||
|
getFilterTabs,
|
||||||
|
getFilterVariables,
|
||||||
|
saveFilterTab
|
||||||
|
} from "./filter";
|
||||||
|
|
||||||
interface VoucherListProps {
|
interface VoucherListProps {
|
||||||
params: VoucherListUrlQueryParams;
|
params: VoucherListUrlQueryParams;
|
||||||
|
@ -47,13 +61,79 @@ export const VoucherList: React.StatelessComponent<VoucherListProps> = ({
|
||||||
);
|
);
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
const closeModal = () => navigate(voucherListUrl(), true);
|
const tabs = getFilterTabs();
|
||||||
|
|
||||||
|
const currentTab =
|
||||||
|
params.activeTab === undefined
|
||||||
|
? areFiltersApplied(params)
|
||||||
|
? tabs.length + 1
|
||||||
|
: 0
|
||||||
|
: parseInt(params.activeTab, 0);
|
||||||
|
|
||||||
|
const changeFilterField = (filter: VoucherListUrlFilters) => {
|
||||||
|
reset();
|
||||||
|
navigate(
|
||||||
|
voucherListUrl({
|
||||||
|
...getActiveFilters(params),
|
||||||
|
...filter,
|
||||||
|
activeTab: undefined
|
||||||
|
})
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const closeModal = () =>
|
||||||
|
navigate(
|
||||||
|
voucherListUrl({
|
||||||
|
...params,
|
||||||
|
action: undefined,
|
||||||
|
ids: undefined
|
||||||
|
}),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
const openModal = (action: VoucherListUrlDialog, ids?: string[]) =>
|
||||||
|
navigate(
|
||||||
|
voucherListUrl({
|
||||||
|
...params,
|
||||||
|
action,
|
||||||
|
ids
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleTabChange = (tab: number) => {
|
||||||
|
reset();
|
||||||
|
navigate(
|
||||||
|
voucherListUrl({
|
||||||
|
activeTab: tab.toString(),
|
||||||
|
...getFilterTabs()[tab - 1].data
|
||||||
|
})
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleTabDelete = () => {
|
||||||
|
deleteFilterTab(currentTab);
|
||||||
|
reset();
|
||||||
|
navigate(voucherListUrl());
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleTabSave = (data: SaveFilterTabDialogFormData) => {
|
||||||
|
saveFilterTab(data.name, getActiveFilters(params));
|
||||||
|
handleTabChange(tabs.length + 1);
|
||||||
|
};
|
||||||
|
|
||||||
const paginationState = createPaginationState(settings.rowNumber, params);
|
const paginationState = createPaginationState(settings.rowNumber, params);
|
||||||
|
const queryVariables = React.useMemo(
|
||||||
|
() => ({
|
||||||
|
...paginationState,
|
||||||
|
filter: getFilterVariables(params)
|
||||||
|
}),
|
||||||
|
[params]
|
||||||
|
);
|
||||||
|
|
||||||
const canOpenBulkActionDialog = maybe(() => params.ids.length > 0);
|
const canOpenBulkActionDialog = maybe(() => params.ids.length > 0);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TypedVoucherList displayLoader variables={paginationState}>
|
<TypedVoucherList displayLoader variables={queryVariables}>
|
||||||
{({ data, loading, refetch }) => {
|
{({ data, loading, refetch }) => {
|
||||||
const { loadNextPage, loadPreviousPage, pageInfo } = paginate(
|
const { loadNextPage, loadPreviousPage, pageInfo } = paginate(
|
||||||
maybe(() => data.vouchers.pageInfo),
|
maybe(() => data.vouchers.pageInfo),
|
||||||
|
@ -92,6 +172,14 @@ export const VoucherList: React.StatelessComponent<VoucherListProps> = ({
|
||||||
title={intl.formatMessage(sectionNames.vouchers)}
|
title={intl.formatMessage(sectionNames.vouchers)}
|
||||||
/>
|
/>
|
||||||
<VoucherListPage
|
<VoucherListPage
|
||||||
|
currentTab={currentTab}
|
||||||
|
initialSearch={params.query || ""}
|
||||||
|
onSearchChange={query => changeFilterField({ query })}
|
||||||
|
onAll={() => navigate(voucherListUrl())}
|
||||||
|
onTabChange={handleTabChange}
|
||||||
|
onTabDelete={() => openModal("delete-search")}
|
||||||
|
onTabSave={() => openModal("save-search")}
|
||||||
|
tabs={tabs.map(tab => tab.name)}
|
||||||
defaultCurrency={maybe(() => shop.defaultCurrency)}
|
defaultCurrency={maybe(() => shop.defaultCurrency)}
|
||||||
settings={settings}
|
settings={settings}
|
||||||
vouchers={maybe(() =>
|
vouchers={maybe(() =>
|
||||||
|
@ -153,6 +241,19 @@ export const VoucherList: React.StatelessComponent<VoucherListProps> = ({
|
||||||
</DialogContentText>
|
</DialogContentText>
|
||||||
)}
|
)}
|
||||||
</ActionDialog>
|
</ActionDialog>
|
||||||
|
<SaveFilterTabDialog
|
||||||
|
open={params.action === "save-search"}
|
||||||
|
confirmButtonState="default"
|
||||||
|
onClose={closeModal}
|
||||||
|
onSubmit={handleTabSave}
|
||||||
|
/>
|
||||||
|
<DeleteFilterTabDialog
|
||||||
|
open={params.action === "delete-search"}
|
||||||
|
confirmButtonState="default"
|
||||||
|
onClose={closeModal}
|
||||||
|
onSubmit={handleTabDelete}
|
||||||
|
tabName={maybe(() => tabs[currentTab - 1].name, "...")}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
31
src/discounts/views/VoucherList/filter.ts
Normal file
31
src/discounts/views/VoucherList/filter.ts
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
import { VoucherFilterInput } from "@saleor/types/globalTypes";
|
||||||
|
import {
|
||||||
|
createFilterTabUtils,
|
||||||
|
createFilterUtils
|
||||||
|
} from "../../../utils/filters";
|
||||||
|
import {
|
||||||
|
VoucherListUrlFilters,
|
||||||
|
VoucherListUrlFiltersEnum,
|
||||||
|
VoucherListUrlQueryParams
|
||||||
|
} from "../../urls";
|
||||||
|
|
||||||
|
export const VOUCHER_FILTERS_KEY = "VoucherFilters";
|
||||||
|
|
||||||
|
export function getFilterVariables(
|
||||||
|
params: VoucherListUrlFilters
|
||||||
|
): VoucherFilterInput {
|
||||||
|
return {
|
||||||
|
search: params.query
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export const {
|
||||||
|
deleteFilterTab,
|
||||||
|
getFilterTabs,
|
||||||
|
saveFilterTab
|
||||||
|
} = createFilterTabUtils<VoucherListUrlFilters>(VOUCHER_FILTERS_KEY);
|
||||||
|
|
||||||
|
export const { areFiltersApplied, getActiveFilters } = createFilterUtils<
|
||||||
|
VoucherListUrlQueryParams,
|
||||||
|
VoucherListUrlFilters
|
||||||
|
>(VoucherListUrlFiltersEnum);
|
2
src/discounts/views/VoucherList/index.ts
Normal file
2
src/discounts/views/VoucherList/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
export { default } from "./VoucherList";
|
||||||
|
export * from "./VoucherList";
|
|
@ -3,7 +3,9 @@ import {
|
||||||
FetchMoreProps,
|
FetchMoreProps,
|
||||||
FilterPageProps,
|
FilterPageProps,
|
||||||
ListActions,
|
ListActions,
|
||||||
PageListProps
|
PageListProps,
|
||||||
|
SearchPageProps,
|
||||||
|
TabPageProps
|
||||||
} from "./types";
|
} from "./types";
|
||||||
|
|
||||||
const pageInfo = {
|
const pageInfo = {
|
||||||
|
@ -46,23 +48,26 @@ export const countries = [
|
||||||
{ code: "AS", label: "American Samoa" }
|
{ code: "AS", label: "American Samoa" }
|
||||||
];
|
];
|
||||||
|
|
||||||
export const filterPageProps: FilterPageProps<{}, unknown> = {
|
export const tabPageProps: TabPageProps = {
|
||||||
currencySymbol: "USD",
|
|
||||||
currentTab: 0,
|
currentTab: 0,
|
||||||
filterTabs: [
|
|
||||||
{
|
|
||||||
data: {},
|
|
||||||
name: "Tab X"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
filtersList: [],
|
|
||||||
initialSearch: "",
|
|
||||||
onAll: () => undefined,
|
onAll: () => undefined,
|
||||||
onFilterAdd: () => undefined,
|
onTabChange: () => undefined,
|
||||||
onFilterDelete: () => undefined,
|
onTabDelete: () => undefined,
|
||||||
onFilterSave: () => undefined,
|
onTabSave: () => undefined,
|
||||||
onSearchChange: () => undefined,
|
tabs: ["Tab X"]
|
||||||
onTabChange: () => undefined
|
};
|
||||||
|
|
||||||
|
export const searchPageProps: SearchPageProps = {
|
||||||
|
initialSearch: "",
|
||||||
|
onSearchChange: () => undefined
|
||||||
|
};
|
||||||
|
|
||||||
|
export const filterPageProps: FilterPageProps = {
|
||||||
|
...searchPageProps,
|
||||||
|
...tabPageProps,
|
||||||
|
currencySymbol: "USD",
|
||||||
|
filtersList: [],
|
||||||
|
onFilterAdd: () => undefined
|
||||||
};
|
};
|
||||||
|
|
||||||
export const filters: Filter[] = [
|
export const filters: Filter[] = [
|
||||||
|
|
|
@ -6,18 +6,36 @@ import { FormattedMessage, useIntl } from "react-intl";
|
||||||
|
|
||||||
import Container from "@saleor/components/Container";
|
import Container from "@saleor/components/Container";
|
||||||
import PageHeader from "@saleor/components/PageHeader";
|
import PageHeader from "@saleor/components/PageHeader";
|
||||||
|
import SearchBar from "@saleor/components/SearchBar";
|
||||||
import { sectionNames } from "@saleor/intl";
|
import { sectionNames } from "@saleor/intl";
|
||||||
import { ListActions, PageListProps } from "@saleor/types";
|
import {
|
||||||
|
ListActions,
|
||||||
|
PageListProps,
|
||||||
|
SearchPageProps,
|
||||||
|
TabPageProps
|
||||||
|
} from "@saleor/types";
|
||||||
import { OrderDraftList_draftOrders_edges_node } from "../../types/OrderDraftList";
|
import { OrderDraftList_draftOrders_edges_node } from "../../types/OrderDraftList";
|
||||||
import OrderDraftList from "../OrderDraftList";
|
import OrderDraftList from "../OrderDraftList";
|
||||||
|
|
||||||
export interface OrderDraftListPageProps extends PageListProps, ListActions {
|
export interface OrderDraftListPageProps
|
||||||
|
extends PageListProps,
|
||||||
|
ListActions,
|
||||||
|
SearchPageProps,
|
||||||
|
TabPageProps {
|
||||||
orders: OrderDraftList_draftOrders_edges_node[];
|
orders: OrderDraftList_draftOrders_edges_node[];
|
||||||
}
|
}
|
||||||
|
|
||||||
const OrderDraftListPage: React.StatelessComponent<OrderDraftListPageProps> = ({
|
const OrderDraftListPage: React.StatelessComponent<OrderDraftListPageProps> = ({
|
||||||
|
currentTab,
|
||||||
disabled,
|
disabled,
|
||||||
|
initialSearch,
|
||||||
onAdd,
|
onAdd,
|
||||||
|
onAll,
|
||||||
|
onSearchChange,
|
||||||
|
onTabChange,
|
||||||
|
onTabDelete,
|
||||||
|
onTabSave,
|
||||||
|
tabs,
|
||||||
...listProps
|
...listProps
|
||||||
}) => {
|
}) => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
@ -38,6 +56,23 @@ const OrderDraftListPage: React.StatelessComponent<OrderDraftListPageProps> = ({
|
||||||
</Button>
|
</Button>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
<Card>
|
<Card>
|
||||||
|
<SearchBar
|
||||||
|
allTabLabel={intl.formatMessage({
|
||||||
|
defaultMessage: "All Drafts",
|
||||||
|
description: "tab name"
|
||||||
|
})}
|
||||||
|
currentTab={currentTab}
|
||||||
|
initialSearch={initialSearch}
|
||||||
|
searchPlaceholder={intl.formatMessage({
|
||||||
|
defaultMessage: "Search Draft"
|
||||||
|
})}
|
||||||
|
tabs={tabs}
|
||||||
|
onAll={onAll}
|
||||||
|
onSearchChange={onSearchChange}
|
||||||
|
onTabChange={onTabChange}
|
||||||
|
onTabDelete={onTabDelete}
|
||||||
|
onTabSave={onTabSave}
|
||||||
|
/>
|
||||||
<OrderDraftList disabled={disabled} {...listProps} />
|
<OrderDraftList disabled={disabled} {...listProps} />
|
||||||
</Card>
|
</Card>
|
||||||
</Container>
|
</Container>
|
||||||
|
|
|
@ -8,9 +8,8 @@ import FilterBar from "@saleor/components/FilterBar";
|
||||||
import TimezoneContext from "@saleor/components/Timezone";
|
import TimezoneContext from "@saleor/components/Timezone";
|
||||||
import { FilterProps } from "../../../types";
|
import { FilterProps } from "../../../types";
|
||||||
import { OrderStatusFilter } from "../../../types/globalTypes";
|
import { OrderStatusFilter } from "../../../types/globalTypes";
|
||||||
import { OrderListUrlFilters } from "../../urls";
|
|
||||||
|
|
||||||
type OrderListFilterProps = FilterProps<OrderListUrlFilters, OrderFilterKeys>;
|
type OrderListFilterProps = FilterProps<OrderFilterKeys>;
|
||||||
|
|
||||||
export enum OrderFilterKeys {
|
export enum OrderFilterKeys {
|
||||||
date = "date",
|
date = "date",
|
||||||
|
|
|
@ -7,17 +7,15 @@ import { FormattedMessage, useIntl } from "react-intl";
|
||||||
import Container from "@saleor/components/Container";
|
import Container from "@saleor/components/Container";
|
||||||
import PageHeader from "@saleor/components/PageHeader";
|
import PageHeader from "@saleor/components/PageHeader";
|
||||||
import { sectionNames } from "@saleor/intl";
|
import { sectionNames } from "@saleor/intl";
|
||||||
import { OrderFilterKeys } from "@saleor/orders/components/OrderListFilter";
|
|
||||||
import { FilterPageProps, ListActions, PageListProps } from "@saleor/types";
|
import { FilterPageProps, ListActions, PageListProps } from "@saleor/types";
|
||||||
import { OrderList_orders_edges_node } from "../../types/OrderList";
|
import { OrderList_orders_edges_node } from "../../types/OrderList";
|
||||||
import { OrderListUrlFilters } from "../../urls";
|
|
||||||
import OrderList from "../OrderList";
|
import OrderList from "../OrderList";
|
||||||
import OrderListFilter from "../OrderListFilter";
|
import OrderListFilter, { OrderFilterKeys } from "../OrderListFilter";
|
||||||
|
|
||||||
export interface OrderListPageProps
|
export interface OrderListPageProps
|
||||||
extends PageListProps,
|
extends PageListProps,
|
||||||
ListActions,
|
ListActions,
|
||||||
FilterPageProps<OrderListUrlFilters, OrderFilterKeys> {
|
FilterPageProps<OrderFilterKeys> {
|
||||||
orders: OrderList_orders_edges_node[];
|
orders: OrderList_orders_edges_node[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,15 +23,15 @@ const OrderListPage: React.FC<OrderListPageProps> = ({
|
||||||
currencySymbol,
|
currencySymbol,
|
||||||
currentTab,
|
currentTab,
|
||||||
filtersList,
|
filtersList,
|
||||||
filterTabs,
|
|
||||||
initialSearch,
|
initialSearch,
|
||||||
|
tabs,
|
||||||
onAdd,
|
onAdd,
|
||||||
onAll,
|
onAll,
|
||||||
onSearchChange,
|
onSearchChange,
|
||||||
onFilterAdd,
|
onFilterAdd,
|
||||||
onFilterSave,
|
|
||||||
onTabChange,
|
onTabChange,
|
||||||
onFilterDelete,
|
onTabDelete,
|
||||||
|
onTabSave,
|
||||||
...listProps
|
...listProps
|
||||||
}) => {
|
}) => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
@ -59,7 +57,7 @@ const OrderListPage: React.FC<OrderListPageProps> = ({
|
||||||
filterLabel={intl.formatMessage({
|
filterLabel={intl.formatMessage({
|
||||||
defaultMessage: "Select all orders where:"
|
defaultMessage: "Select all orders where:"
|
||||||
})}
|
})}
|
||||||
filterTabs={filterTabs}
|
tabs={tabs}
|
||||||
filtersList={filtersList}
|
filtersList={filtersList}
|
||||||
initialSearch={initialSearch}
|
initialSearch={initialSearch}
|
||||||
searchPlaceholder={intl.formatMessage({
|
searchPlaceholder={intl.formatMessage({
|
||||||
|
@ -68,9 +66,9 @@ const OrderListPage: React.FC<OrderListPageProps> = ({
|
||||||
onAll={onAll}
|
onAll={onAll}
|
||||||
onSearchChange={onSearchChange}
|
onSearchChange={onSearchChange}
|
||||||
onFilterAdd={onFilterAdd}
|
onFilterAdd={onFilterAdd}
|
||||||
onFilterSave={onFilterSave}
|
|
||||||
onTabChange={onTabChange}
|
onTabChange={onTabChange}
|
||||||
onFilterDelete={onFilterDelete}
|
onTabDelete={onTabDelete}
|
||||||
|
onTabSave={onTabSave}
|
||||||
/>
|
/>
|
||||||
<OrderList {...listProps} />
|
<OrderList {...listProps} />
|
||||||
</Card>
|
</Card>
|
||||||
|
|
|
@ -168,7 +168,6 @@ export const orderListQuery = gql`
|
||||||
$after: String
|
$after: String
|
||||||
$last: Int
|
$last: Int
|
||||||
$before: String
|
$before: String
|
||||||
$status: OrderStatusFilter
|
|
||||||
$filter: OrderFilterInput
|
$filter: OrderFilterInput
|
||||||
) {
|
) {
|
||||||
orders(
|
orders(
|
||||||
|
@ -176,7 +175,6 @@ export const orderListQuery = gql`
|
||||||
after: $after
|
after: $after
|
||||||
first: $first
|
first: $first
|
||||||
last: $last
|
last: $last
|
||||||
status: $status
|
|
||||||
filter: $filter
|
filter: $filter
|
||||||
) {
|
) {
|
||||||
edges {
|
edges {
|
||||||
|
@ -221,8 +219,15 @@ export const orderDraftListQuery = gql`
|
||||||
$after: String
|
$after: String
|
||||||
$last: Int
|
$last: Int
|
||||||
$before: String
|
$before: String
|
||||||
|
$filter: OrderDraftFilterInput
|
||||||
|
) {
|
||||||
|
draftOrders(
|
||||||
|
before: $before
|
||||||
|
after: $after
|
||||||
|
first: $first
|
||||||
|
last: $last
|
||||||
|
filter: $filter
|
||||||
) {
|
) {
|
||||||
draftOrders(before: $before, after: $after, first: $first, last: $last) {
|
|
||||||
edges {
|
edges {
|
||||||
node {
|
node {
|
||||||
__typename
|
__typename
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
// This file was automatically generated and should not be edited.
|
// This file was automatically generated and should not be edited.
|
||||||
|
|
||||||
import { PaymentChargeStatusEnum, OrderStatus } from "./../../types/globalTypes";
|
import { OrderDraftFilterInput, PaymentChargeStatusEnum, OrderStatus } from "./../../types/globalTypes";
|
||||||
|
|
||||||
// ====================================================
|
// ====================================================
|
||||||
// GraphQL query operation: OrderDraftList
|
// GraphQL query operation: OrderDraftList
|
||||||
|
@ -81,4 +81,5 @@ export interface OrderDraftListVariables {
|
||||||
after?: string | null;
|
after?: string | null;
|
||||||
last?: number | null;
|
last?: number | null;
|
||||||
before?: string | null;
|
before?: string | null;
|
||||||
|
filter?: OrderDraftFilterInput | null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
// This file was automatically generated and should not be edited.
|
// This file was automatically generated and should not be edited.
|
||||||
|
|
||||||
import { OrderStatusFilter, OrderFilterInput, PaymentChargeStatusEnum, OrderStatus } from "./../../types/globalTypes";
|
import { OrderFilterInput, PaymentChargeStatusEnum, OrderStatus } from "./../../types/globalTypes";
|
||||||
|
|
||||||
// ====================================================
|
// ====================================================
|
||||||
// GraphQL query operation: OrderList
|
// GraphQL query operation: OrderList
|
||||||
|
@ -81,6 +81,5 @@ export interface OrderListVariables {
|
||||||
after?: string | null;
|
after?: string | null;
|
||||||
last?: number | null;
|
last?: number | null;
|
||||||
before?: string | null;
|
before?: string | null;
|
||||||
status?: OrderStatusFilter | null;
|
|
||||||
filter?: OrderFilterInput | null;
|
filter?: OrderFilterInput | null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,8 @@ import {
|
||||||
Filters,
|
Filters,
|
||||||
FiltersWithMultipleValues,
|
FiltersWithMultipleValues,
|
||||||
Pagination,
|
Pagination,
|
||||||
SingleAction
|
SingleAction,
|
||||||
|
TabActionDialog
|
||||||
} from "../types";
|
} from "../types";
|
||||||
|
|
||||||
const orderSectionUrl = "/orders";
|
const orderSectionUrl = "/orders";
|
||||||
|
@ -18,14 +19,15 @@ export enum OrderListUrlFiltersEnum {
|
||||||
dateFrom = "dateFrom",
|
dateFrom = "dateFrom",
|
||||||
dateTo = "dateTo",
|
dateTo = "dateTo",
|
||||||
email = "email",
|
email = "email",
|
||||||
payment = "payment"
|
payment = "payment",
|
||||||
|
query = "query"
|
||||||
}
|
}
|
||||||
export enum OrderListUrlFiltersWithMultipleValuesEnum {
|
export enum OrderListUrlFiltersWithMultipleValuesEnum {
|
||||||
status = "status"
|
status = "status"
|
||||||
}
|
}
|
||||||
export type OrderListUrlFilters = Filters<OrderListUrlFiltersEnum> &
|
export type OrderListUrlFilters = Filters<OrderListUrlFiltersEnum> &
|
||||||
FiltersWithMultipleValues<OrderListUrlFiltersWithMultipleValuesEnum>;
|
FiltersWithMultipleValues<OrderListUrlFiltersWithMultipleValuesEnum>;
|
||||||
export type OrderListUrlDialog = "cancel" | "save-search" | "delete-search";
|
export type OrderListUrlDialog = "cancel" | TabActionDialog;
|
||||||
export type OrderListUrlQueryParams = BulkAction &
|
export type OrderListUrlQueryParams = BulkAction &
|
||||||
Dialog<OrderListUrlDialog> &
|
Dialog<OrderListUrlDialog> &
|
||||||
OrderListUrlFilters &
|
OrderListUrlFilters &
|
||||||
|
@ -41,9 +43,15 @@ export const orderListUrl = (params?: OrderListUrlQueryParams): string => {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const orderDraftListPath = urlJoin(orderSectionUrl, "drafts");
|
export const orderDraftListPath = urlJoin(orderSectionUrl, "drafts");
|
||||||
export type OrderDraftListUrlDialog = "remove";
|
export enum OrderDraftListUrlFiltersEnum {
|
||||||
export type OrderDraftListUrlQueryParams = BulkAction &
|
query = "query"
|
||||||
|
}
|
||||||
|
export type OrderDraftListUrlFilters = Filters<OrderDraftListUrlFiltersEnum>;
|
||||||
|
export type OrderDraftListUrlDialog = "remove" | TabActionDialog;
|
||||||
|
export type OrderDraftListUrlQueryParams = ActiveTab &
|
||||||
|
BulkAction &
|
||||||
Dialog<OrderDraftListUrlDialog> &
|
Dialog<OrderDraftListUrlDialog> &
|
||||||
|
OrderDraftListUrlFilters &
|
||||||
Pagination;
|
Pagination;
|
||||||
export const orderDraftListUrl = (
|
export const orderDraftListUrl = (
|
||||||
params?: OrderDraftListUrlQueryParams
|
params?: OrderDraftListUrlQueryParams
|
||||||
|
|
|
@ -5,6 +5,10 @@ import React from "react";
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
|
|
||||||
import ActionDialog from "@saleor/components/ActionDialog";
|
import ActionDialog from "@saleor/components/ActionDialog";
|
||||||
|
import DeleteFilterTabDialog from "@saleor/components/DeleteFilterTabDialog";
|
||||||
|
import SaveFilterTabDialog, {
|
||||||
|
SaveFilterTabDialogFormData
|
||||||
|
} from "@saleor/components/SaveFilterTabDialog";
|
||||||
import useBulkActions from "@saleor/hooks/useBulkActions";
|
import useBulkActions from "@saleor/hooks/useBulkActions";
|
||||||
import useListSettings from "@saleor/hooks/useListSettings";
|
import useListSettings from "@saleor/hooks/useListSettings";
|
||||||
import useNavigator from "@saleor/hooks/useNavigator";
|
import useNavigator from "@saleor/hooks/useNavigator";
|
||||||
|
@ -14,19 +18,29 @@ import usePaginator, {
|
||||||
} from "@saleor/hooks/usePaginator";
|
} from "@saleor/hooks/usePaginator";
|
||||||
import { getMutationState, maybe } from "@saleor/misc";
|
import { getMutationState, maybe } from "@saleor/misc";
|
||||||
import { ListViews } from "@saleor/types";
|
import { ListViews } from "@saleor/types";
|
||||||
import OrderDraftListPage from "../components/OrderDraftListPage";
|
import OrderDraftListPage from "../../components/OrderDraftListPage";
|
||||||
import {
|
import {
|
||||||
TypedOrderDraftBulkCancelMutation,
|
TypedOrderDraftBulkCancelMutation,
|
||||||
TypedOrderDraftCreateMutation
|
TypedOrderDraftCreateMutation
|
||||||
} from "../mutations";
|
} from "../../mutations";
|
||||||
import { TypedOrderDraftListQuery } from "../queries";
|
import { TypedOrderDraftListQuery } from "../../queries";
|
||||||
import { OrderDraftBulkCancel } from "../types/OrderDraftBulkCancel";
|
import { OrderDraftBulkCancel } from "../../types/OrderDraftBulkCancel";
|
||||||
import { OrderDraftCreate } from "../types/OrderDraftCreate";
|
import { OrderDraftCreate } from "../../types/OrderDraftCreate";
|
||||||
import {
|
import {
|
||||||
orderDraftListUrl,
|
orderDraftListUrl,
|
||||||
|
OrderDraftListUrlDialog,
|
||||||
|
OrderDraftListUrlFilters,
|
||||||
OrderDraftListUrlQueryParams,
|
OrderDraftListUrlQueryParams,
|
||||||
orderUrl
|
orderUrl
|
||||||
} from "../urls";
|
} from "../../urls";
|
||||||
|
import {
|
||||||
|
areFiltersApplied,
|
||||||
|
deleteFilterTab,
|
||||||
|
getActiveFilters,
|
||||||
|
getFilterTabs,
|
||||||
|
getFilterVariables,
|
||||||
|
saveFilterTab
|
||||||
|
} from "./filter";
|
||||||
|
|
||||||
interface OrderDraftListProps {
|
interface OrderDraftListProps {
|
||||||
params: OrderDraftListUrlQueryParams;
|
params: OrderDraftListUrlQueryParams;
|
||||||
|
@ -46,13 +60,34 @@ export const OrderDraftList: React.StatelessComponent<OrderDraftListProps> = ({
|
||||||
);
|
);
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
|
const tabs = getFilterTabs();
|
||||||
|
|
||||||
|
const currentTab =
|
||||||
|
params.activeTab === undefined
|
||||||
|
? areFiltersApplied(params)
|
||||||
|
? tabs.length + 1
|
||||||
|
: 0
|
||||||
|
: parseInt(params.activeTab, 0);
|
||||||
|
|
||||||
|
const changeFilterField = (filter: OrderDraftListUrlFilters) => {
|
||||||
|
reset();
|
||||||
|
navigate(
|
||||||
|
orderDraftListUrl({
|
||||||
|
...getActiveFilters(params),
|
||||||
|
...filter,
|
||||||
|
activeTab: undefined
|
||||||
|
})
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const closeModal = () =>
|
const closeModal = () =>
|
||||||
navigate(
|
navigate(
|
||||||
orderDraftListUrl({
|
orderDraftListUrl({
|
||||||
...params,
|
...params,
|
||||||
action: undefined,
|
action: undefined,
|
||||||
ids: undefined
|
ids: undefined
|
||||||
})
|
}),
|
||||||
|
true
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleCreateOrderCreateSuccess = (data: OrderDraftCreate) => {
|
const handleCreateOrderCreateSuccess = (data: OrderDraftCreate) => {
|
||||||
|
@ -64,12 +99,49 @@ export const OrderDraftList: React.StatelessComponent<OrderDraftListProps> = ({
|
||||||
navigate(orderUrl(data.draftOrderCreate.order.id));
|
navigate(orderUrl(data.draftOrderCreate.order.id));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const openModal = (action: OrderDraftListUrlDialog, ids?: string[]) =>
|
||||||
|
navigate(
|
||||||
|
orderDraftListUrl({
|
||||||
|
...params,
|
||||||
|
action,
|
||||||
|
ids
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleTabChange = (tab: number) => {
|
||||||
|
reset();
|
||||||
|
navigate(
|
||||||
|
orderDraftListUrl({
|
||||||
|
activeTab: tab.toString(),
|
||||||
|
...getFilterTabs()[tab - 1].data
|
||||||
|
})
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleTabDelete = () => {
|
||||||
|
deleteFilterTab(currentTab);
|
||||||
|
reset();
|
||||||
|
navigate(orderDraftListUrl());
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleTabSave = (data: SaveFilterTabDialogFormData) => {
|
||||||
|
saveFilterTab(data.name, getActiveFilters(params));
|
||||||
|
handleTabChange(tabs.length + 1);
|
||||||
|
};
|
||||||
|
|
||||||
const paginationState = createPaginationState(settings.rowNumber, params);
|
const paginationState = createPaginationState(settings.rowNumber, params);
|
||||||
|
const queryVariables = React.useMemo(
|
||||||
|
() => ({
|
||||||
|
...paginationState,
|
||||||
|
filter: getFilterVariables(params)
|
||||||
|
}),
|
||||||
|
[params]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TypedOrderDraftCreateMutation onCompleted={handleCreateOrderCreateSuccess}>
|
<TypedOrderDraftCreateMutation onCompleted={handleCreateOrderCreateSuccess}>
|
||||||
{createOrder => (
|
{createOrder => (
|
||||||
<TypedOrderDraftListQuery displayLoader variables={paginationState}>
|
<TypedOrderDraftListQuery displayLoader variables={queryVariables}>
|
||||||
{({ data, loading, refetch }) => {
|
{({ data, loading, refetch }) => {
|
||||||
const { loadNextPage, loadPreviousPage, pageInfo } = paginate(
|
const { loadNextPage, loadPreviousPage, pageInfo } = paginate(
|
||||||
maybe(() => data.draftOrders.pageInfo),
|
maybe(() => data.draftOrders.pageInfo),
|
||||||
|
@ -114,6 +186,14 @@ export const OrderDraftList: React.StatelessComponent<OrderDraftListProps> = ({
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<OrderDraftListPage
|
<OrderDraftListPage
|
||||||
|
currentTab={currentTab}
|
||||||
|
initialSearch={params.query || ""}
|
||||||
|
onSearchChange={query => changeFilterField({ query })}
|
||||||
|
onAll={() => navigate(orderDraftListUrl())}
|
||||||
|
onTabChange={handleTabChange}
|
||||||
|
onTabDelete={() => openModal("delete-search")}
|
||||||
|
onTabSave={() => openModal("save-search")}
|
||||||
|
tabs={tabs.map(tab => tab.name)}
|
||||||
disabled={loading}
|
disabled={loading}
|
||||||
settings={settings}
|
settings={settings}
|
||||||
orders={maybe(() =>
|
orders={maybe(() =>
|
||||||
|
@ -174,6 +254,19 @@ export const OrderDraftList: React.StatelessComponent<OrderDraftListProps> = ({
|
||||||
/>
|
/>
|
||||||
</DialogContentText>
|
</DialogContentText>
|
||||||
</ActionDialog>
|
</ActionDialog>
|
||||||
|
<SaveFilterTabDialog
|
||||||
|
open={params.action === "save-search"}
|
||||||
|
confirmButtonState="default"
|
||||||
|
onClose={closeModal}
|
||||||
|
onSubmit={handleTabSave}
|
||||||
|
/>
|
||||||
|
<DeleteFilterTabDialog
|
||||||
|
open={params.action === "delete-search"}
|
||||||
|
confirmButtonState="default"
|
||||||
|
onClose={closeModal}
|
||||||
|
onSubmit={handleTabDelete}
|
||||||
|
tabName={maybe(() => tabs[currentTab - 1].name, "...")}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
31
src/orders/views/OrderDraftList/filter.ts
Normal file
31
src/orders/views/OrderDraftList/filter.ts
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
import { OrderDraftFilterInput } from "@saleor/types/globalTypes";
|
||||||
|
import {
|
||||||
|
createFilterTabUtils,
|
||||||
|
createFilterUtils
|
||||||
|
} from "../../../utils/filters";
|
||||||
|
import {
|
||||||
|
OrderDraftListUrlFilters,
|
||||||
|
OrderDraftListUrlFiltersEnum,
|
||||||
|
OrderDraftListUrlQueryParams
|
||||||
|
} from "../../urls";
|
||||||
|
|
||||||
|
export const ORDER_DRAFT_FILTERS_KEY = "orderDraftFilters";
|
||||||
|
|
||||||
|
export function getFilterVariables(
|
||||||
|
params: OrderDraftListUrlFilters
|
||||||
|
): OrderDraftFilterInput {
|
||||||
|
return {
|
||||||
|
search: params.query
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export const {
|
||||||
|
deleteFilterTab,
|
||||||
|
getFilterTabs,
|
||||||
|
saveFilterTab
|
||||||
|
} = createFilterTabUtils<OrderDraftListUrlFilters>(ORDER_DRAFT_FILTERS_KEY);
|
||||||
|
|
||||||
|
export const { areFiltersApplied, getActiveFilters } = createFilterUtils<
|
||||||
|
OrderDraftListUrlQueryParams,
|
||||||
|
OrderDraftListUrlFilters
|
||||||
|
>(OrderDraftListUrlFiltersEnum);
|
2
src/orders/views/OrderDraftList/index.ts
Normal file
2
src/orders/views/OrderDraftList/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
export { default } from "./OrderDraftList";
|
||||||
|
export * from "./OrderDraftList";
|
|
@ -228,15 +228,15 @@ export const OrderList: React.StatelessComponent<OrderListProps> = ({
|
||||||
/>
|
/>
|
||||||
</Button>
|
</Button>
|
||||||
}
|
}
|
||||||
onSearchChange={email => changeFilterField({ email })}
|
onSearchChange={query => changeFilterField({ query })}
|
||||||
onFilterAdd={data =>
|
onFilterAdd={data =>
|
||||||
changeFilterField(createFilter(params, data))
|
changeFilterField(createFilter(params, data))
|
||||||
}
|
}
|
||||||
onFilterSave={() => openModal("save-search")}
|
onTabSave={() => openModal("save-search")}
|
||||||
onFilterDelete={() => openModal("delete-search")}
|
onTabDelete={() => openModal("delete-search")}
|
||||||
onTabChange={handleTabChange}
|
onTabChange={handleTabChange}
|
||||||
initialSearch={params.email || ""}
|
initialSearch={params.query || ""}
|
||||||
filterTabs={getFilterTabs()}
|
tabs={getFilterTabs().map(tab => tab.name)}
|
||||||
onAll={() =>
|
onAll={() =>
|
||||||
changeFilters({
|
changeFilters({
|
||||||
status: undefined
|
status: undefined
|
||||||
|
|
|
@ -10,6 +10,10 @@ Array [
|
||||||
"label": "Date to 2019-09-10",
|
"label": "Date to 2019-09-10",
|
||||||
"onClick": [Function],
|
"onClick": [Function],
|
||||||
},
|
},
|
||||||
|
Object {
|
||||||
|
"label": "email@example.com",
|
||||||
|
"onClick": [Function],
|
||||||
|
},
|
||||||
Object {
|
Object {
|
||||||
"label": "Fulfilled",
|
"label": "Fulfilled",
|
||||||
"onClick": [Function],
|
"onClick": [Function],
|
||||||
|
@ -88,6 +92,7 @@ Object {
|
||||||
"lte": "2019-09-10",
|
"lte": "2019-09-10",
|
||||||
},
|
},
|
||||||
"customer": "email@example.com",
|
"customer": "email@example.com",
|
||||||
|
"search": "24",
|
||||||
"status": Array [
|
"status": Array [
|
||||||
"FULFILLED",
|
"FULFILLED",
|
||||||
"PARTIALLY_FULFILLED",
|
"PARTIALLY_FULFILLED",
|
||||||
|
@ -102,6 +107,7 @@ Object {
|
||||||
"lte": "2019-09-10",
|
"lte": "2019-09-10",
|
||||||
},
|
},
|
||||||
"customer": "email@example.com",
|
"customer": "email@example.com",
|
||||||
|
"search": "24",
|
||||||
"status": Array [
|
"status": Array [
|
||||||
"FULFILLED",
|
"FULFILLED",
|
||||||
],
|
],
|
||||||
|
|
|
@ -115,6 +115,7 @@ test("Crate filter chips", () => {
|
||||||
{
|
{
|
||||||
dateFrom: "2019-09-01",
|
dateFrom: "2019-09-01",
|
||||||
dateTo: "2019-09-10",
|
dateTo: "2019-09-10",
|
||||||
|
email: "email@example.com",
|
||||||
status: [OrderStatus.FULFILLED, OrderStatus.PARTIALLY_FULFILLED]
|
status: [OrderStatus.FULFILLED, OrderStatus.PARTIALLY_FULFILLED]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -133,6 +134,7 @@ describe("Get filter variables", () => {
|
||||||
dateFrom: "2019-09-01",
|
dateFrom: "2019-09-01",
|
||||||
dateTo: "2019-09-10",
|
dateTo: "2019-09-10",
|
||||||
email: "email@example.com",
|
email: "email@example.com",
|
||||||
|
query: "24",
|
||||||
status: OrderStatus.FULFILLED.toString()
|
status: OrderStatus.FULFILLED.toString()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -144,6 +146,7 @@ describe("Get filter variables", () => {
|
||||||
dateFrom: "2019-09-01",
|
dateFrom: "2019-09-01",
|
||||||
dateTo: "2019-09-10",
|
dateTo: "2019-09-10",
|
||||||
email: "email@example.com",
|
email: "email@example.com",
|
||||||
|
query: "24",
|
||||||
status: [
|
status: [
|
||||||
OrderStatus.FULFILLED.toString(),
|
OrderStatus.FULFILLED.toString(),
|
||||||
OrderStatus.PARTIALLY_FULFILLED.toString()
|
OrderStatus.PARTIALLY_FULFILLED.toString()
|
||||||
|
|
|
@ -20,6 +20,7 @@ import { OrderFilterKeys } from "../../components/OrderListFilter";
|
||||||
import {
|
import {
|
||||||
OrderListUrlFilters,
|
OrderListUrlFilters,
|
||||||
OrderListUrlFiltersEnum,
|
OrderListUrlFiltersEnum,
|
||||||
|
OrderListUrlFiltersWithMultipleValuesEnum,
|
||||||
OrderListUrlQueryParams
|
OrderListUrlQueryParams
|
||||||
} from "../../urls";
|
} from "../../urls";
|
||||||
|
|
||||||
|
@ -83,6 +84,7 @@ export function getFilterVariables(
|
||||||
lte: params.dateTo
|
lte: params.dateTo
|
||||||
},
|
},
|
||||||
customer: params.email,
|
customer: params.email,
|
||||||
|
search: params.query,
|
||||||
status: Array.isArray(params.status)
|
status: Array.isArray(params.status)
|
||||||
? params.status.map(status => findInEnum(status, OrderStatusFilter))
|
? params.status.map(status => findInEnum(status, OrderStatusFilter))
|
||||||
: params.status
|
: params.status
|
||||||
|
@ -190,6 +192,20 @@ export function createFilterChips(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!!filters.email) {
|
||||||
|
filterChips = [
|
||||||
|
...filterChips,
|
||||||
|
{
|
||||||
|
label: filters.email,
|
||||||
|
onClick: () =>
|
||||||
|
onFilterDelete({
|
||||||
|
...filters,
|
||||||
|
email: undefined
|
||||||
|
})
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
if (!!filters.status) {
|
if (!!filters.status) {
|
||||||
const statusFilterChips = Array.isArray(filters.status)
|
const statusFilterChips = Array.isArray(filters.status)
|
||||||
? filters.status.map((status, statusIndex) => ({
|
? filters.status.map((status, statusIndex) => ({
|
||||||
|
@ -228,4 +244,7 @@ export const {
|
||||||
export const { areFiltersApplied, getActiveFilters } = createFilterUtils<
|
export const { areFiltersApplied, getActiveFilters } = createFilterUtils<
|
||||||
OrderListUrlQueryParams,
|
OrderListUrlQueryParams,
|
||||||
OrderListUrlFilters
|
OrderListUrlFilters
|
||||||
>(OrderListUrlFiltersEnum);
|
>({
|
||||||
|
...OrderListUrlFiltersEnum,
|
||||||
|
...OrderListUrlFiltersWithMultipleValuesEnum
|
||||||
|
});
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import Card from "@material-ui/core/Card";
|
|
||||||
import {
|
import {
|
||||||
createStyles,
|
createStyles,
|
||||||
Theme,
|
Theme,
|
||||||
|
@ -70,7 +69,6 @@ const ProductTypeList = withStyles(styles, { name: "ProductTypeList" })(
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card>
|
|
||||||
<Table>
|
<Table>
|
||||||
<TableHead
|
<TableHead
|
||||||
colSpan={numberOfColumns}
|
colSpan={numberOfColumns}
|
||||||
|
@ -103,9 +101,7 @@ const ProductTypeList = withStyles(styles, { name: "ProductTypeList" })(
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TablePagination
|
<TablePagination
|
||||||
colSpan={numberOfColumns}
|
colSpan={numberOfColumns}
|
||||||
hasNextPage={
|
hasNextPage={pageInfo && !disabled ? pageInfo.hasNextPage : false}
|
||||||
pageInfo && !disabled ? pageInfo.hasNextPage : false
|
|
||||||
}
|
|
||||||
onNextPage={onNextPage}
|
onNextPage={onNextPage}
|
||||||
hasPreviousPage={
|
hasPreviousPage={
|
||||||
pageInfo && !disabled ? pageInfo.hasPreviousPage : false
|
pageInfo && !disabled ? pageInfo.hasPreviousPage : false
|
||||||
|
@ -126,9 +122,7 @@ const ProductTypeList = withStyles(styles, { name: "ProductTypeList" })(
|
||||||
className={!!productType ? classes.link : undefined}
|
className={!!productType ? classes.link : undefined}
|
||||||
hover={!!productType}
|
hover={!!productType}
|
||||||
key={productType ? productType.id : "skeleton"}
|
key={productType ? productType.id : "skeleton"}
|
||||||
onClick={
|
onClick={productType ? onRowClick(productType.id) : undefined}
|
||||||
productType ? onRowClick(productType.id) : undefined
|
|
||||||
}
|
|
||||||
selected={isSelected}
|
selected={isSelected}
|
||||||
>
|
>
|
||||||
<TableCell padding="checkbox">
|
<TableCell padding="checkbox">
|
||||||
|
@ -201,7 +195,6 @@ const ProductTypeList = withStyles(styles, { name: "ProductTypeList" })(
|
||||||
)}
|
)}
|
||||||
</TableBody>
|
</TableBody>
|
||||||
</Table>
|
</Table>
|
||||||
</Card>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,23 +1,46 @@
|
||||||
import Button from "@material-ui/core/Button";
|
import Button from "@material-ui/core/Button";
|
||||||
|
import Card from "@material-ui/core/Card";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
|
|
||||||
import AppHeader from "@saleor/components/AppHeader";
|
import AppHeader from "@saleor/components/AppHeader";
|
||||||
import Container from "@saleor/components/Container";
|
import Container from "@saleor/components/Container";
|
||||||
import PageHeader from "@saleor/components/PageHeader";
|
import PageHeader from "@saleor/components/PageHeader";
|
||||||
|
import SearchBar from "@saleor/components/SearchBar";
|
||||||
import { sectionNames } from "@saleor/intl";
|
import { sectionNames } from "@saleor/intl";
|
||||||
import { ListActions, PageListProps } from "../../../types";
|
import {
|
||||||
|
ListActions,
|
||||||
|
PageListProps,
|
||||||
|
SearchPageProps,
|
||||||
|
TabPageProps
|
||||||
|
} from "../../../types";
|
||||||
import { ProductTypeList_productTypes_edges_node } from "../../types/ProductTypeList";
|
import { ProductTypeList_productTypes_edges_node } from "../../types/ProductTypeList";
|
||||||
import ProductTypeList from "../ProductTypeList";
|
import ProductTypeList from "../ProductTypeList";
|
||||||
|
|
||||||
interface ProductTypeListPageProps extends PageListProps, ListActions {
|
export interface ProductTypeListPageProps
|
||||||
|
extends PageListProps,
|
||||||
|
ListActions,
|
||||||
|
SearchPageProps,
|
||||||
|
TabPageProps {
|
||||||
productTypes: ProductTypeList_productTypes_edges_node[];
|
productTypes: ProductTypeList_productTypes_edges_node[];
|
||||||
onBack: () => void;
|
onBack: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ProductTypeListPage: React.StatelessComponent<
|
const ProductTypeListPage: React.StatelessComponent<
|
||||||
ProductTypeListPageProps
|
ProductTypeListPageProps
|
||||||
> = ({ disabled, onAdd, onBack, ...listProps }) => {
|
> = ({
|
||||||
|
currentTab,
|
||||||
|
initialSearch,
|
||||||
|
onAdd,
|
||||||
|
onAll,
|
||||||
|
onBack,
|
||||||
|
onSearchChange,
|
||||||
|
onTabChange,
|
||||||
|
onTabDelete,
|
||||||
|
onTabSave,
|
||||||
|
tabs,
|
||||||
|
...listProps
|
||||||
|
}) => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -26,19 +49,33 @@ const ProductTypeListPage: React.StatelessComponent<
|
||||||
{intl.formatMessage(sectionNames.configuration)}
|
{intl.formatMessage(sectionNames.configuration)}
|
||||||
</AppHeader>
|
</AppHeader>
|
||||||
<PageHeader title={intl.formatMessage(sectionNames.productTypes)}>
|
<PageHeader title={intl.formatMessage(sectionNames.productTypes)}>
|
||||||
<Button
|
<Button color="primary" variant="contained" onClick={onAdd}>
|
||||||
color="primary"
|
|
||||||
variant="contained"
|
|
||||||
disabled={disabled}
|
|
||||||
onClick={onAdd}
|
|
||||||
>
|
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
defaultMessage="create product type"
|
defaultMessage="create product type"
|
||||||
description="button"
|
description="button"
|
||||||
/>
|
/>
|
||||||
</Button>
|
</Button>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
<ProductTypeList disabled={disabled} {...listProps} />
|
<Card>
|
||||||
|
<SearchBar
|
||||||
|
allTabLabel={intl.formatMessage({
|
||||||
|
defaultMessage: "All Product Types",
|
||||||
|
description: "tab name"
|
||||||
|
})}
|
||||||
|
currentTab={currentTab}
|
||||||
|
initialSearch={initialSearch}
|
||||||
|
searchPlaceholder={intl.formatMessage({
|
||||||
|
defaultMessage: "Search Product Type"
|
||||||
|
})}
|
||||||
|
tabs={tabs}
|
||||||
|
onAll={onAll}
|
||||||
|
onSearchChange={onSearchChange}
|
||||||
|
onTabChange={onTabChange}
|
||||||
|
onTabDelete={onTabDelete}
|
||||||
|
onTabSave={onTabSave}
|
||||||
|
/>
|
||||||
|
<ProductTypeList {...listProps} />
|
||||||
|
</Card>
|
||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -51,8 +51,15 @@ export const productTypeListQuery = gql`
|
||||||
$before: String
|
$before: String
|
||||||
$first: Int
|
$first: Int
|
||||||
$last: Int
|
$last: Int
|
||||||
|
$filter: ProductTypeFilterInput
|
||||||
|
) {
|
||||||
|
productTypes(
|
||||||
|
after: $after
|
||||||
|
before: $before
|
||||||
|
first: $first
|
||||||
|
last: $last
|
||||||
|
filter: $filter
|
||||||
) {
|
) {
|
||||||
productTypes(after: $after, before: $before, first: $first, last: $last) {
|
|
||||||
edges {
|
edges {
|
||||||
node {
|
node {
|
||||||
...ProductTypeFragment
|
...ProductTypeFragment
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
// This file was automatically generated and should not be edited.
|
// This file was automatically generated and should not be edited.
|
||||||
|
|
||||||
|
import { ProductTypeFilterInput } from "./../../types/globalTypes";
|
||||||
|
|
||||||
// ====================================================
|
// ====================================================
|
||||||
// GraphQL query operation: ProductTypeList
|
// GraphQL query operation: ProductTypeList
|
||||||
// ====================================================
|
// ====================================================
|
||||||
|
@ -49,4 +51,5 @@ export interface ProductTypeListVariables {
|
||||||
before?: string | null;
|
before?: string | null;
|
||||||
first?: number | null;
|
first?: number | null;
|
||||||
last?: number | null;
|
last?: number | null;
|
||||||
|
filter?: ProductTypeFilterInput | null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,29 @@
|
||||||
import { stringify as stringifyQs } from "qs";
|
import { stringify as stringifyQs } from "qs";
|
||||||
import urlJoin from "url-join";
|
import urlJoin from "url-join";
|
||||||
|
|
||||||
import { BulkAction, Dialog, Pagination, SingleAction } from "../types";
|
import {
|
||||||
|
ActiveTab,
|
||||||
|
BulkAction,
|
||||||
|
Dialog,
|
||||||
|
Filters,
|
||||||
|
Pagination,
|
||||||
|
SingleAction,
|
||||||
|
TabActionDialog
|
||||||
|
} from "../types";
|
||||||
|
|
||||||
const productTypeSection = "/product-types/";
|
const productTypeSection = "/product-types/";
|
||||||
|
|
||||||
export const productTypeListPath = productTypeSection;
|
export const productTypeListPath = productTypeSection;
|
||||||
export type ProductTypeListUrlDialog = "remove";
|
export enum ProductTypeListUrlFiltersEnum {
|
||||||
export type ProductTypeListUrlQueryParams = BulkAction &
|
query = "query"
|
||||||
|
}
|
||||||
|
export type ProductTypeListUrlFilters = Filters<ProductTypeListUrlFiltersEnum>;
|
||||||
|
export type ProductTypeListUrlDialog = "remove" | TabActionDialog;
|
||||||
|
export type ProductTypeListUrlQueryParams = ActiveTab &
|
||||||
|
BulkAction &
|
||||||
Dialog<ProductTypeListUrlDialog> &
|
Dialog<ProductTypeListUrlDialog> &
|
||||||
Pagination;
|
Pagination &
|
||||||
|
ProductTypeListUrlFilters;
|
||||||
export const productTypeListUrl = (params?: ProductTypeListUrlQueryParams) =>
|
export const productTypeListUrl = (params?: ProductTypeListUrlQueryParams) =>
|
||||||
productTypeListPath + "?" + stringifyQs(params);
|
productTypeListPath + "?" + stringifyQs(params);
|
||||||
|
|
||||||
|
|
|
@ -5,26 +5,41 @@ import React from "react";
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
|
|
||||||
import ActionDialog from "@saleor/components/ActionDialog";
|
import ActionDialog from "@saleor/components/ActionDialog";
|
||||||
|
import DeleteFilterTabDialog from "@saleor/components/DeleteFilterTabDialog";
|
||||||
|
import SaveFilterTabDialog, {
|
||||||
|
SaveFilterTabDialogFormData
|
||||||
|
} from "@saleor/components/SaveFilterTabDialog";
|
||||||
import useBulkActions from "@saleor/hooks/useBulkActions";
|
import useBulkActions from "@saleor/hooks/useBulkActions";
|
||||||
|
import useListSettings from "@saleor/hooks/useListSettings";
|
||||||
import useNavigator from "@saleor/hooks/useNavigator";
|
import useNavigator from "@saleor/hooks/useNavigator";
|
||||||
import useNotifier from "@saleor/hooks/useNotifier";
|
import useNotifier from "@saleor/hooks/useNotifier";
|
||||||
import usePaginator, {
|
import usePaginator, {
|
||||||
createPaginationState
|
createPaginationState
|
||||||
} from "@saleor/hooks/usePaginator";
|
} from "@saleor/hooks/usePaginator";
|
||||||
import { commonMessages } from "@saleor/intl";
|
import { commonMessages } from "@saleor/intl";
|
||||||
import { PAGINATE_BY } from "../../config";
|
import { ListViews } from "@saleor/types";
|
||||||
import { configurationMenuUrl } from "../../configuration";
|
import { configurationMenuUrl } from "../../../configuration";
|
||||||
import { getMutationState, maybe } from "../../misc";
|
import { getMutationState, maybe } from "../../../misc";
|
||||||
import ProductTypeListPage from "../components/ProductTypeListPage";
|
import ProductTypeListPage from "../../components/ProductTypeListPage";
|
||||||
import { TypedProductTypeBulkDeleteMutation } from "../mutations";
|
import { TypedProductTypeBulkDeleteMutation } from "../../mutations";
|
||||||
import { TypedProductTypeListQuery } from "../queries";
|
import { TypedProductTypeListQuery } from "../../queries";
|
||||||
import { ProductTypeBulkDelete } from "../types/ProductTypeBulkDelete";
|
import { ProductTypeBulkDelete } from "../../types/ProductTypeBulkDelete";
|
||||||
import {
|
import {
|
||||||
productTypeAddUrl,
|
productTypeAddUrl,
|
||||||
productTypeListUrl,
|
productTypeListUrl,
|
||||||
|
ProductTypeListUrlDialog,
|
||||||
|
ProductTypeListUrlFilters,
|
||||||
ProductTypeListUrlQueryParams,
|
ProductTypeListUrlQueryParams,
|
||||||
productTypeUrl
|
productTypeUrl
|
||||||
} from "../urls";
|
} from "../../urls";
|
||||||
|
import {
|
||||||
|
areFiltersApplied,
|
||||||
|
deleteFilterTab,
|
||||||
|
getActiveFilters,
|
||||||
|
getFilterTabs,
|
||||||
|
getFilterVariables,
|
||||||
|
saveFilterTab
|
||||||
|
} from "./filter";
|
||||||
|
|
||||||
interface ProductTypeListProps {
|
interface ProductTypeListProps {
|
||||||
params: ProductTypeListUrlQueryParams;
|
params: ProductTypeListUrlQueryParams;
|
||||||
|
@ -39,13 +54,80 @@ export const ProductTypeList: React.StatelessComponent<
|
||||||
const { isSelected, listElements, reset, toggle, toggleAll } = useBulkActions(
|
const { isSelected, listElements, reset, toggle, toggleAll } = useBulkActions(
|
||||||
params.ids
|
params.ids
|
||||||
);
|
);
|
||||||
|
const { settings } = useListSettings(ListViews.PRODUCT_LIST);
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
const closeModal = () => navigate(productTypeListUrl(), true);
|
const tabs = getFilterTabs();
|
||||||
|
|
||||||
|
const currentTab =
|
||||||
|
params.activeTab === undefined
|
||||||
|
? areFiltersApplied(params)
|
||||||
|
? tabs.length + 1
|
||||||
|
: 0
|
||||||
|
: parseInt(params.activeTab, 0);
|
||||||
|
|
||||||
|
const changeFilterField = (filter: ProductTypeListUrlFilters) => {
|
||||||
|
reset();
|
||||||
|
navigate(
|
||||||
|
productTypeListUrl({
|
||||||
|
...getActiveFilters(params),
|
||||||
|
...filter,
|
||||||
|
activeTab: undefined
|
||||||
|
})
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const closeModal = () =>
|
||||||
|
navigate(
|
||||||
|
productTypeListUrl({
|
||||||
|
...params,
|
||||||
|
action: undefined,
|
||||||
|
ids: undefined
|
||||||
|
}),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
const openModal = (action: ProductTypeListUrlDialog, ids?: string[]) =>
|
||||||
|
navigate(
|
||||||
|
productTypeListUrl({
|
||||||
|
...params,
|
||||||
|
action,
|
||||||
|
ids
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleTabChange = (tab: number) => {
|
||||||
|
reset();
|
||||||
|
navigate(
|
||||||
|
productTypeListUrl({
|
||||||
|
activeTab: tab.toString(),
|
||||||
|
...getFilterTabs()[tab - 1].data
|
||||||
|
})
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleTabDelete = () => {
|
||||||
|
deleteFilterTab(currentTab);
|
||||||
|
reset();
|
||||||
|
navigate(productTypeListUrl());
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleTabSave = (data: SaveFilterTabDialogFormData) => {
|
||||||
|
saveFilterTab(data.name, getActiveFilters(params));
|
||||||
|
handleTabChange(tabs.length + 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
const paginationState = createPaginationState(settings.rowNumber, params);
|
||||||
|
const queryVariables = React.useMemo(
|
||||||
|
() => ({
|
||||||
|
...paginationState,
|
||||||
|
filter: getFilterVariables(params)
|
||||||
|
}),
|
||||||
|
[params]
|
||||||
|
);
|
||||||
|
|
||||||
const paginationState = createPaginationState(PAGINATE_BY, params);
|
|
||||||
return (
|
return (
|
||||||
<TypedProductTypeListQuery displayLoader variables={paginationState}>
|
<TypedProductTypeListQuery displayLoader variables={queryVariables}>
|
||||||
{({ data, loading, refetch }) => {
|
{({ data, loading, refetch }) => {
|
||||||
const { loadNextPage, loadPreviousPage, pageInfo } = paginate(
|
const { loadNextPage, loadPreviousPage, pageInfo } = paginate(
|
||||||
maybe(() => data.productTypes.pageInfo),
|
maybe(() => data.productTypes.pageInfo),
|
||||||
|
@ -93,6 +175,14 @@ export const ProductTypeList: React.StatelessComponent<
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ProductTypeListPage
|
<ProductTypeListPage
|
||||||
|
currentTab={currentTab}
|
||||||
|
initialSearch={params.query || ""}
|
||||||
|
onSearchChange={query => changeFilterField({ query })}
|
||||||
|
onAll={() => navigate(productTypeListUrl())}
|
||||||
|
onTabChange={handleTabChange}
|
||||||
|
onTabDelete={() => openModal("delete-search")}
|
||||||
|
onTabSave={() => openModal("save-search")}
|
||||||
|
tabs={tabs.map(tab => tab.name)}
|
||||||
disabled={loading}
|
disabled={loading}
|
||||||
productTypes={maybe(() =>
|
productTypes={maybe(() =>
|
||||||
data.productTypes.edges.map(edge => edge.node)
|
data.productTypes.edges.map(edge => edge.node)
|
||||||
|
@ -150,6 +240,19 @@ export const ProductTypeList: React.StatelessComponent<
|
||||||
/>
|
/>
|
||||||
</DialogContentText>
|
</DialogContentText>
|
||||||
</ActionDialog>
|
</ActionDialog>
|
||||||
|
<SaveFilterTabDialog
|
||||||
|
open={params.action === "save-search"}
|
||||||
|
confirmButtonState="default"
|
||||||
|
onClose={closeModal}
|
||||||
|
onSubmit={handleTabSave}
|
||||||
|
/>
|
||||||
|
<DeleteFilterTabDialog
|
||||||
|
open={params.action === "delete-search"}
|
||||||
|
confirmButtonState="default"
|
||||||
|
onClose={closeModal}
|
||||||
|
onSubmit={handleTabDelete}
|
||||||
|
tabName={maybe(() => tabs[currentTab - 1].name, "...")}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
31
src/productTypes/views/ProductTypeList/filter.ts
Normal file
31
src/productTypes/views/ProductTypeList/filter.ts
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
import { ProductTypeFilterInput } from "@saleor/types/globalTypes";
|
||||||
|
import {
|
||||||
|
createFilterTabUtils,
|
||||||
|
createFilterUtils
|
||||||
|
} from "../../../utils/filters";
|
||||||
|
import {
|
||||||
|
ProductTypeListUrlFilters,
|
||||||
|
ProductTypeListUrlFiltersEnum,
|
||||||
|
ProductTypeListUrlQueryParams
|
||||||
|
} from "../../urls";
|
||||||
|
|
||||||
|
export const PRODUCT_TYPE_FILTERS_KEY = "productTypeFilters";
|
||||||
|
|
||||||
|
export function getFilterVariables(
|
||||||
|
params: ProductTypeListUrlFilters
|
||||||
|
): ProductTypeFilterInput {
|
||||||
|
return {
|
||||||
|
search: params.query
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export const {
|
||||||
|
deleteFilterTab,
|
||||||
|
getFilterTabs,
|
||||||
|
saveFilterTab
|
||||||
|
} = createFilterTabUtils<ProductTypeListUrlFilters>(PRODUCT_TYPE_FILTERS_KEY);
|
||||||
|
|
||||||
|
export const { areFiltersApplied, getActiveFilters } = createFilterUtils<
|
||||||
|
ProductTypeListUrlQueryParams,
|
||||||
|
ProductTypeListUrlFilters
|
||||||
|
>(ProductTypeListUrlFiltersEnum);
|
2
src/productTypes/views/ProductTypeList/index.ts
Normal file
2
src/productTypes/views/ProductTypeList/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
export { default } from "./ProductTypeList";
|
||||||
|
export * from "./ProductTypeList";
|
|
@ -5,11 +5,10 @@ import { FieldType, IFilter } from "@saleor/components/Filter";
|
||||||
import FilterBar from "@saleor/components/FilterBar";
|
import FilterBar from "@saleor/components/FilterBar";
|
||||||
import { FilterProps } from "@saleor/types";
|
import { FilterProps } from "@saleor/types";
|
||||||
import { StockAvailability } from "@saleor/types/globalTypes";
|
import { StockAvailability } from "@saleor/types/globalTypes";
|
||||||
import { ProductListUrlFilters } from "../../urls";
|
|
||||||
|
|
||||||
type ProductListFilterProps = FilterProps<
|
type ProductListFilterProps = Omit<
|
||||||
ProductListUrlFilters,
|
FilterProps,
|
||||||
ProductFilterKeys
|
"allTabLabel" | "filterLabel" | "searchPlaceholder"
|
||||||
>;
|
>;
|
||||||
|
|
||||||
export enum ProductFilterKeys {
|
export enum ProductFilterKeys {
|
||||||
|
@ -133,7 +132,22 @@ const ProductListFilter: React.FC<ProductListFilterProps> = props => {
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
return <FilterBar {...props} filterMenu={filterMenu} />;
|
return (
|
||||||
|
<FilterBar
|
||||||
|
{...props}
|
||||||
|
allTabLabel={intl.formatMessage({
|
||||||
|
defaultMessage: "All Products",
|
||||||
|
description: "tab name"
|
||||||
|
})}
|
||||||
|
filterMenu={filterMenu}
|
||||||
|
filterLabel={intl.formatMessage({
|
||||||
|
defaultMessage: "Select all products where:"
|
||||||
|
})}
|
||||||
|
searchPlaceholder={intl.formatMessage({
|
||||||
|
defaultMessage: "Search Products..."
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
ProductListFilter.displayName = "ProductListFilter";
|
ProductListFilter.displayName = "ProductListFilter";
|
||||||
export default ProductListFilter;
|
export default ProductListFilter;
|
||||||
|
|
|
@ -24,14 +24,13 @@ import {
|
||||||
ListActions,
|
ListActions,
|
||||||
PageListProps
|
PageListProps
|
||||||
} from "@saleor/types";
|
} from "@saleor/types";
|
||||||
import { ProductListUrlFilters } from "../../urls";
|
|
||||||
import ProductList from "../ProductList";
|
import ProductList from "../ProductList";
|
||||||
import ProductListFilter, { ProductFilterKeys } from "../ProductListFilter";
|
import ProductListFilter, { ProductFilterKeys } from "../ProductListFilter";
|
||||||
|
|
||||||
export interface ProductListPageProps
|
export interface ProductListPageProps
|
||||||
extends PageListProps<ProductListColumns>,
|
extends PageListProps<ProductListColumns>,
|
||||||
ListActions,
|
ListActions,
|
||||||
FilterPageProps<ProductListUrlFilters, ProductFilterKeys>,
|
FilterPageProps<ProductFilterKeys>,
|
||||||
FetchMoreProps {
|
FetchMoreProps {
|
||||||
availableInGridAttributes: AvailableInGridAttributes_availableInGrid_edges_node[];
|
availableInGridAttributes: AvailableInGridAttributes_availableInGrid_edges_node[];
|
||||||
currencySymbol: string;
|
currencySymbol: string;
|
||||||
|
@ -52,22 +51,22 @@ export const ProductListPage: React.FC<ProductListPageProps> = props => {
|
||||||
currentTab,
|
currentTab,
|
||||||
defaultSettings,
|
defaultSettings,
|
||||||
filtersList,
|
filtersList,
|
||||||
filterTabs,
|
|
||||||
gridAttributes,
|
gridAttributes,
|
||||||
availableInGridAttributes,
|
availableInGridAttributes,
|
||||||
hasMore,
|
hasMore,
|
||||||
initialSearch,
|
initialSearch,
|
||||||
loading,
|
loading,
|
||||||
settings,
|
settings,
|
||||||
|
tabs,
|
||||||
totalGridAttributes,
|
totalGridAttributes,
|
||||||
onAdd,
|
onAdd,
|
||||||
onAll,
|
onAll,
|
||||||
onFetchMore,
|
onFetchMore,
|
||||||
onSearchChange,
|
onSearchChange,
|
||||||
onFilterAdd,
|
onFilterAdd,
|
||||||
onFilterSave,
|
|
||||||
onTabChange,
|
onTabChange,
|
||||||
onFilterDelete,
|
onTabDelete,
|
||||||
|
onTabSave,
|
||||||
onUpdateListSettings,
|
onUpdateListSettings,
|
||||||
...listProps
|
...listProps
|
||||||
} = props;
|
} = props;
|
||||||
|
@ -137,27 +136,17 @@ export const ProductListPage: React.FC<ProductListPageProps> = props => {
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
<Card>
|
<Card>
|
||||||
<ProductListFilter
|
<ProductListFilter
|
||||||
allTabLabel={intl.formatMessage({
|
|
||||||
defaultMessage: "All Products",
|
|
||||||
description: "tab name"
|
|
||||||
})}
|
|
||||||
currencySymbol={currencySymbol}
|
currencySymbol={currencySymbol}
|
||||||
currentTab={currentTab}
|
currentTab={currentTab}
|
||||||
filterLabel={intl.formatMessage({
|
|
||||||
defaultMessage: "Select all products where:"
|
|
||||||
})}
|
|
||||||
filterTabs={filterTabs}
|
|
||||||
filtersList={filtersList}
|
filtersList={filtersList}
|
||||||
initialSearch={initialSearch}
|
initialSearch={initialSearch}
|
||||||
searchPlaceholder={intl.formatMessage({
|
|
||||||
defaultMessage: "Search Products..."
|
|
||||||
})}
|
|
||||||
onAll={onAll}
|
onAll={onAll}
|
||||||
onSearchChange={onSearchChange}
|
|
||||||
onFilterAdd={onFilterAdd}
|
onFilterAdd={onFilterAdd}
|
||||||
onFilterSave={onFilterSave}
|
onSearchChange={onSearchChange}
|
||||||
onTabChange={onTabChange}
|
onTabChange={onTabChange}
|
||||||
onFilterDelete={onFilterDelete}
|
onTabDelete={onTabDelete}
|
||||||
|
onTabSave={onTabSave}
|
||||||
|
tabs={tabs}
|
||||||
/>
|
/>
|
||||||
<ProductList
|
<ProductList
|
||||||
{...listProps}
|
{...listProps}
|
||||||
|
|
|
@ -1,7 +1,14 @@
|
||||||
import { stringify as stringifyQs } from "qs";
|
import { stringify as stringifyQs } from "qs";
|
||||||
import urlJoin from "url-join";
|
import urlJoin from "url-join";
|
||||||
|
|
||||||
import { ActiveTab, BulkAction, Dialog, Filters, Pagination } from "../types";
|
import {
|
||||||
|
ActiveTab,
|
||||||
|
BulkAction,
|
||||||
|
Dialog,
|
||||||
|
Filters,
|
||||||
|
Pagination,
|
||||||
|
TabActionDialog
|
||||||
|
} from "../types";
|
||||||
|
|
||||||
const productSection = "/products/";
|
const productSection = "/products/";
|
||||||
|
|
||||||
|
@ -13,8 +20,7 @@ export type ProductListUrlDialog =
|
||||||
| "publish"
|
| "publish"
|
||||||
| "unpublish"
|
| "unpublish"
|
||||||
| "delete"
|
| "delete"
|
||||||
| "save-search"
|
| TabActionDialog;
|
||||||
| "delete-search";
|
|
||||||
export enum ProductListUrlFiltersEnum {
|
export enum ProductListUrlFiltersEnum {
|
||||||
isPublished = "isPublished",
|
isPublished = "isPublished",
|
||||||
priceFrom = "priceFrom",
|
priceFrom = "priceFrom",
|
||||||
|
|
|
@ -351,11 +351,11 @@ export const ProductList: React.StatelessComponent<ProductListProps> = ({
|
||||||
onFilterAdd={filter =>
|
onFilterAdd={filter =>
|
||||||
changeFilterField(createFilter(filter))
|
changeFilterField(createFilter(filter))
|
||||||
}
|
}
|
||||||
onFilterSave={() => openModal("save-search")}
|
onTabSave={() => openModal("save-search")}
|
||||||
onFilterDelete={() => openModal("delete-search")}
|
onTabDelete={() => openModal("delete-search")}
|
||||||
onTabChange={handleTabChange}
|
onTabChange={handleTabChange}
|
||||||
initialSearch={params.query || ""}
|
initialSearch={params.query || ""}
|
||||||
filterTabs={getFilterTabs()}
|
tabs={getFilterTabs().map(tab => tab.name)}
|
||||||
/>
|
/>
|
||||||
<ActionDialog
|
<ActionDialog
|
||||||
open={params.action === "delete"}
|
open={params.action === "delete"}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { defineMessages, IntlShape } from "react-intl";
|
import { defineMessages, IntlShape } from "react-intl";
|
||||||
|
|
||||||
import { FilterContentSubmitData } from "../../../components/Filter";
|
import { FilterContentSubmitData } from "../../../components/Filter";
|
||||||
import { Filter } from "../../../components/TableFilter";
|
import { Filter } from "../../../components/TableFilter";
|
||||||
import {
|
import {
|
||||||
|
|
|
@ -33,7 +33,7 @@ const ShippingZoneDetails: React.StatelessComponent<
|
||||||
const notify = useNotifier();
|
const notify = useNotifier();
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
const closeModal = () => navigate(shippingZoneUrl(id));
|
const closeModal = () => navigate(shippingZoneUrl(id), true);
|
||||||
|
|
||||||
const onShippingRateCreate = (data: CreateShippingRate) => {
|
const onShippingRateCreate = (data: CreateShippingRate) => {
|
||||||
if (data.shippingPriceCreate.errors.length === 0) {
|
if (data.shippingPriceCreate.errors.length === 0) {
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import Card from "@material-ui/core/Card";
|
|
||||||
import {
|
import {
|
||||||
createStyles,
|
createStyles,
|
||||||
Theme,
|
Theme,
|
||||||
|
@ -84,7 +83,6 @@ const StaffList = withStyles(styles, { name: "StaffList" })(
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card>
|
|
||||||
<Table>
|
<Table>
|
||||||
<TableHead>
|
<TableHead>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
|
@ -125,9 +123,7 @@ const StaffList = withStyles(styles, { name: "StaffList" })(
|
||||||
[classes.tableRow]: !!staffMember
|
[classes.tableRow]: !!staffMember
|
||||||
})}
|
})}
|
||||||
hover={!!staffMember}
|
hover={!!staffMember}
|
||||||
onClick={
|
onClick={!!staffMember ? onRowClick(staffMember.id) : undefined}
|
||||||
!!staffMember ? onRowClick(staffMember.id) : undefined
|
|
||||||
}
|
|
||||||
key={staffMember ? staffMember.id : "skeleton"}
|
key={staffMember ? staffMember.id : "skeleton"}
|
||||||
>
|
>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
|
@ -139,9 +135,7 @@ const StaffList = withStyles(styles, { name: "StaffList" })(
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<div className={classes.avatarDefault}>
|
<div className={classes.avatarDefault}>
|
||||||
<Typography>
|
<Typography>{getUserInitials(staffMember)}</Typography>
|
||||||
{getUserInitials(staffMember)}
|
|
||||||
</Typography>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
@ -185,7 +179,6 @@ const StaffList = withStyles(styles, { name: "StaffList" })(
|
||||||
)}
|
)}
|
||||||
</TableBody>
|
</TableBody>
|
||||||
</Table>
|
</Table>
|
||||||
</Card>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,26 +1,37 @@
|
||||||
import Button from "@material-ui/core/Button";
|
import Button from "@material-ui/core/Button";
|
||||||
|
import Card from "@material-ui/core/Card";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
|
|
||||||
import AppHeader from "@saleor/components/AppHeader";
|
import AppHeader from "@saleor/components/AppHeader";
|
||||||
import { Container } from "@saleor/components/Container";
|
import { Container } from "@saleor/components/Container";
|
||||||
import PageHeader from "@saleor/components/PageHeader";
|
import PageHeader from "@saleor/components/PageHeader";
|
||||||
|
import SearchBar from "@saleor/components/SearchBar";
|
||||||
import { sectionNames } from "@saleor/intl";
|
import { sectionNames } from "@saleor/intl";
|
||||||
import { ListProps } from "@saleor/types";
|
import { ListProps, SearchPageProps, TabPageProps } from "@saleor/types";
|
||||||
import { StaffList_staffUsers_edges_node } from "../../types/StaffList";
|
import { StaffList_staffUsers_edges_node } from "../../types/StaffList";
|
||||||
import StaffList from "../StaffList/StaffList";
|
import StaffList from "../StaffList/StaffList";
|
||||||
|
|
||||||
export interface StaffListPageProps extends ListProps {
|
export interface StaffListPageProps
|
||||||
|
extends ListProps,
|
||||||
|
SearchPageProps,
|
||||||
|
TabPageProps {
|
||||||
staffMembers: StaffList_staffUsers_edges_node[];
|
staffMembers: StaffList_staffUsers_edges_node[];
|
||||||
onAdd: () => void;
|
onAdd: () => void;
|
||||||
onBack: () => void;
|
onBack: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const StaffListPage: React.StatelessComponent<StaffListPageProps> = ({
|
const StaffListPage: React.StatelessComponent<StaffListPageProps> = ({
|
||||||
disabled,
|
currentTab,
|
||||||
|
initialSearch,
|
||||||
onAdd,
|
onAdd,
|
||||||
|
onAll,
|
||||||
onBack,
|
onBack,
|
||||||
|
onSearchChange,
|
||||||
|
onTabChange,
|
||||||
|
onTabDelete,
|
||||||
|
onTabSave,
|
||||||
|
tabs,
|
||||||
...listProps
|
...listProps
|
||||||
}) => {
|
}) => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
@ -31,19 +42,33 @@ const StaffListPage: React.StatelessComponent<StaffListPageProps> = ({
|
||||||
{intl.formatMessage(sectionNames.configuration)}
|
{intl.formatMessage(sectionNames.configuration)}
|
||||||
</AppHeader>
|
</AppHeader>
|
||||||
<PageHeader title={intl.formatMessage(sectionNames.staff)}>
|
<PageHeader title={intl.formatMessage(sectionNames.staff)}>
|
||||||
<Button
|
<Button color="primary" variant="contained" onClick={onAdd}>
|
||||||
color="primary"
|
|
||||||
disabled={disabled}
|
|
||||||
variant="contained"
|
|
||||||
onClick={onAdd}
|
|
||||||
>
|
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
defaultMessage="Invite staff member"
|
defaultMessage="Invite staff member"
|
||||||
description="button"
|
description="button"
|
||||||
/>
|
/>
|
||||||
</Button>
|
</Button>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
<StaffList disabled={disabled} {...listProps} />
|
<Card>
|
||||||
|
<SearchBar
|
||||||
|
allTabLabel={intl.formatMessage({
|
||||||
|
defaultMessage: "All Staff Members",
|
||||||
|
description: "tab name"
|
||||||
|
})}
|
||||||
|
currentTab={currentTab}
|
||||||
|
initialSearch={initialSearch}
|
||||||
|
searchPlaceholder={intl.formatMessage({
|
||||||
|
defaultMessage: "Search Staff Member"
|
||||||
|
})}
|
||||||
|
tabs={tabs}
|
||||||
|
onAll={onAll}
|
||||||
|
onSearchChange={onSearchChange}
|
||||||
|
onTabChange={onTabChange}
|
||||||
|
onTabDelete={onTabDelete}
|
||||||
|
onTabSave={onTabSave}
|
||||||
|
/>
|
||||||
|
<StaffList {...listProps} />
|
||||||
|
</Card>
|
||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -30,8 +30,20 @@ export const staffMemberDetailsFragment = gql`
|
||||||
`;
|
`;
|
||||||
const staffList = gql`
|
const staffList = gql`
|
||||||
${staffMemberFragment}
|
${staffMemberFragment}
|
||||||
query StaffList($first: Int, $after: String, $last: Int, $before: String) {
|
query StaffList(
|
||||||
staffUsers(before: $before, after: $after, first: $first, last: $last) {
|
$first: Int
|
||||||
|
$after: String
|
||||||
|
$last: Int
|
||||||
|
$before: String
|
||||||
|
$filter: StaffUserInput
|
||||||
|
) {
|
||||||
|
staffUsers(
|
||||||
|
before: $before
|
||||||
|
after: $after
|
||||||
|
first: $first
|
||||||
|
last: $last
|
||||||
|
filter: $filter
|
||||||
|
) {
|
||||||
edges {
|
edges {
|
||||||
cursor
|
cursor
|
||||||
node {
|
node {
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
// This file was automatically generated and should not be edited.
|
// This file was automatically generated and should not be edited.
|
||||||
|
|
||||||
import { PermissionEnum } from "./../../types/globalTypes";
|
import { StaffUserInput, PermissionEnum } from "./../../types/globalTypes";
|
||||||
|
|
||||||
// ====================================================
|
// ====================================================
|
||||||
// GraphQL query operation: StaffList
|
// GraphQL query operation: StaffList
|
||||||
|
@ -64,4 +64,5 @@ export interface StaffListVariables {
|
||||||
after?: string | null;
|
after?: string | null;
|
||||||
last?: number | null;
|
last?: number | null;
|
||||||
before?: string | null;
|
before?: string | null;
|
||||||
|
filter?: StaffUserInput | null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,28 @@
|
||||||
import { stringify as stringifyQs } from "qs";
|
import { stringify as stringifyQs } from "qs";
|
||||||
import urlJoin from "url-join";
|
import urlJoin from "url-join";
|
||||||
|
|
||||||
import { BulkAction, Dialog, Pagination } from "../types";
|
import {
|
||||||
|
ActiveTab,
|
||||||
|
BulkAction,
|
||||||
|
Dialog,
|
||||||
|
Filters,
|
||||||
|
Pagination,
|
||||||
|
TabActionDialog
|
||||||
|
} from "../types";
|
||||||
|
|
||||||
const staffSection = "/staff/";
|
const staffSection = "/staff/";
|
||||||
|
|
||||||
export const staffListPath = staffSection;
|
export const staffListPath = staffSection;
|
||||||
export type StaffListUrlDialog = "add" | "remove";
|
export enum StaffListUrlFiltersEnum {
|
||||||
export type StaffListUrlQueryParams = BulkAction &
|
query = "query"
|
||||||
|
}
|
||||||
|
export type StaffListUrlFilters = Filters<StaffListUrlFiltersEnum>;
|
||||||
|
export type StaffListUrlDialog = "add" | "remove" | TabActionDialog;
|
||||||
|
export type StaffListUrlQueryParams = ActiveTab &
|
||||||
|
BulkAction &
|
||||||
Dialog<StaffListUrlDialog> &
|
Dialog<StaffListUrlDialog> &
|
||||||
Pagination;
|
Pagination &
|
||||||
|
StaffListUrlFilters;
|
||||||
export const staffListUrl = (params?: StaffListUrlQueryParams) =>
|
export const staffListUrl = (params?: StaffListUrlQueryParams) =>
|
||||||
staffListPath + "?" + stringifyQs(params);
|
staffListPath + "?" + stringifyQs(params);
|
||||||
|
|
||||||
|
|
|
@ -8,22 +8,36 @@ import usePaginator, {
|
||||||
} from "@saleor/hooks/usePaginator";
|
} from "@saleor/hooks/usePaginator";
|
||||||
import { useIntl } from "react-intl";
|
import { useIntl } from "react-intl";
|
||||||
|
|
||||||
|
import DeleteFilterTabDialog from "@saleor/components/DeleteFilterTabDialog";
|
||||||
|
import SaveFilterTabDialog, {
|
||||||
|
SaveFilterTabDialogFormData
|
||||||
|
} from "@saleor/components/SaveFilterTabDialog";
|
||||||
import { configurationMenuUrl } from "@saleor/configuration";
|
import { configurationMenuUrl } from "@saleor/configuration";
|
||||||
import { commonMessages } from "@saleor/intl";
|
import { commonMessages } from "@saleor/intl";
|
||||||
import { getMutationState, maybe } from "@saleor/misc";
|
import { getMutationState, maybe } from "@saleor/misc";
|
||||||
import { ListViews } from "@saleor/types";
|
import { ListViews } from "@saleor/types";
|
||||||
import StaffAddMemberDialog, {
|
import StaffAddMemberDialog, {
|
||||||
FormData as AddStaffMemberForm
|
FormData as AddStaffMemberForm
|
||||||
} from "../components/StaffAddMemberDialog";
|
} from "../../components/StaffAddMemberDialog";
|
||||||
import StaffListPage from "../components/StaffListPage";
|
import StaffListPage from "../../components/StaffListPage";
|
||||||
import { TypedStaffMemberAddMutation } from "../mutations";
|
import { TypedStaffMemberAddMutation } from "../../mutations";
|
||||||
import { TypedStaffListQuery } from "../queries";
|
import { TypedStaffListQuery } from "../../queries";
|
||||||
import { StaffMemberAdd } from "../types/StaffMemberAdd";
|
import { StaffMemberAdd } from "../../types/StaffMemberAdd";
|
||||||
import {
|
import {
|
||||||
staffListUrl,
|
staffListUrl,
|
||||||
|
StaffListUrlDialog,
|
||||||
|
StaffListUrlFilters,
|
||||||
StaffListUrlQueryParams,
|
StaffListUrlQueryParams,
|
||||||
staffMemberDetailsUrl
|
staffMemberDetailsUrl
|
||||||
} from "../urls";
|
} from "../../urls";
|
||||||
|
import {
|
||||||
|
areFiltersApplied,
|
||||||
|
deleteFilterTab,
|
||||||
|
getActiveFilters,
|
||||||
|
getFilterTabs,
|
||||||
|
getFilterVariables,
|
||||||
|
saveFilterTab
|
||||||
|
} from "./filter";
|
||||||
|
|
||||||
interface StaffListProps {
|
interface StaffListProps {
|
||||||
params: StaffListUrlQueryParams;
|
params: StaffListUrlQueryParams;
|
||||||
|
@ -40,6 +54,24 @@ export const StaffList: React.StatelessComponent<StaffListProps> = ({
|
||||||
);
|
);
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
|
const tabs = getFilterTabs();
|
||||||
|
|
||||||
|
const currentTab =
|
||||||
|
params.activeTab === undefined
|
||||||
|
? areFiltersApplied(params)
|
||||||
|
? tabs.length + 1
|
||||||
|
: 0
|
||||||
|
: parseInt(params.activeTab, 0);
|
||||||
|
|
||||||
|
const changeFilterField = (filter: StaffListUrlFilters) =>
|
||||||
|
navigate(
|
||||||
|
staffListUrl({
|
||||||
|
...getActiveFilters(params),
|
||||||
|
...filter,
|
||||||
|
activeTab: undefined
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
const closeModal = () =>
|
const closeModal = () =>
|
||||||
navigate(
|
navigate(
|
||||||
staffListUrl({
|
staffListUrl({
|
||||||
|
@ -50,9 +82,45 @@ export const StaffList: React.StatelessComponent<StaffListProps> = ({
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const openModal = (action: StaffListUrlDialog, ids?: string[]) =>
|
||||||
|
navigate(
|
||||||
|
staffListUrl({
|
||||||
|
...params,
|
||||||
|
action,
|
||||||
|
ids
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleTabChange = (tab: number) => {
|
||||||
|
navigate(
|
||||||
|
staffListUrl({
|
||||||
|
activeTab: tab.toString(),
|
||||||
|
...getFilterTabs()[tab - 1].data
|
||||||
|
})
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleTabDelete = () => {
|
||||||
|
deleteFilterTab(currentTab);
|
||||||
|
navigate(staffListUrl());
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleTabSave = (data: SaveFilterTabDialogFormData) => {
|
||||||
|
saveFilterTab(data.name, getActiveFilters(params));
|
||||||
|
handleTabChange(tabs.length + 1);
|
||||||
|
};
|
||||||
|
|
||||||
const paginationState = createPaginationState(settings.rowNumber, params);
|
const paginationState = createPaginationState(settings.rowNumber, params);
|
||||||
|
const queryVariables = React.useMemo(
|
||||||
|
() => ({
|
||||||
|
...paginationState,
|
||||||
|
filter: getFilterVariables(params)
|
||||||
|
}),
|
||||||
|
[params]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TypedStaffListQuery displayLoader variables={paginationState}>
|
<TypedStaffListQuery displayLoader variables={queryVariables}>
|
||||||
{({ data, loading }) => {
|
{({ data, loading }) => {
|
||||||
const handleStaffMemberAddSuccess = (data: StaffMemberAdd) => {
|
const handleStaffMemberAddSuccess = (data: StaffMemberAdd) => {
|
||||||
if (data.staffCreate.errors.length === 0) {
|
if (data.staffCreate.errors.length === 0) {
|
||||||
|
@ -97,6 +165,14 @@ export const StaffList: React.StatelessComponent<StaffListProps> = ({
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<StaffListPage
|
<StaffListPage
|
||||||
|
currentTab={currentTab}
|
||||||
|
initialSearch={params.query || ""}
|
||||||
|
onSearchChange={query => changeFilterField({ query })}
|
||||||
|
onAll={() => navigate(staffListUrl())}
|
||||||
|
onTabChange={handleTabChange}
|
||||||
|
onTabDelete={() => openModal("delete-search")}
|
||||||
|
onTabSave={() => openModal("save-search")}
|
||||||
|
tabs={tabs.map(tab => tab.name)}
|
||||||
disabled={loading || addStaffMemberData.loading}
|
disabled={loading || addStaffMemberData.loading}
|
||||||
settings={settings}
|
settings={settings}
|
||||||
pageInfo={pageInfo}
|
pageInfo={pageInfo}
|
||||||
|
@ -126,6 +202,19 @@ export const StaffList: React.StatelessComponent<StaffListProps> = ({
|
||||||
onClose={closeModal}
|
onClose={closeModal}
|
||||||
onConfirm={handleStaffMemberAdd}
|
onConfirm={handleStaffMemberAdd}
|
||||||
/>
|
/>
|
||||||
|
<SaveFilterTabDialog
|
||||||
|
open={params.action === "save-search"}
|
||||||
|
confirmButtonState="default"
|
||||||
|
onClose={closeModal}
|
||||||
|
onSubmit={handleTabSave}
|
||||||
|
/>
|
||||||
|
<DeleteFilterTabDialog
|
||||||
|
open={params.action === "delete-search"}
|
||||||
|
confirmButtonState="default"
|
||||||
|
onClose={closeModal}
|
||||||
|
onSubmit={handleTabDelete}
|
||||||
|
tabName={maybe(() => tabs[currentTab - 1].name, "...")}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
31
src/staff/views/StaffList/filter.ts
Normal file
31
src/staff/views/StaffList/filter.ts
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
import { StaffUserInput } from "@saleor/types/globalTypes";
|
||||||
|
import {
|
||||||
|
createFilterTabUtils,
|
||||||
|
createFilterUtils
|
||||||
|
} from "../../../utils/filters";
|
||||||
|
import {
|
||||||
|
StaffListUrlFilters,
|
||||||
|
StaffListUrlFiltersEnum,
|
||||||
|
StaffListUrlQueryParams
|
||||||
|
} from "../../urls";
|
||||||
|
|
||||||
|
export const STAFF_FILTERS_KEY = "staffFilters";
|
||||||
|
|
||||||
|
export function getFilterVariables(
|
||||||
|
params: StaffListUrlFilters
|
||||||
|
): StaffUserInput {
|
||||||
|
return {
|
||||||
|
search: params.query
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export const {
|
||||||
|
deleteFilterTab,
|
||||||
|
getFilterTabs,
|
||||||
|
saveFilterTab
|
||||||
|
} = createFilterTabUtils<StaffListUrlFilters>(STAFF_FILTERS_KEY);
|
||||||
|
|
||||||
|
export const { areFiltersApplied, getActiveFilters } = createFilterUtils<
|
||||||
|
StaffListUrlQueryParams,
|
||||||
|
StaffListUrlFilters
|
||||||
|
>(StaffListUrlFiltersEnum);
|
2
src/staff/views/StaffList/index.ts
Normal file
2
src/staff/views/StaffList/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
export { default } from "./StaffList";
|
||||||
|
export * from "./StaffList";
|
File diff suppressed because it is too large
Load diff
|
@ -5,12 +5,19 @@ import AttributeListPage, {
|
||||||
AttributeListPageProps
|
AttributeListPageProps
|
||||||
} from "@saleor/attributes/components/AttributeListPage";
|
} from "@saleor/attributes/components/AttributeListPage";
|
||||||
import { attributes } from "@saleor/attributes/fixtures";
|
import { attributes } from "@saleor/attributes/fixtures";
|
||||||
import { listActionsProps, pageListProps } from "@saleor/fixtures";
|
import {
|
||||||
|
listActionsProps,
|
||||||
|
pageListProps,
|
||||||
|
searchPageProps,
|
||||||
|
tabPageProps
|
||||||
|
} from "@saleor/fixtures";
|
||||||
import Decorator from "../../Decorator";
|
import Decorator from "../../Decorator";
|
||||||
|
|
||||||
const props: AttributeListPageProps = {
|
const props: AttributeListPageProps = {
|
||||||
...pageListProps.default,
|
...pageListProps.default,
|
||||||
...listActionsProps,
|
...listActionsProps,
|
||||||
|
...tabPageProps,
|
||||||
|
...searchPageProps,
|
||||||
attributes
|
attributes
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,12 @@ import React from "react";
|
||||||
|
|
||||||
import CategoryListPage from "../../../categories/components/CategoryListPage";
|
import CategoryListPage from "../../../categories/components/CategoryListPage";
|
||||||
import { categories } from "../../../categories/fixtures";
|
import { categories } from "../../../categories/fixtures";
|
||||||
import { listActionsProps, pageListProps } from "../../../fixtures";
|
import {
|
||||||
|
listActionsProps,
|
||||||
|
pageListProps,
|
||||||
|
searchPageProps,
|
||||||
|
tabPageProps
|
||||||
|
} from "../../../fixtures";
|
||||||
import Decorator from "../../Decorator";
|
import Decorator from "../../Decorator";
|
||||||
|
|
||||||
const categoryTableProps = {
|
const categoryTableProps = {
|
||||||
|
@ -11,6 +16,8 @@ const categoryTableProps = {
|
||||||
onAddCategory: undefined,
|
onAddCategory: undefined,
|
||||||
onCategoryClick: () => undefined,
|
onCategoryClick: () => undefined,
|
||||||
...listActionsProps,
|
...listActionsProps,
|
||||||
|
...tabPageProps,
|
||||||
|
...searchPageProps,
|
||||||
...pageListProps.default
|
...pageListProps.default
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -5,12 +5,19 @@ import CollectionListPage, {
|
||||||
CollectionListPageProps
|
CollectionListPageProps
|
||||||
} from "../../../collections/components/CollectionListPage";
|
} from "../../../collections/components/CollectionListPage";
|
||||||
import { collections } from "../../../collections/fixtures";
|
import { collections } from "../../../collections/fixtures";
|
||||||
import { listActionsProps, pageListProps } from "../../../fixtures";
|
import {
|
||||||
|
listActionsProps,
|
||||||
|
pageListProps,
|
||||||
|
searchPageProps,
|
||||||
|
tabPageProps
|
||||||
|
} from "../../../fixtures";
|
||||||
import Decorator from "../../Decorator";
|
import Decorator from "../../Decorator";
|
||||||
|
|
||||||
const props: CollectionListPageProps = {
|
const props: CollectionListPageProps = {
|
||||||
...listActionsProps,
|
...listActionsProps,
|
||||||
...pageListProps.default,
|
...pageListProps.default,
|
||||||
|
...searchPageProps,
|
||||||
|
...tabPageProps,
|
||||||
collections
|
collections
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -19,4 +26,5 @@ storiesOf("Views / Collections / Collection list", module)
|
||||||
.add("default", () => <CollectionListPage {...props} />)
|
.add("default", () => <CollectionListPage {...props} />)
|
||||||
.add("loading", () => (
|
.add("loading", () => (
|
||||||
<CollectionListPage {...props} collections={undefined} disabled={true} />
|
<CollectionListPage {...props} collections={undefined} disabled={true} />
|
||||||
));
|
))
|
||||||
|
.add("no data", () => <CollectionListPage {...props} collections={[]} />);
|
||||||
|
|
|
@ -5,12 +5,19 @@ import CustomerListPage, {
|
||||||
CustomerListPageProps
|
CustomerListPageProps
|
||||||
} from "../../../customers/components/CustomerListPage";
|
} from "../../../customers/components/CustomerListPage";
|
||||||
import { customerList } from "../../../customers/fixtures";
|
import { customerList } from "../../../customers/fixtures";
|
||||||
import { listActionsProps, pageListProps } from "../../../fixtures";
|
import {
|
||||||
|
listActionsProps,
|
||||||
|
pageListProps,
|
||||||
|
searchPageProps,
|
||||||
|
tabPageProps
|
||||||
|
} from "../../../fixtures";
|
||||||
import Decorator from "../../Decorator";
|
import Decorator from "../../Decorator";
|
||||||
|
|
||||||
const props: CustomerListPageProps = {
|
const props: CustomerListPageProps = {
|
||||||
...listActionsProps,
|
...listActionsProps,
|
||||||
...pageListProps.default,
|
...pageListProps.default,
|
||||||
|
...searchPageProps,
|
||||||
|
...tabPageProps,
|
||||||
customers: customerList
|
customers: customerList
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -5,12 +5,19 @@ import SaleListPage, {
|
||||||
SaleListPageProps
|
SaleListPageProps
|
||||||
} from "../../../discounts/components/SaleListPage";
|
} from "../../../discounts/components/SaleListPage";
|
||||||
import { saleList } from "../../../discounts/fixtures";
|
import { saleList } from "../../../discounts/fixtures";
|
||||||
import { listActionsProps, pageListProps } from "../../../fixtures";
|
import {
|
||||||
|
listActionsProps,
|
||||||
|
pageListProps,
|
||||||
|
searchPageProps,
|
||||||
|
tabPageProps
|
||||||
|
} from "../../../fixtures";
|
||||||
import Decorator from "../../Decorator";
|
import Decorator from "../../Decorator";
|
||||||
|
|
||||||
const props: SaleListPageProps = {
|
const props: SaleListPageProps = {
|
||||||
...listActionsProps,
|
...listActionsProps,
|
||||||
...pageListProps.default,
|
...pageListProps.default,
|
||||||
|
...searchPageProps,
|
||||||
|
...tabPageProps,
|
||||||
defaultCurrency: "USD",
|
defaultCurrency: "USD",
|
||||||
sales: saleList
|
sales: saleList
|
||||||
};
|
};
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue