Merge pull request #234 from mirumee/ref/update-mui

Update @material-ui to v4
This commit is contained in:
Dominik Żegleń 2019-11-07 15:08:20 +01:00 committed by GitHub
commit 12659ef660
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
357 changed files with 47829 additions and 49678 deletions

View file

@ -3,7 +3,7 @@ language: node_js
sudo: false sudo: false
node_js: node_js:
- "11.15" - "12.12"
branches: branches:
only: only:

View file

@ -55,3 +55,4 @@ All notable, unreleased changes to this project will be documented in this file.
- Fix minor bugs - #230 by @dominik-zeglen - Fix minor bugs - #230 by @dominik-zeglen
- Fix permission handling - #231 by @dominik-zeglen - Fix permission handling - #231 by @dominik-zeglen
- Use React.FC instead of deprecated React.StatelessComponent type - #245 by @dominik-zeglen - Use React.FC instead of deprecated React.StatelessComponent type - #245 by @dominik-zeglen
- Update @material-ui to v4 - #234 by @dominik-zeglen

View file

@ -1,4 +1,5 @@
module.exports = api => { module.exports = api => {
const isExtract = api.env("extract");
const isTest = api.env("test"); const isTest = api.env("test");
const isStorybook = api.env("storybook"); const isStorybook = api.env("storybook");
@ -30,16 +31,20 @@ module.exports = api => {
} }
], ],
"@babel/plugin-proposal-object-rest-spread", "@babel/plugin-proposal-object-rest-spread",
"react-intl-auto", "react-intl-auto"
[ ];
if (isExtract) {
plugins.push([
"react-intl", "react-intl",
{ {
extractFromFormatMessageCall: true, extractFromFormatMessageCall: true,
messagesDir: "build/locale/" messagesDir: "build/locale/"
} }
], ]);
"macros" }
];
plugins.push("macros");
return { return {
presets, presets,

View file

@ -1,6 +1,6 @@
msgid "" msgid ""
msgstr "" msgstr ""
"POT-Creation-Date: 2019-11-06T13:15:56.589Z\n" "POT-Creation-Date: 2019-11-07T13:41:50.654Z\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"
@ -28,7 +28,7 @@ msgid "*Optional. Adding product to collection helps users find it."
msgstr "" msgstr ""
#: build/locale/src/attributes/views/AttributeCreate/AttributeCreate.json #: build/locale/src/attributes/views/AttributeCreate/AttributeCreate.json
#. [src.attributes.views.AttributeCreate.2348058468] - attribute value edit error #. [src.attributes.views.AttributeCreate.354316953] - attribute value edit error
#. defaultMessage is: #. defaultMessage is:
#. A value named {name} already exists #. A value named {name} already exists
msgctxt "attribute value edit error" msgctxt "attribute value edit error"
@ -623,6 +623,14 @@ msgctxt "product attribute error"
msgid "All attributes should have value" msgid "All attributes should have value"
msgstr "" msgstr ""
#: build/locale/src/webhooks/components/WebhookEvents/WebhookEvents.json
#. [src.webhooks.components.WebhookEvents.2454751033] - event
#. defaultMessage is:
#. All events
msgctxt "event"
msgid "All events"
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:
@ -663,14 +671,6 @@ msgctxt "description"
msgid "Anonymous user" msgid "Anonymous user"
msgstr "" msgstr ""
#: build/locale/src/webhooks/components/WebhookEvents/WebhookEvents.json
#. [src.webhooks.components.WebhookEvents.3053363669] - event
#. defaultMessage is:
#. Any events
msgctxt "event"
msgid "Any events"
msgstr ""
#: build/locale/src/discounts/components/VoucherSummary/VoucherSummary.json #: build/locale/src/discounts/components/VoucherSummary/VoucherSummary.json
#. [src.discounts.components.VoucherSummary.2735425668] - voucher #. [src.discounts.components.VoucherSummary.2735425668] - voucher
#. defaultMessage is: #. defaultMessage is:
@ -728,7 +728,7 @@ msgid "Are you sure you want to cancel this fulfillment?"
msgstr "" msgstr ""
#: build/locale/src/orders/components/OrderBulkCancelDialog/OrderBulkCancelDialog.json #: build/locale/src/orders/components/OrderBulkCancelDialog/OrderBulkCancelDialog.json
#. [src.orders.components.OrderBulkCancelDialog.276130122] #. [src.orders.components.OrderBulkCancelDialog.3011571869]
#. defaultMessage is: #. defaultMessage is:
#. Are you sure you want to cancel {counter,plural,one{this order} other{{displayQuantity} orders}}? #. Are you sure you want to cancel {counter,plural,one{this order} other{{displayQuantity} orders}}?
msgctxt "description" msgctxt "description"
@ -736,7 +736,7 @@ msgid "Are you sure you want to cancel {counter,plural,one{this order} other{{di
msgstr "" msgstr ""
#: build/locale/src/attributes/components/AttributeValueDeleteDialog/AttributeValueDeleteDialog.json #: build/locale/src/attributes/components/AttributeValueDeleteDialog/AttributeValueDeleteDialog.json
#. [src.attributes.components.AttributeValueDeleteDialog.273524270] - delete attribute value #. [src.attributes.components.AttributeValueDeleteDialog.1326420604] - delete attribute value
#. defaultMessage is: #. defaultMessage is:
#. Are you sure you want to delete "{name}" value? #. Are you sure you want to delete "{name}" value?
msgctxt "delete attribute value" msgctxt "delete attribute value"
@ -744,7 +744,7 @@ msgid "Are you sure you want to delete \"{name}\" value?"
msgstr "" msgstr ""
#: build/locale/src/attributes/components/AttributeValueDeleteDialog/AttributeValueDeleteDialog.json #: build/locale/src/attributes/components/AttributeValueDeleteDialog/AttributeValueDeleteDialog.json
#. [src.attributes.components.AttributeValueDeleteDialog.1934550550] #. [src.attributes.components.AttributeValueDeleteDialog.4031078167]
#. defaultMessage is: #. defaultMessage is:
#. Are you sure you want to delete "{name}" value? If you delete it you wont be able to assign it to any of the products with "{attributeName}" attribute. #. Are you sure you want to delete "{name}" value? If you delete it you wont be able to assign it to any of the products with "{attributeName}" attribute.
msgctxt "description" msgctxt "description"
@ -760,11 +760,11 @@ msgid "Are you sure you want to delete collection's image?"
msgstr "" msgstr ""
#: build/locale/src/orders/components/OrderDraftCancelDialog/OrderDraftCancelDialog.json #: build/locale/src/orders/components/OrderDraftCancelDialog/OrderDraftCancelDialog.json
#. [src.orders.components.OrderDraftCancelDialog.36681973] #. [src.orders.components.OrderDraftCancelDialog.66064347]
#. defaultMessage is: #. defaultMessage is:
#. Are you sure you want to delete draft #{number}? #. Are you sure you want to delete draft #{orderNumber}?
msgctxt "description" msgctxt "description"
msgid "Are you sure you want to delete draft #{number}?" msgid "Are you sure you want to delete draft #{orderNumber}?"
msgstr "" msgstr ""
#: build/locale/src/navigation/views/MenuDetails/index.json #: build/locale/src/navigation/views/MenuDetails/index.json
@ -832,7 +832,7 @@ msgid "Are you sure you want to delete {collectionName}?"
msgstr "" msgstr ""
#: build/locale/src/attributes/components/AttributeBulkDeleteDialog/AttributeBulkDeleteDialog.json #: build/locale/src/attributes/components/AttributeBulkDeleteDialog/AttributeBulkDeleteDialog.json
#. [src.attributes.components.AttributeBulkDeleteDialog.2916860383] - dialog content #. [src.attributes.components.AttributeBulkDeleteDialog.1860138828] - dialog content
#. defaultMessage is: #. defaultMessage is:
#. Are you sure you want to delete {counter,plural,one{this attribute} other{{displayQuantity} attributes}}? #. Are you sure you want to delete {counter,plural,one{this attribute} other{{displayQuantity} attributes}}?
msgctxt "dialog content" msgctxt "dialog content"
@ -840,7 +840,7 @@ msgid "Are you sure you want to delete {counter,plural,one{this attribute} other
msgstr "" msgstr ""
#: build/locale/src/categories/views/CategoryDetails.json #: build/locale/src/categories/views/CategoryDetails.json
#. [src.categories.views.299584400] #. [src.categories.views.982216972]
#. 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}}?
msgctxt "description" msgctxt "description"
@ -848,7 +848,7 @@ msgid "Are you sure you want to delete {counter,plural,one{this attribute} other
msgstr "" msgstr ""
#: build/locale/src/categories/views/CategoryDetails.json #: build/locale/src/categories/views/CategoryDetails.json
#. [src.categories.views.3231188861] #. [src.categories.views.3920301974]
#. defaultMessage is: #. defaultMessage is:
#. Are you sure you want to delete {counter,plural,one{this attribute} other{{displayQuantity} products}}? #. Are you sure you want to delete {counter,plural,one{this attribute} other{{displayQuantity} products}}?
msgctxt "description" msgctxt "description"
@ -856,7 +856,7 @@ msgid "Are you sure you want to delete {counter,plural,one{this attribute} other
msgstr "" msgstr ""
#: build/locale/src/categories/views/CategoryList/CategoryList.json #: build/locale/src/categories/views/CategoryList/CategoryList.json
#. [src.categories.views.CategoryList.2144707585] #. [src.categories.views.CategoryList.1592907702]
#. defaultMessage is: #. defaultMessage is:
#. Are you sure you want to delete {counter,plural,one{this category} other{{displayQuantity} categories}}? #. Are you sure you want to delete {counter,plural,one{this category} other{{displayQuantity} categories}}?
msgctxt "description" msgctxt "description"
@ -864,7 +864,7 @@ msgid "Are you sure you want to delete {counter,plural,one{this category} other{
msgstr "" msgstr ""
#: build/locale/src/collections/views/CollectionList/CollectionList.json #: build/locale/src/collections/views/CollectionList/CollectionList.json
#. [src.collections.views.CollectionList.2497542455] #. [src.collections.views.CollectionList.1421224348]
#. 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"
@ -872,7 +872,7 @@ msgid "Are you sure you want to delete {counter,plural,one{this collection} othe
msgstr "" msgstr ""
#: build/locale/src/customers/views/CustomerList/CustomerList.json #: build/locale/src/customers/views/CustomerList/CustomerList.json
#. [src.customers.views.CustomerList.409347866] #. [src.customers.views.CustomerList.3616300497]
#. 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"
@ -888,7 +888,7 @@ msgid "Are you sure you want to delete {counter,plural,one{this menu} other{{dis
msgstr "" msgstr ""
#: build/locale/src/orders/views/OrderDraftList/OrderDraftList.json #: build/locale/src/orders/views/OrderDraftList/OrderDraftList.json
#. [src.orders.views.OrderDraftList.1389231130] - dialog content #. [src.orders.views.OrderDraftList.1398914741] - 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"
@ -896,7 +896,7 @@ msgid "Are you sure you want to delete {counter,plural,one{this order draft} oth
msgstr "" msgstr ""
#: build/locale/src/pages/views/PageList.json #: build/locale/src/pages/views/PageList.json
#. [src.pages.views.3382708469] - dialog content #. [src.pages.views.808633099] - dialog content
#. defaultMessage is: #. defaultMessage is:
#. Are you sure you want to delete {counter,plural,one{this page} other{{displayQuantity} pages}}? #. Are you sure you want to delete {counter,plural,one{this page} other{{displayQuantity} pages}}?
msgctxt "dialog content" msgctxt "dialog content"
@ -904,7 +904,7 @@ msgid "Are you sure you want to delete {counter,plural,one{this page} other{{dis
msgstr "" msgstr ""
#: build/locale/src/productTypes/views/ProductTypeList/ProductTypeList.json #: build/locale/src/productTypes/views/ProductTypeList/ProductTypeList.json
#. [src.productTypes.views.ProductTypeList.2294091098] - dialog content #. [src.productTypes.views.ProductTypeList.2787668922] - 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"
@ -912,7 +912,7 @@ msgid "Are you sure you want to delete {counter,plural,one{this product type} ot
msgstr "" msgstr ""
#: build/locale/src/products/views/ProductList/ProductList.json #: build/locale/src/products/views/ProductList/ProductList.json
#. [src.products.views.ProductList.2742463171] - dialog content #. [src.products.views.ProductList.785143617] - dialog content
#. defaultMessage is: #. defaultMessage is:
#. Are you sure you want to delete {counter,plural,one{this product} other{{displayQuantity} products}}? #. Are you sure you want to delete {counter,plural,one{this product} other{{displayQuantity} products}}?
msgctxt "dialog content" msgctxt "dialog content"
@ -920,7 +920,7 @@ msgid "Are you sure you want to delete {counter,plural,one{this product} other{{
msgstr "" msgstr ""
#: build/locale/src/discounts/views/SaleList/SaleList.json #: build/locale/src/discounts/views/SaleList/SaleList.json
#. [src.discounts.views.SaleList.2516361175] - dialog content #. [src.discounts.views.SaleList.315033130] - 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"
@ -928,7 +928,7 @@ msgid "Are you sure you want to delete {counter,plural,one{this sale} other{{dis
msgstr "" msgstr ""
#: build/locale/src/shipping/views/ShippingZonesList.json #: build/locale/src/shipping/views/ShippingZonesList.json
#. [src.shipping.views.3698270769] - dialog content #. [src.shipping.views.226833304] - dialog content
#. defaultMessage is: #. defaultMessage is:
#. Are you sure you want to delete {counter,plural,one{this shipping zone} other{{displayQuantity} shipping zones}}? #. Are you sure you want to delete {counter,plural,one{this shipping zone} other{{displayQuantity} shipping zones}}?
msgctxt "dialog content" msgctxt "dialog content"
@ -936,7 +936,7 @@ msgid "Are you sure you want to delete {counter,plural,one{this shipping zone} o
msgstr "" msgstr ""
#: build/locale/src/products/views/ProductUpdate/ProductUpdate.json #: build/locale/src/products/views/ProductUpdate/ProductUpdate.json
#. [src.products.views.ProductUpdate.2446451819] - dialog content #. [src.products.views.ProductUpdate.408018316] - dialog content
#. defaultMessage is: #. defaultMessage is:
#. Are you sure you want to delete {counter,plural,one{this variant} other{{displayQuantity} variants}}? #. Are you sure you want to delete {counter,plural,one{this variant} other{{displayQuantity} variants}}?
msgctxt "dialog content" msgctxt "dialog content"
@ -944,7 +944,7 @@ msgid "Are you sure you want to delete {counter,plural,one{this variant} other{{
msgstr "" msgstr ""
#: build/locale/src/discounts/views/VoucherList/VoucherList.json #: build/locale/src/discounts/views/VoucherList/VoucherList.json
#. [src.discounts.views.VoucherList.1791926983] - dialog content #. [src.discounts.views.VoucherList.3263927472] - 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"
@ -1080,11 +1080,11 @@ msgid "Are you sure you want to delete {voucherCode}?"
msgstr "" msgstr ""
#: build/locale/src/orders/components/OrderDraftFinalizeDialog/OrderDraftFinalizeDialog.json #: build/locale/src/orders/components/OrderDraftFinalizeDialog/OrderDraftFinalizeDialog.json
#. [src.orders.components.OrderDraftFinalizeDialog.1489195029] #. [src.orders.components.OrderDraftFinalizeDialog.3358029330]
#. defaultMessage is: #. defaultMessage is:
#. Are you sure you want to finalize draft #{number}? #. Are you sure you want to finalize draft #{orderNumber}?
msgctxt "description" msgctxt "description"
msgid "Are you sure you want to finalize draft #{number}?" msgid "Are you sure you want to finalize draft #{orderNumber}?"
msgstr "" msgstr ""
#: build/locale/src/orders/components/OrderMarkAsPaidDialog/OrderMarkAsPaidDialog.json #: build/locale/src/orders/components/OrderMarkAsPaidDialog/OrderMarkAsPaidDialog.json
@ -1096,7 +1096,7 @@ msgid "Are you sure you want to mark this order as paid?"
msgstr "" msgstr ""
#: build/locale/src/collections/views/CollectionList/CollectionList.json #: build/locale/src/collections/views/CollectionList/CollectionList.json
#. [src.collections.views.CollectionList.1348793822] #. [src.collections.views.CollectionList.3216529047]
#. 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"
@ -1104,7 +1104,7 @@ msgid "Are you sure you want to publish {counter,plural,one{this collection} oth
msgstr "" msgstr ""
#: build/locale/src/pages/views/PageList.json #: build/locale/src/pages/views/PageList.json
#. [src.pages.views.504298570] - dialog content #. [src.pages.views.64432778] - dialog content
#. defaultMessage is: #. defaultMessage is:
#. Are you sure you want to publish {counter,plural,one{this page} other{{displayQuantity} pages}}? #. Are you sure you want to publish {counter,plural,one{this page} other{{displayQuantity} pages}}?
msgctxt "dialog content" msgctxt "dialog content"
@ -1112,7 +1112,7 @@ msgid "Are you sure you want to publish {counter,plural,one{this page} other{{di
msgstr "" msgstr ""
#: build/locale/src/products/views/ProductList/ProductList.json #: build/locale/src/products/views/ProductList/ProductList.json
#. [src.products.views.ProductList.740606822] - dialog content #. [src.products.views.ProductList.4099592898] - dialog content
#. defaultMessage is: #. defaultMessage is:
#. Are you sure you want to publish {counter,plural,one{this product} other{{displayQuantity} products}}? #. Are you sure you want to publish {counter,plural,one{this product} other{{displayQuantity} products}}?
msgctxt "dialog content" msgctxt "dialog content"
@ -1136,19 +1136,19 @@ msgid "Are you sure you want to unassign {attributeName} from {productTypeName}?
msgstr "" msgstr ""
#: build/locale/src/productTypes/components/ProductTypeBulkAttributeUnassignDialog/ProductTypeBulkAttributeUnassignDialog.json #: build/locale/src/productTypes/components/ProductTypeBulkAttributeUnassignDialog/ProductTypeBulkAttributeUnassignDialog.json
#. [src.productTypes.components.ProductTypeBulkAttributeUnassignDialog.2500510112] - unassign multiple attributes from product type #. [src.productTypes.components.ProductTypeBulkAttributeUnassignDialog.1465383223] - unassign multiple attributes from product type
#. defaultMessage is: #. defaultMessage is:
#. Are you sure you want to unassign {counter,plural,one{this attribute} other{{displayQuantity} attributes}} from {productTypeName}? #. Are you sure you want to unassign {counter,plural,one{this attribute} other{{attributeQuantity} attributes}} from {productTypeName}?
msgctxt "unassign multiple attributes from product type" msgctxt "unassign multiple attributes from product type"
msgid "Are you sure you want to unassign {counter,plural,one{this attribute} other{{displayQuantity} attributes}} from {productTypeName}?" msgid "Are you sure you want to unassign {counter,plural,one{this attribute} other{{attributeQuantity} attributes}} from {productTypeName}?"
msgstr "" msgstr ""
#: build/locale/src/discounts/views/SaleDetails.json #: build/locale/src/discounts/views/SaleDetails.json
#. [src.discounts.views.376977560] - dialog content #. [src.discounts.views.1169376180] - dialog content
#. defaultMessage is: #. defaultMessage is:
#. Are you sure you want to unassign {counter,plural,one{this category} other{{displayQuantity} categories}}? #. Are you sure you want to unassign {counter,plural,one{this category} other{{displayQuantity} categories}}?
#: build/locale/src/discounts/views/VoucherDetails.json #: build/locale/src/discounts/views/VoucherDetails.json
#. [src.discounts.views.376977560] - dialog content #. [src.discounts.views.1169376180] - dialog content
#. defaultMessage is: #. defaultMessage is:
#. Are you sure you want to unassign {counter,plural,one{this category} other{{displayQuantity} categories}}? #. Are you sure you want to unassign {counter,plural,one{this category} other{{displayQuantity} categories}}?
msgctxt "dialog content" msgctxt "dialog content"
@ -1156,11 +1156,11 @@ msgid "Are you sure you want to unassign {counter,plural,one{this category} othe
msgstr "" msgstr ""
#: build/locale/src/discounts/views/SaleDetails.json #: build/locale/src/discounts/views/SaleDetails.json
#. [src.discounts.views.396618268] - dialog content #. [src.discounts.views.3809911073] - dialog content
#. defaultMessage is: #. defaultMessage is:
#. Are you sure you want to unassign {counter,plural,one{this collection} other{{displayQuantity} collections}}? #. Are you sure you want to unassign {counter,plural,one{this collection} other{{displayQuantity} collections}}?
#: build/locale/src/discounts/views/VoucherDetails.json #: build/locale/src/discounts/views/VoucherDetails.json
#. [src.discounts.views.396618268] - dialog content #. [src.discounts.views.3809911073] - dialog content
#. defaultMessage is: #. defaultMessage is:
#. Are you sure you want to unassign {counter,plural,one{this collection} other{{displayQuantity} collections}}? #. Are you sure you want to unassign {counter,plural,one{this collection} other{{displayQuantity} collections}}?
msgctxt "dialog content" msgctxt "dialog content"
@ -1168,7 +1168,7 @@ msgid "Are you sure you want to unassign {counter,plural,one{this collection} ot
msgstr "" msgstr ""
#: build/locale/src/collections/views/CollectionDetails.json #: build/locale/src/collections/views/CollectionDetails.json
#. [src.collections.views.1908998638] #. [src.collections.views.735691989]
#. defaultMessage is: #. defaultMessage is:
#. Are you sure you want to unassign {counter,plural,one{this product} other{{displayQuantity} products}}? #. Are you sure you want to unassign {counter,plural,one{this product} other{{displayQuantity} products}}?
msgctxt "description" msgctxt "description"
@ -1176,11 +1176,11 @@ msgid "Are you sure you want to unassign {counter,plural,one{this product} other
msgstr "" msgstr ""
#: build/locale/src/discounts/views/SaleDetails.json #: build/locale/src/discounts/views/SaleDetails.json
#. [src.discounts.views.786949385] - dialog content #. [src.discounts.views.735691989] - dialog content
#. defaultMessage is: #. defaultMessage is:
#. Are you sure you want to unassign {counter,plural,one{this product} other{{displayQuantity} products}}? #. Are you sure you want to unassign {counter,plural,one{this product} other{{displayQuantity} products}}?
#: build/locale/src/discounts/views/VoucherDetails.json #: build/locale/src/discounts/views/VoucherDetails.json
#. [src.discounts.views.786949385] - dialog content #. [src.discounts.views.735691989] - dialog content
#. defaultMessage is: #. defaultMessage is:
#. Are you sure you want to unassign {counter,plural,one{this product} other{{displayQuantity} products}}? #. Are you sure you want to unassign {counter,plural,one{this product} other{{displayQuantity} products}}?
msgctxt "dialog content" msgctxt "dialog content"
@ -1188,7 +1188,7 @@ msgid "Are you sure you want to unassign {counter,plural,one{this product} other
msgstr "" msgstr ""
#: build/locale/src/collections/views/CollectionList/CollectionList.json #: build/locale/src/collections/views/CollectionList/CollectionList.json
#. [src.collections.views.CollectionList.3944356444] #. [src.collections.views.CollectionList.3449136787]
#. 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"
@ -1196,7 +1196,7 @@ msgid "Are you sure you want to unpublish {counter,plural,one{this collection} o
msgstr "" msgstr ""
#: build/locale/src/pages/views/PageList.json #: build/locale/src/pages/views/PageList.json
#. [src.pages.views.691980200] - dialog content #. [src.pages.views.1265636351] - dialog content
#. defaultMessage is: #. defaultMessage is:
#. Are you sure you want to unpublish {counter,plural,one{this page} other{{displayQuantity} pages}}? #. Are you sure you want to unpublish {counter,plural,one{this page} other{{displayQuantity} pages}}?
msgctxt "dialog content" msgctxt "dialog content"
@ -1204,7 +1204,7 @@ msgid "Are you sure you want to unpublish {counter,plural,one{this page} other{{
msgstr "" msgstr ""
#: build/locale/src/products/views/ProductList/ProductList.json #: build/locale/src/products/views/ProductList/ProductList.json
#. [src.products.views.ProductList.193914731] - dialog content #. [src.products.views.ProductList.1752069132] - dialog content
#. defaultMessage is: #. defaultMessage is:
#. Are you sure you want to unpublish {counter,plural,one{this product} other{{displayQuantity} products}}? #. Are you sure you want to unpublish {counter,plural,one{this product} other{{displayQuantity} products}}?
msgctxt "dialog content" msgctxt "dialog content"
@ -1484,7 +1484,7 @@ msgid "Authentication Type"
msgstr "" msgstr ""
#: build/locale/src/siteSettings/components/SiteSettingsPage/SiteSettingsPage.json #: build/locale/src/siteSettings/components/SiteSettingsPage/SiteSettingsPage.json
#. [src.siteSettings.components.SiteSettingsPage.3619898341] #. [src.siteSettings.components.SiteSettingsPage.1214877701]
#. defaultMessage is: #. defaultMessage is:
#. Authentication method defines additional ways that customers can log in to your ecommerce. #. Authentication method defines additional ways that customers can log in to your ecommerce.
msgctxt "description" msgctxt "description"
@ -5507,6 +5507,14 @@ msgctxt "description"
msgid "Order draft succesfully created" msgid "Order draft succesfully created"
msgstr "" msgstr ""
#: build/locale/src/webhooks/components/WebhookEvents/WebhookEvents.json
#. [src.webhooks.components.WebhookEvents.3907151399] - event
#. defaultMessage is:
#. Order fulfilled
msgctxt "event"
msgid "Order fulfilled"
msgstr ""
#: build/locale/src/webhooks/components/WebhookEvents/WebhookEvents.json #: build/locale/src/webhooks/components/WebhookEvents/WebhookEvents.json
#. [src.webhooks.components.WebhookEvents.3345061702] - event #. [src.webhooks.components.WebhookEvents.3345061702] - event
#. defaultMessage is: #. defaultMessage is:
@ -8436,11 +8444,11 @@ msgid "Translation"
msgstr "" msgstr ""
#: build/locale/src/translations/components/TranslationsCategoriesPage/TranslationsCategoriesPage.json #: build/locale/src/translations/components/TranslationsCategoriesPage/TranslationsCategoriesPage.json
#. [src.translations.components.TranslationsCategoriesPage.2043581404] #. [src.translations.components.TranslationsCategoriesPage.1611537010]
#. defaultMessage is: #. defaultMessage is:
#. Translation Category "{categoryNane}" - {languageCode} #. Translation Category "{categoryName}" - {languageCode}
msgctxt "description" msgctxt "description"
msgid "Translation Category \"{categoryNane}\" - {languageCode}" msgid "Translation Category \"{categoryName}\" - {languageCode}"
msgstr "" msgstr ""
#: build/locale/src/translations/components/TranslationsCollectionsPage/TranslationsCollectionsPage.json #: build/locale/src/translations/components/TranslationsCollectionsPage/TranslationsCollectionsPage.json
@ -9598,33 +9606,45 @@ msgstr ""
#: build/locale/src/home/components/HomeProductListCard/HomeProductListCard.json #: build/locale/src/home/components/HomeProductListCard/HomeProductListCard.json
#. [homeProductListCardOrders] - number of ordered products #. [homeProductListCardOrders] - number of ordered products
#. defaultMessage is: #. defaultMessage is:
#. {amount,plural,one{One ordered} other{{amount} Ordered}} #. {amount, plural,
#. one {One ordered}
#. other {{amount} Ordered}
#. }
msgctxt "number of ordered products" msgctxt "number of ordered products"
msgid "{amount,plural,one{One ordered} other{{amount} Ordered}}" msgid "{amount, plural,\n one {One ordered}\n other {{amount} Ordered}\n }"
msgstr "" msgstr ""
#: build/locale/src/home/components/HomeNotificationTable/HomeNotificationTable.json #: build/locale/src/home/components/HomeNotificationTable/HomeNotificationTable.json
#. [homeNotificationTableOrders] #. [homeNotificationTableOrders]
#. defaultMessage is: #. defaultMessage is:
#. {amount,plural,one{One order} other{{amount} Orders}} are ready to fulfill #. {amount, plural,
#. one {One order}
#. other {{amount} Orders}
#. } are ready to fulfill
msgctxt "description" msgctxt "description"
msgid "{amount,plural,one{One order} other{{amount} Orders}} are ready to fulfill" msgid "{amount, plural,\n one {One order}\n other {{amount} Orders}\n } are ready to fulfill"
msgstr "" msgstr ""
#: build/locale/src/home/components/HomeNotificationTable/HomeNotificationTable.json #: build/locale/src/home/components/HomeNotificationTable/HomeNotificationTable.json
#. [homeNotificationTablePayments] #. [homeNotificationTablePayments]
#. defaultMessage is: #. defaultMessage is:
#. {amount,plural,one{One payment} other{{amount} Payments}} to capture #. {amount, plural,
#. one {One payment}
#. other {{amount} Payments}
#. } to capture
msgctxt "description" msgctxt "description"
msgid "{amount,plural,one{One payment} other{{amount} Payments}} to capture" msgid "{amount, plural,\n one {One payment}\n other {{amount} Payments}\n } to capture"
msgstr "" msgstr ""
#: build/locale/src/home/components/HomeNotificationTable/HomeNotificationTable.json #: build/locale/src/home/components/HomeNotificationTable/HomeNotificationTable.json
#. [homeNotificationTableProducts] #. [homeNotificationTableProducts]
#. defaultMessage is: #. defaultMessage is:
#. {amount,plural,one{One product} other{{amount} Products}} out of stock #. {amount, plural,
#. one {One product}
#. other {{amount} Products}
#. } out of stock
msgctxt "description" msgctxt "description"
msgid "{amount,plural,one{One product} other{{amount} Products}} out of stock" msgid "{amount, plural,\n one {One product}\n other {{amount} Products}\n } out of stock"
msgstr "" msgstr ""
#: build/locale/src/translations/components/TranslationsEntitiesList/TranslationsEntitiesList.json #: build/locale/src/translations/components/TranslationsEntitiesList/TranslationsEntitiesList.json

8103
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -13,13 +13,13 @@
}, },
"homepage": "http://getsaleor.com/", "homepage": "http://getsaleor.com/",
"engines": { "engines": {
"node": ">=10.6.0", "node": ">=12.12.0",
"npm": ">=6.1.0" "npm": ">=6.11.0"
}, },
"dependencies": { "dependencies": {
"@material-ui/core": "^3.9.3", "@material-ui/core": "^4.5.1",
"@material-ui/icons": "^3.0.2", "@material-ui/icons": "^4.5.1",
"@material-ui/styles": "^3.0.0-alpha.10", "@material-ui/styles": "^4.5.2",
"apollo": "^2.17.2", "apollo": "^2.17.2",
"apollo-cache-inmemory": "^1.6.2", "apollo-cache-inmemory": "^1.6.2",
"apollo-client": "^2.6.4", "apollo-client": "^2.6.4",
@ -45,7 +45,7 @@
"lodash": "^4.17.14", "lodash": "^4.17.14",
"lodash-es": "^4.17.14", "lodash-es": "^4.17.14",
"moment-timezone": "^0.5.26", "moment-timezone": "^0.5.26",
"qs": "^6.7.0", "qs": "^6.9.0",
"react": "^16.9.0", "react": "^16.9.0",
"react-apollo": "^3.0.0", "react-apollo": "^3.0.0",
"react-dom": "^16.9.0", "react-dom": "^16.9.0",
@ -63,7 +63,7 @@
"react-sortable-tree": "^2.6.2", "react-sortable-tree": "^2.6.2",
"react-svg": "^2.2.11", "react-svg": "^2.2.11",
"slugify": "^1.3.4", "slugify": "^1.3.4",
"typescript": "^3.5.3", "typescript": "^3.6.4",
"url-join": "^4.0.1", "url-join": "^4.0.1",
"use-react-router": "^1.0.7" "use-react-router": "^1.0.7"
}, },
@ -108,6 +108,7 @@
"babel-plugin-react-intl-auto": "^2.3.0", "babel-plugin-react-intl-auto": "^2.3.0",
"codecov": "^3.5.0", "codecov": "^3.5.0",
"core-js": "^3.2.1", "core-js": "^3.2.1",
"cross-env": "^6.0.3",
"enzyme": "^3.10.0", "enzyme": "^3.10.0",
"enzyme-adapter-react-16": "^1.14.0", "enzyme-adapter-react-16": "^1.14.0",
"enzyme-to-json": "^3.3.5", "enzyme-to-json": "^3.3.5",
@ -174,7 +175,7 @@
}, },
"scripts": { "scripts": {
"build": "webpack -p", "build": "webpack -p",
"extract-json-messages": "rimraf build/locale && babel src 'src/**/*.{ts,tsx}' -o build/dashboard.bundle.js", "extract-json-messages": "rimraf build/locale && cross-env NODE_ENV=extract babel src 'src/**/*.{ts,tsx}' -o build/dashboard.bundle.js",
"extract-pot-messages": "rip json2pot \"build/locale/**/*.json\" -c description -o locale/messages.pot", "extract-pot-messages": "rip json2pot \"build/locale/**/*.json\" -c description -o locale/messages.pot",
"extract-messages": "npm run extract-json-messages && npm run extract-pot-messages", "extract-messages": "npm run extract-json-messages && npm run extract-pot-messages",
"build-messages": "rip po2json 'locale/**/*.po' -m 'build/locale/**/*.json' -o 'locale' -c 'description'", "build-messages": "rip po2json 'locale/**/*.po' -m 'build/locale/**/*.json' -o 'locale' -c 'description'",

View file

@ -36,10 +36,7 @@ const AttributeBulkDeleteDialog: React.FC<AttributeBulkDeleteDialogProps> = ({
> >
<DialogContentText> <DialogContentText>
<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} other{{displayQuantity} attributes}}?"
one {this attribute}
other {{displayQuantity} attributes}
}?"
description="dialog content" description="dialog content"
values={{ values={{
counter: quantity, counter: quantity,

View file

@ -1,2 +1,2 @@
export { default } from './AttributeBulkDeleteDialog'; export { default } from "./AttributeBulkDeleteDialog";
export * from './AttributeBulkDeleteDialog'; export * from "./AttributeBulkDeleteDialog";

View file

@ -1,2 +1,2 @@
export { default } from './AttributeDeleteDialog'; export { default } from "./AttributeDeleteDialog";
export * from './AttributeDeleteDialog'; export * from "./AttributeDeleteDialog";

View file

@ -1,2 +1,2 @@
export { default } from './AttributeDetails'; export { default } from "./AttributeDetails";
export * from './AttributeDetails'; export * from "./AttributeDetails";

View file

@ -1,10 +1,9 @@
import { Theme } from "@material-ui/core/styles"; import { makeStyles } from "@material-ui/core/styles";
import Table from "@material-ui/core/Table"; import Table from "@material-ui/core/Table";
import TableBody from "@material-ui/core/TableBody"; import TableBody from "@material-ui/core/TableBody";
import TableCell from "@material-ui/core/TableCell"; 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 makeStyles from "@material-ui/styles/makeStyles";
import React from "react"; import React from "react";
import { FormattedMessage, useIntl } from "react-intl"; import { FormattedMessage, useIntl } from "react-intl";
@ -21,7 +20,7 @@ export interface AttributeListProps extends ListProps, ListActions {
attributes: AttributeList_attributes_edges_node[]; attributes: AttributeList_attributes_edges_node[];
} }
const useStyles = makeStyles((theme: Theme) => ({ const useStyles = makeStyles(theme => ({
[theme.breakpoints.up("lg")]: { [theme.breakpoints.up("lg")]: {
colFaceted: { colFaceted: {
width: 150 width: 150

View file

@ -1,2 +1,2 @@
export { default } from './AttributeList'; export { default } from "./AttributeList";
export * from './AttributeList'; export * from "./AttributeList";

View file

@ -1,2 +1,2 @@
export { default } from './AttributeListPage'; export { default } from "./AttributeListPage";
export * from './AttributeListPage'; export * from "./AttributeListPage";

View file

@ -1,2 +1,2 @@
export { default } from './AttributePage'; export { default } from "./AttributePage";
export * from './AttributePage'; export * from "./AttributePage";

View file

@ -1,2 +1,2 @@
export { default } from './AttributeProperties'; export { default } from "./AttributeProperties";
export * from './AttributeProperties'; export * from "./AttributeProperties";

View file

@ -41,7 +41,7 @@ const AttributeValueDeleteDialog: React.FC<AttributeValueDeleteDialogProps> = ({
<DialogContentText> <DialogContentText>
{useName ? ( {useName ? (
<FormattedMessage <FormattedMessage
defaultMessage='Are you sure you want to delete "{ name }" value? If you delete it you wont be able to assign it to any of the products with "{ attributeName }" attribute.' defaultMessage='Are you sure you want to delete "{name}" value? If you delete it you wont be able to assign it to any of the products with "{attributeName}" attribute.'
values={{ values={{
attributeName, attributeName,
name name
@ -49,7 +49,7 @@ const AttributeValueDeleteDialog: React.FC<AttributeValueDeleteDialogProps> = ({
/> />
) : ( ) : (
<FormattedMessage <FormattedMessage
defaultMessage='Are you sure you want to delete "{ name }" value?' defaultMessage='Are you sure you want to delete "{name}" value?'
description="delete attribute value" description="delete attribute value"
values={{ values={{
name name

View file

@ -1,2 +1,2 @@
export { default } from './AttributeValueDeleteDialog'; export { default } from "./AttributeValueDeleteDialog";
export * from './AttributeValueDeleteDialog'; export * from "./AttributeValueDeleteDialog";

View file

@ -1,2 +1,2 @@
export { default } from './AttributeValueEditDialog'; export { default } from "./AttributeValueEditDialog";
export * from './AttributeValueEditDialog'; export * from "./AttributeValueEditDialog";

View file

@ -1,13 +1,12 @@
import Button from "@material-ui/core/Button"; import Button from "@material-ui/core/Button";
import Card from "@material-ui/core/Card"; import Card from "@material-ui/core/Card";
import IconButton from "@material-ui/core/IconButton"; import IconButton from "@material-ui/core/IconButton";
import { Theme } from "@material-ui/core/styles"; import { makeStyles } from "@material-ui/core/styles";
import Table from "@material-ui/core/Table"; import Table from "@material-ui/core/Table";
import TableCell from "@material-ui/core/TableCell"; import TableCell from "@material-ui/core/TableCell";
import TableHead from "@material-ui/core/TableHead"; import TableHead from "@material-ui/core/TableHead";
import TableRow from "@material-ui/core/TableRow"; import TableRow from "@material-ui/core/TableRow";
import DeleteIcon from "@material-ui/icons/Delete"; import DeleteIcon from "@material-ui/icons/Delete";
import makeStyles from "@material-ui/styles/makeStyles";
import React from "react"; import React from "react";
import { FormattedMessage, useIntl } from "react-intl"; import { FormattedMessage, useIntl } from "react-intl";
@ -30,12 +29,12 @@ export interface AttributeValuesProps {
onValueUpdate: (id: string) => void; onValueUpdate: (id: string) => void;
} }
const useStyles = makeStyles((theme: Theme) => ({ const useStyles = makeStyles(theme => ({
columnAdmin: { columnAdmin: {
width: "50%" width: "50%"
}, },
columnDrag: { columnDrag: {
width: 48 + theme.spacing.unit * 1.5 width: 48 + theme.spacing(1.5)
}, },
columnStore: { columnStore: {
width: "50%" width: "50%"
@ -45,9 +44,9 @@ const useStyles = makeStyles((theme: Theme) => ({
}, },
iconCell: { iconCell: {
"&:last-child": { "&:last-child": {
paddingRight: theme.spacing.unit paddingRight: theme.spacing()
}, },
width: 48 + theme.spacing.unit * 1.5 width: 48 + theme.spacing(1.5)
}, },
link: { link: {
cursor: "pointer" cursor: "pointer"

View file

@ -1,2 +1,2 @@
export { default } from './AttributeValues'; export { default } from "./AttributeValues";
export * from './AttributeValues'; export * from "./AttributeValues";

View file

@ -91,7 +91,7 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ params }) => {
field: "name", field: "name",
message: intl.formatMessage( message: intl.formatMessage(
{ {
defaultMessage: "A value named { name } already exists", defaultMessage: "A value named {name} already exists",
description: "attribute value edit error" description: "attribute value edit error"
}, },
{ {
@ -112,7 +112,7 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ params }) => {
field: "name", field: "name",
message: intl.formatMessage( message: intl.formatMessage(
{ {
defaultMessage: "A value named { name } already exists", defaultMessage: "A value named {name} already exists",
description: "attribute value edit error" description: "attribute value edit error"
}, },
{ {

View file

@ -12,12 +12,12 @@ import {
export const PRODUCT_FILTERS_KEY = "productFilters"; export const PRODUCT_FILTERS_KEY = "productFilters";
export function getFilterVariables( export function getFilterVariables(
params: AttributeListUrlFilters params: AttributeListUrlFilters
): AttributeFilterInput { ): AttributeFilterInput {
return { return {
search: params.query search: params.query
}; };
} }
export const { export const {
deleteFilterTab, deleteFilterTab,

View file

@ -1,5 +1,4 @@
import { Theme } from "@material-ui/core/styles"; import { makeStyles } from "@material-ui/core/styles";
import { makeStyles } from "@material-ui/styles";
import React from "react"; import React from "react";
import SVG from "react-inlinesvg"; import SVG from "react-inlinesvg";
@ -9,24 +8,24 @@ import saleorLightLogo from "@assets/images/logo-light.svg";
import useTheme from "@saleor/hooks/useTheme"; import useTheme from "@saleor/hooks/useTheme";
const useStyles = makeStyles( const useStyles = makeStyles(
(theme: Theme) => ({ theme => ({
logo: { logo: {
"& svg": { "& svg": {
display: "block", display: "block",
height: 40, height: 40,
marginBottom: theme.spacing.unit * 4 marginBottom: theme.spacing(4)
} }
}, },
mainPanel: { mainPanel: {
[theme.breakpoints.down("sm")]: { [theme.breakpoints.down("sm")]: {
padding: theme.spacing.unit * 2 padding: theme.spacing(2)
}, },
background: theme.palette.background.paper, background: theme.palette.background.paper,
display: "flex", display: "flex",
flexDirection: "column", flexDirection: "column",
height: "100vh", height: "100vh",
justifyContent: "center", justifyContent: "center",
padding: theme.spacing.unit * 6, padding: theme.spacing(6),
width: "100%" width: "100%"
}, },
mainPanelContent: { mainPanelContent: {

View file

@ -1,21 +1,26 @@
import CircularProgress from "@material-ui/core/CircularProgress"; import CircularProgress from "@material-ui/core/CircularProgress";
import { createStyles, withStyles, WithStyles } from "@material-ui/core/styles"; import { makeStyles } from "@material-ui/core/styles";
import React from "react"; import React from "react";
const styles = createStyles({ const useStyles = makeStyles(
root: { {
alignItems: "center", root: {
display: "flex", alignItems: "center",
height: "100vh", display: "flex",
justifyContent: "center" height: "100vh",
} justifyContent: "center"
}); }
const LoginLoading = withStyles(styles, { name: "LoginLoading" })( },
({ classes }: WithStyles<typeof styles>) => ( { name: "LoginLoading" }
);
const LoginLoading: React.FC = props => {
const classes = useStyles(props);
return (
<div className={classes.root}> <div className={classes.root}>
<CircularProgress size={128} /> <CircularProgress size={128} />
</div> </div>
) );
); };
LoginLoading.displayName = "LoginLoading"; LoginLoading.displayName = "LoginLoading";
export default LoginLoading; export default LoginLoading;

View file

@ -1,10 +1,5 @@
import Button from "@material-ui/core/Button"; import Button from "@material-ui/core/Button";
import { import { makeStyles } from "@material-ui/core/styles";
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import TextField from "@material-ui/core/TextField"; import TextField from "@material-ui/core/TextField";
import Typography from "@material-ui/core/Typography"; import Typography from "@material-ui/core/Typography";
import React from "react"; import React from "react";
@ -19,8 +14,8 @@ export interface FormData {
password: string; password: string;
} }
const styles = (theme: Theme) => const useStyles = makeStyles(
createStyles({ theme => ({
buttonContainer: { buttonContainer: {
display: "flex", display: "flex",
justifyContent: "flex-end" justifyContent: "flex-end"
@ -38,93 +33,90 @@ const styles = (theme: Theme) =>
color: theme.palette.error.contrastText color: theme.palette.error.contrastText
}, },
background: theme.palette.error.main, background: theme.palette.error.main,
borderRadius: theme.spacing.unit, borderRadius: theme.spacing(),
marginBottom: theme.spacing.unit * 3, marginBottom: theme.spacing(3),
padding: theme.spacing.unit * 1.5 padding: theme.spacing(1.5)
} }
}); }),
{ name: "LoginCard" }
);
export interface LoginCardProps extends WithStyles<typeof styles> { export interface LoginCardProps {
error: boolean; error: boolean;
disableLoginButton: boolean; disableLoginButton: boolean;
onPasswordRecovery: () => void; onPasswordRecovery: () => void;
onSubmit?(event: FormData); onSubmit?(event: FormData);
} }
const LoginCard = withStyles(styles, { name: "LoginCard" })( const LoginCard: React.FC<LoginCardProps> = props => {
({ const { error, disableLoginButton, onPasswordRecovery, onSubmit } = props;
classes,
error,
disableLoginButton,
onPasswordRecovery,
onSubmit
}: LoginCardProps) => {
const intl = useIntl();
return ( const classes = useStyles(props);
<Form initial={{ email: "", password: "" }} onSubmit={onSubmit}> const intl = useIntl();
{({ change: handleChange, data, submit: handleSubmit }) => (
<> return (
{error && ( <Form initial={{ email: "", password: "" }} onSubmit={onSubmit}>
<div className={classes.panel}> {({ change: handleChange, data, submit: handleSubmit }) => (
<Typography variant="caption"> <>
<FormattedMessage defaultMessage="Sorry, your username and/or password are incorrect. Please try again." /> {error && (
</Typography> <div className={classes.panel}>
</div> <Typography variant="caption">
)} <FormattedMessage defaultMessage="Sorry, your username and/or password are incorrect. Please try again." />
<TextField </Typography>
autoFocus
fullWidth
autoComplete="username"
label={intl.formatMessage(commonMessages.email)}
name="email"
onChange={handleChange}
value={data.email}
inputProps={{
"data-tc": "email"
}}
/>
<FormSpacer />
<TextField
fullWidth
autoComplete="password"
label={intl.formatMessage({
defaultMessage: "Password"
})}
name="password"
onChange={handleChange}
type="password"
value={data.password}
inputProps={{
"data-tc": "password"
}}
/>
<FormSpacer />
<div className={classes.buttonContainer}>
<Button
className={classes.loginButton}
color="primary"
disabled={disableLoginButton}
variant="contained"
onClick={handleSubmit}
type="submit"
data-tc="submit"
>
<FormattedMessage defaultMessage="Login" description="button" />
</Button>
</div> </div>
<FormSpacer /> )}
<Typography className={classes.link} onClick={onPasswordRecovery}> <TextField
<FormattedMessage autoFocus
defaultMessage="Reset your password" fullWidth
description="button" autoComplete="username"
/> label={intl.formatMessage(commonMessages.email)}
</Typography> name="email"
</> onChange={handleChange}
)} value={data.email}
</Form> inputProps={{
); "data-tc": "email"
} }}
); />
<FormSpacer />
<TextField
fullWidth
autoComplete="password"
label={intl.formatMessage({
defaultMessage: "Password"
})}
name="password"
onChange={handleChange}
type="password"
value={data.password}
inputProps={{
"data-tc": "password"
}}
/>
<FormSpacer />
<div className={classes.buttonContainer}>
<Button
className={classes.loginButton}
color="primary"
disabled={disableLoginButton}
variant="contained"
onClick={handleSubmit}
type="submit"
data-tc="submit"
>
<FormattedMessage defaultMessage="Login" description="button" />
</Button>
</div>
<FormSpacer />
<Typography className={classes.link} onClick={onPasswordRecovery}>
<FormattedMessage
defaultMessage="Reset your password"
description="button"
/>
</Typography>
</>
)}
</Form>
);
};
LoginCard.displayName = "LoginCard"; LoginCard.displayName = "LoginCard";
export default LoginCard; export default LoginCard;

View file

@ -1,7 +1,7 @@
import Button from "@material-ui/core/Button"; import Button from "@material-ui/core/Button";
import { makeStyles } from "@material-ui/core/styles";
import TextField from "@material-ui/core/TextField"; import TextField from "@material-ui/core/TextField";
import Typography from "@material-ui/core/Typography"; import Typography from "@material-ui/core/Typography";
import { makeStyles } from "@material-ui/styles";
import React from "react"; import React from "react";
import { FormattedMessage, useIntl } from "react-intl"; import { FormattedMessage, useIntl } from "react-intl";

View file

@ -1,8 +1,7 @@
import Button from "@material-ui/core/Button"; import Button from "@material-ui/core/Button";
import { Theme } from "@material-ui/core/styles"; import { makeStyles } from "@material-ui/core/styles";
import TextField from "@material-ui/core/TextField"; import TextField from "@material-ui/core/TextField";
import Typography from "@material-ui/core/Typography"; import Typography from "@material-ui/core/Typography";
import { makeStyles } from "@material-ui/styles";
import React from "react"; import React from "react";
import { FormattedMessage, useIntl } from "react-intl"; import { FormattedMessage, useIntl } from "react-intl";
@ -11,15 +10,15 @@ import FormSpacer from "@saleor/components/FormSpacer";
import { commonMessages } from "@saleor/intl"; import { commonMessages } from "@saleor/intl";
const useStyles = makeStyles( const useStyles = makeStyles(
(theme: Theme) => ({ theme => ({
errorText: {
color: theme.palette.error.contrastText
},
panel: { panel: {
"& span": {
color: theme.palette.error.contrastText
},
background: theme.palette.error.main, background: theme.palette.error.main,
borderRadius: theme.spacing.unit, borderRadius: theme.spacing(),
marginBottom: theme.spacing.unit * 3, marginBottom: theme.spacing(3),
padding: theme.spacing.unit * 1.5 padding: theme.spacing(1.5)
}, },
submit: { submit: {
width: "100%" width: "100%"
@ -51,7 +50,9 @@ const ResetPasswordPage: React.FC<ResetPasswordPageProps> = props => {
<> <>
{!!error && ( {!!error && (
<div className={classes.panel}> <div className={classes.panel}>
<Typography variant="caption">{error}</Typography> <Typography variant="caption" className={classes.errorText}>
{error}
</Typography>
</div> </div>
)} )}
<Typography> <Typography>

View file

@ -1,6 +1,6 @@
import Button from "@material-ui/core/Button"; import Button from "@material-ui/core/Button";
import { makeStyles } from "@material-ui/core/styles";
import Typography from "@material-ui/core/Typography"; import Typography from "@material-ui/core/Typography";
import { makeStyles } from "@material-ui/styles";
import React from "react"; import React from "react";
import { FormattedMessage } from "react-intl"; import { FormattedMessage } from "react-intl";

View file

@ -1,4 +1,4 @@
import { PermissionEnum } from '../types/globalTypes' import { PermissionEnum } from "../types/globalTypes";
import { User } from "./types/User"; import { User } from "./types/User";
export const hasPermission = (permission: PermissionEnum, user: User) => export const hasPermission = (permission: PermissionEnum, user: User) =>

View file

@ -1,6 +1,5 @@
import { Theme } from "@material-ui/core/styles"; import makeStyles from "@material-ui/core/styles/makeStyles";
import TextField from "@material-ui/core/TextField"; import TextField from "@material-ui/core/TextField";
import makeStyles from "@material-ui/styles/makeStyles";
import React from "react"; import React from "react";
import Button from "@material-ui/core/Button"; import Button from "@material-ui/core/Button";
@ -16,7 +15,7 @@ import { FormattedMessage, useIntl } from "react-intl";
import { CategoryDetails_category_backgroundImage } from "../../types/CategoryDetails"; import { CategoryDetails_category_backgroundImage } from "../../types/CategoryDetails";
import { FormData } from "../CategoryUpdatePage"; import { FormData } from "../CategoryUpdatePage";
const useStyles = makeStyles((theme: Theme) => ({ const useStyles = makeStyles(theme => ({
fileField: { fileField: {
display: "none" display: "none"
}, },
@ -29,11 +28,11 @@ const useStyles = makeStyles((theme: Theme) => ({
imageContainer: { imageContainer: {
background: "#ffffff", background: "#ffffff",
border: "1px solid #eaeaea", border: "1px solid #eaeaea",
borderRadius: theme.spacing.unit, borderRadius: theme.spacing(),
height: 148, height: 148,
justifySelf: "start", justifySelf: "start",
overflow: "hidden", overflow: "hidden",
padding: theme.spacing.unit * 2, padding: theme.spacing(2),
position: "relative", position: "relative",
width: 148 width: 148
} }

View file

@ -4,19 +4,14 @@ import DialogActions from "@material-ui/core/DialogActions";
import DialogContent from "@material-ui/core/DialogContent"; import DialogContent from "@material-ui/core/DialogContent";
import DialogContentText from "@material-ui/core/DialogContentText"; import DialogContentText from "@material-ui/core/DialogContentText";
import DialogTitle from "@material-ui/core/DialogTitle"; import DialogTitle from "@material-ui/core/DialogTitle";
import { import { makeStyles } from "@material-ui/core/styles";
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import React from "react"; import React from "react";
import { FormattedMessage } from "react-intl"; import { FormattedMessage } from "react-intl";
import { buttonMessages } from "@saleor/intl"; import { buttonMessages } from "@saleor/intl";
const styles = (theme: Theme) => const useStyles = makeStyles(
createStyles({ theme => ({
deleteButton: { deleteButton: {
"&:hover": { "&:hover": {
backgroundColor: theme.palette.error.main backgroundColor: theme.palette.error.main
@ -24,49 +19,58 @@ const styles = (theme: Theme) =>
backgroundColor: theme.palette.error.main, backgroundColor: theme.palette.error.main,
color: theme.palette.error.contrastText color: theme.palette.error.contrastText
} }
}); }),
{
name: "CategoryDeleteDialog"
}
);
export interface CategoryDeleteDialogProps extends WithStyles<typeof styles> { export interface CategoryDeleteDialogProps {
open: boolean; open: boolean;
name: string; name: string;
onClose(); onClose();
onConfirm(); onConfirm();
} }
const CategoryDeleteDialog = withStyles(styles, { const CategoryDeleteDialog: React.FC<CategoryDeleteDialogProps> = props => {
name: "CategoryDeleteDialog" const { name, open, onConfirm, onClose } = props;
})(({ classes, name, open, onConfirm, onClose }: CategoryDeleteDialogProps) => (
<Dialog onClose={onClose} open={open}> const classes = useStyles(props);
<DialogTitle>
<FormattedMessage return (
defaultMessage="Delete category" <Dialog onClose={onClose} open={open}>
description="dialog title" <DialogTitle>
/>
</DialogTitle>
<DialogContent>
<DialogContentText>
<FormattedMessage <FormattedMessage
defaultMessage="Are you sure you want to delete {categoryName}?" defaultMessage="Delete category"
description="delete category" description="dialog title"
values={{
categoryName: <strong>{name}</strong>
}}
/> />
</DialogContentText> </DialogTitle>
</DialogContent> <DialogContent>
<DialogActions> <DialogContentText>
<Button onClick={onClose}> <FormattedMessage
<FormattedMessage {...buttonMessages.back} /> defaultMessage="Are you sure you want to delete {categoryName}?"
</Button> description="delete category"
<Button values={{
className={classes.deleteButton} categoryName: <strong>{name}</strong>
variant="contained" }}
onClick={onConfirm} />
> </DialogContentText>
<FormattedMessage {...buttonMessages.save} /> </DialogContent>
</Button> <DialogActions>
</DialogActions> <Button onClick={onClose}>
</Dialog> <FormattedMessage {...buttonMessages.back} />
)); </Button>
<Button
className={classes.deleteButton}
variant="contained"
onClick={onConfirm}
>
<FormattedMessage {...buttonMessages.save} />
</Button>
</DialogActions>
</Dialog>
);
};
CategoryDeleteDialog.displayName = "CategoryDeleteDialog"; CategoryDeleteDialog.displayName = "CategoryDeleteDialog";
export default CategoryDeleteDialog; export default CategoryDeleteDialog;

View file

@ -1,9 +1,4 @@
import { import { makeStyles } from "@material-ui/core/styles";
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import Table from "@material-ui/core/Table"; import Table from "@material-ui/core/Table";
import TableBody from "@material-ui/core/TableBody"; import TableBody from "@material-ui/core/TableBody";
import TableCell from "@material-ui/core/TableCell"; import TableCell from "@material-ui/core/TableCell";
@ -20,8 +15,8 @@ import TablePagination from "@saleor/components/TablePagination";
import { maybe, renderCollection } from "@saleor/misc"; import { maybe, renderCollection } from "@saleor/misc";
import { ListActions, ListProps } from "@saleor/types"; import { ListActions, ListProps } from "@saleor/types";
const styles = (theme: Theme) => const useStyles = makeStyles(
createStyles({ theme => ({
[theme.breakpoints.up("lg")]: { [theme.breakpoints.up("lg")]: {
colName: { colName: {
width: 840 width: 840
@ -45,7 +40,9 @@ const styles = (theme: Theme) =>
tableRow: { tableRow: {
cursor: "pointer" cursor: "pointer"
} }
}); }),
{ name: "CategoryList" }
);
interface CategoryListProps extends ListProps, ListActions { interface CategoryListProps extends ListProps, ListActions {
categories?: CategoryFragment[]; categories?: CategoryFragment[];
@ -55,10 +52,9 @@ interface CategoryListProps extends ListProps, ListActions {
const numberOfColumns = 4; const numberOfColumns = 4;
const CategoryList = withStyles(styles, { name: "CategoryList" })( const CategoryList: React.FC<CategoryListProps> = props => {
({ const {
categories, categories,
classes,
disabled, disabled,
settings, settings,
pageInfo, pageInfo,
@ -72,7 +68,11 @@ const CategoryList = withStyles(styles, { name: "CategoryList" })(
onPreviousPage, onPreviousPage,
onUpdateListSettings, onUpdateListSettings,
onRowClick onRowClick
}: CategoryListProps & WithStyles<typeof styles>) => ( } = props;
const classes = useStyles(props);
return (
<Table> <Table>
<TableHead <TableHead
colSpan={numberOfColumns} colSpan={numberOfColumns}
@ -175,7 +175,8 @@ const CategoryList = withStyles(styles, { name: "CategoryList" })(
)} )}
</TableBody> </TableBody>
</Table> </Table>
) );
); };
CategoryList.displayName = "CategoryList"; CategoryList.displayName = "CategoryList";
export default CategoryList; export default CategoryList;

View file

@ -1,9 +1,4 @@
import { import { makeStyles } from "@material-ui/core/styles";
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import Table from "@material-ui/core/Table"; import Table from "@material-ui/core/Table";
import TableBody from "@material-ui/core/TableBody"; import TableBody from "@material-ui/core/TableBody";
import TableCell from "@material-ui/core/TableCell"; import TableCell from "@material-ui/core/TableCell";
@ -25,8 +20,8 @@ import { ListActions, ListProps } from "@saleor/types";
import React from "react"; import React from "react";
import { CategoryDetails_category_products_edges_node } from "../../types/CategoryDetails"; import { CategoryDetails_category_products_edges_node } from "../../types/CategoryDetails";
const styles = (theme: Theme) => const useStyles = makeStyles(
createStyles({ theme => ({
[theme.breakpoints.up("lg")]: { [theme.breakpoints.up("lg")]: {
colName: { colName: {
width: "auto" width: "auto"
@ -69,20 +64,20 @@ const styles = (theme: Theme) =>
textRight: { textRight: {
textAlign: "right" textAlign: "right"
} }
}); }),
{
name: "CategoryProductList"
}
);
interface CategoryProductListProps interface CategoryProductListProps extends ListProps, ListActions {
extends ListProps,
ListActions,
WithStyles<typeof styles> {
products: CategoryDetails_category_products_edges_node[]; products: CategoryDetails_category_products_edges_node[];
} }
export const CategoryProductList = withStyles(styles, { export const CategoryProductList: React.FC<
name: "CategoryProductList" CategoryProductListProps
})( > = props => {
({ const {
classes,
disabled, disabled,
isChecked, isChecked,
pageInfo, pageInfo,
@ -94,150 +89,150 @@ export const CategoryProductList = withStyles(styles, {
onNextPage, onNextPage,
onPreviousPage, onPreviousPage,
onRowClick onRowClick
}: CategoryProductListProps) => { } = props;
const intl = useIntl();
const numberOfColumns = 5; const classes = useStyles(props);
const intl = useIntl();
return ( const numberOfColumns = 5;
<div className={classes.tableContainer}>
<Table className={classes.table}>
<colgroup>
<col />
<col className={classes.colName} />
<col className={classes.colType} />
<col className={classes.colPublished} />
<col className={classes.colPrice} />
</colgroup>
<TableHead
colSpan={numberOfColumns}
selected={selected}
disabled={disabled}
items={products}
toggleAll={toggleAll}
toolbar={toolbar}
>
<TableCell className={classes.colName}>
<span className={classes.colNameHeader}>
<FormattedMessage defaultMessage="Name" description="product" />
</span>
</TableCell>
<TableCell className={classes.colType}>
<FormattedMessage
defaultMessage="Type"
description="product type"
/>
</TableCell>
<TableCell className={classes.colPublished}>
<FormattedMessage
defaultMessage="Published"
description="product status"
/>
</TableCell>
<TableCell className={classes.colPrice}>
<FormattedMessage
defaultMessage="Price"
description="product price"
/>
</TableCell>
</TableHead>
<TableFooter>
<TableRow>
<TablePagination
colSpan={numberOfColumns}
hasNextPage={
pageInfo && !disabled ? pageInfo.hasNextPage : false
}
onNextPage={onNextPage}
hasPreviousPage={
pageInfo && !disabled ? pageInfo.hasPreviousPage : false
}
onPreviousPage={onPreviousPage}
/>
</TableRow>
</TableFooter>
<TableBody>
{renderCollection(
products,
product => {
const isSelected = product ? isChecked(product.id) : false;
return ( return (
<TableRow <div className={classes.tableContainer}>
selected={isSelected} <Table className={classes.table}>
hover={!!product} <colgroup>
key={product ? product.id : "skeleton"} <col />
onClick={product && onRowClick(product.id)} <col className={classes.colName} />
className={classes.link} <col className={classes.colType} />
<col className={classes.colPublished} />
<col className={classes.colPrice} />
</colgroup>
<TableHead
colSpan={numberOfColumns}
selected={selected}
disabled={disabled}
items={products}
toggleAll={toggleAll}
toolbar={toolbar}
>
<TableCell className={classes.colName}>
<span className={classes.colNameHeader}>
<FormattedMessage defaultMessage="Name" description="product" />
</span>
</TableCell>
<TableCell className={classes.colType}>
<FormattedMessage
defaultMessage="Type"
description="product type"
/>
</TableCell>
<TableCell className={classes.colPublished}>
<FormattedMessage
defaultMessage="Published"
description="product status"
/>
</TableCell>
<TableCell className={classes.colPrice}>
<FormattedMessage
defaultMessage="Price"
description="product price"
/>
</TableCell>
</TableHead>
<TableFooter>
<TableRow>
<TablePagination
colSpan={numberOfColumns}
hasNextPage={pageInfo && !disabled ? pageInfo.hasNextPage : false}
onNextPage={onNextPage}
hasPreviousPage={
pageInfo && !disabled ? pageInfo.hasPreviousPage : false
}
onPreviousPage={onPreviousPage}
/>
</TableRow>
</TableFooter>
<TableBody>
{renderCollection(
products,
product => {
const isSelected = product ? isChecked(product.id) : false;
return (
<TableRow
selected={isSelected}
hover={!!product}
key={product ? product.id : "skeleton"}
onClick={product && onRowClick(product.id)}
className={classes.link}
>
<TableCell padding="checkbox">
<Checkbox
checked={isSelected}
disabled={disabled}
disableClickPropagation
onChange={() => toggle(product.id)}
/>
</TableCell>
<TableCellAvatar
className={classes.colName}
thumbnail={maybe(() => product.thumbnail.url)}
> >
<TableCell padding="checkbox"> {product ? product.name : <Skeleton />}
<Checkbox </TableCellAvatar>
checked={isSelected} <TableCell className={classes.colType}>
disabled={disabled} {product && product.productType ? (
disableClickPropagation product.productType.name
onChange={() => toggle(product.id)} ) : (
<Skeleton />
)}
</TableCell>
<TableCell className={classes.colPublished}>
{product &&
maybe(() => product.isAvailable !== undefined) ? (
<StatusLabel
label={
product.isAvailable
? intl.formatMessage({
defaultMessage: "Published",
description: "product",
id: "productStatusLabel"
})
: intl.formatMessage({
defaultMessage: "Not published",
description: "product"
})
}
status={product.isAvailable ? "success" : "error"}
/> />
</TableCell> ) : (
<TableCellAvatar <Skeleton />
className={classes.colName} )}
thumbnail={maybe(() => product.thumbnail.url)} </TableCell>
> <TableCell className={classes.colPrice}>
{product ? product.name : <Skeleton />} {maybe(() => product.basePrice) &&
</TableCellAvatar> maybe(() => product.basePrice.amount) !== undefined &&
<TableCell className={classes.colType}> maybe(() => product.basePrice.currency) !== undefined ? (
{product && product.productType ? ( <Money money={product.basePrice} />
product.productType.name ) : (
) : ( <Skeleton />
<Skeleton /> )}
)}
</TableCell>
<TableCell className={classes.colPublished}>
{product &&
maybe(() => product.isAvailable !== undefined) ? (
<StatusLabel
label={
product.isAvailable
? intl.formatMessage({
defaultMessage: "Published",
description: "product",
id: "productStatusLabel"
})
: intl.formatMessage({
defaultMessage: "Not published",
description: "product"
})
}
status={product.isAvailable ? "success" : "error"}
/>
) : (
<Skeleton />
)}
</TableCell>
<TableCell className={classes.colPrice}>
{maybe(() => product.basePrice) &&
maybe(() => product.basePrice.amount) !== undefined &&
maybe(() => product.basePrice.currency) !== undefined ? (
<Money money={product.basePrice} />
) : (
<Skeleton />
)}
</TableCell>
</TableRow>
);
},
() => (
<TableRow>
<TableCell colSpan={numberOfColumns}>
<FormattedMessage defaultMessage="No products found" />
</TableCell> </TableCell>
</TableRow> </TableRow>
) );
)} },
</TableBody> () => (
</Table> <TableRow>
</div> <TableCell colSpan={numberOfColumns}>
); <FormattedMessage defaultMessage="No products found" />
} </TableCell>
); </TableRow>
)
)}
</TableBody>
</Table>
</div>
);
};
CategoryProductList.displayName = "CategoryProductList"; CategoryProductList.displayName = "CategoryProductList";
export default CategoryProductList; export default CategoryProductList;

View file

@ -369,10 +369,7 @@ export const CategoryDetails: React.FC<CategoryDetailsProps> = ({
> >
<DialogContentText> <DialogContentText>
<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} other{{displayQuantity} categories}}?"
one {this attribute}
other {{displayQuantity} categories}
}?"
values={{ values={{
counter: maybe( counter: maybe(
() => params.ids.length () => params.ids.length
@ -409,10 +406,7 @@ export const CategoryDetails: React.FC<CategoryDetailsProps> = ({
{" "} {" "}
<DialogContentText> <DialogContentText>
<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} other{{displayQuantity} products}}?"
one {this attribute}
other {{displayQuantity} products}
}?"
values={{ values={{
counter: maybe( counter: maybe(
() => params.ids.length () => params.ids.length

View file

@ -222,10 +222,7 @@ export const CategoryList: React.FC<CategoryListProps> = ({ params }) => {
> >
<DialogContentText> <DialogContentText>
<FormattedMessage <FormattedMessage
defaultMessage="Are you sure you want to delete {counter, plural, defaultMessage="Are you sure you want to delete {counter,plural,one{this category} other{{displayQuantity} categories}}?"
one {this category}
other {{displayQuantity} categories}
}?"
values={{ values={{
counter: maybe(() => params.ids.length), counter: maybe(() => params.ids.length),
displayQuantity: ( displayQuantity: (

View file

@ -1,9 +1,4 @@
import { import { makeStyles } from "@material-ui/core/styles";
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import TextField from "@material-ui/core/TextField"; import TextField from "@material-ui/core/TextField";
import React from "react"; import React from "react";
import { FormattedMessage, useIntl } from "react-intl"; import { FormattedMessage, useIntl } from "react-intl";
@ -19,15 +14,15 @@ import Skeleton from "@saleor/components/Skeleton";
import { commonMessages } from "@saleor/intl"; import { commonMessages } from "@saleor/intl";
import { CollectionDetails_collection_backgroundImage } from "../../types/CollectionDetails"; import { CollectionDetails_collection_backgroundImage } from "../../types/CollectionDetails";
const styles = (theme: Theme) => const useStyles = makeStyles(
createStyles({ theme => ({
PhotosIcon: { PhotosIcon: {
height: "64px", height: "64px",
margin: "0 auto", margin: "0 auto",
width: "64px" width: "64px"
}, },
PhotosIconContainer: { PhotosIconContainer: {
margin: `${theme.spacing.unit * 5}px 0`, margin: theme.spacing(5, 0),
textAlign: "center" textAlign: "center"
}, },
fileField: { fileField: {
@ -42,15 +37,19 @@ const styles = (theme: Theme) =>
imageContainer: { imageContainer: {
background: "#ffffff", background: "#ffffff",
border: "1px solid #eaeaea", border: "1px solid #eaeaea",
borderRadius: theme.spacing.unit, borderRadius: theme.spacing(),
height: 148, height: 148,
justifySelf: "start", justifySelf: "start",
overflow: "hidden", overflow: "hidden",
padding: theme.spacing.unit * 2, padding: theme.spacing(2),
position: "relative", position: "relative",
width: 148 width: 148
} }
}); }),
{
name: "CollectionImage"
}
);
export interface CollectionImageProps { export interface CollectionImageProps {
data: { data: {
@ -62,83 +61,78 @@ export interface CollectionImageProps {
onImageUpload: (file: File) => void; onImageUpload: (file: File) => void;
} }
export const CollectionImage = withStyles(styles)( export const CollectionImage: React.FC<CollectionImageProps> = props => {
({ const { data, onImageUpload, image, onChange, onImageDelete } = props;
classes,
data,
onImageUpload,
image,
onChange,
onImageDelete
}: CollectionImageProps & WithStyles<typeof styles>) => {
const anchor = React.useRef<HTMLInputElement>();
const intl = useIntl();
const handleImageUploadButtonClick = () => anchor.current.click(); const anchor = React.useRef<HTMLInputElement>();
const classes = useStyles(props);
const intl = useIntl();
return ( const handleImageUploadButtonClick = () => anchor.current.click();
<Card>
<CardTitle return (
title={intl.formatMessage({ <Card>
defaultMessage: "Background Image (optional)", <CardTitle
description: "section header" title={intl.formatMessage({
})} defaultMessage: "Background Image (optional)",
toolbar={ description: "section header"
<> })}
<Button toolbar={
variant="text"
color="primary"
onClick={handleImageUploadButtonClick}
>
<FormattedMessage {...commonMessages.uploadImage} />
</Button>
<input
className={classes.fileField}
id="fileUpload"
onChange={event => onImageUpload(event.target.files[0])}
type="file"
ref={anchor}
/>
</>
}
/>
{image === undefined ? (
<CardContent>
<div>
<div className={classes.imageContainer}>
<Skeleton />
</div>
</div>
</CardContent>
) : image === null ? (
<ImageUpload onImageUpload={onImageUpload} />
) : (
<CardContent>
<ImageTile image={image} onImageDelete={onImageDelete} />
</CardContent>
)}
{image && (
<> <>
<Hr /> <Button
<CardContent> variant="text"
<TextField color="primary"
name="backgroundImageAlt" onClick={handleImageUploadButtonClick}
label={intl.formatMessage(commonMessages.description)} >
helperText={intl.formatMessage({ <FormattedMessage {...commonMessages.uploadImage} />
defaultMessage: "(Optional)", </Button>
description: "field is optional" <input
})} className={classes.fileField}
value={data.backgroundImageAlt} id="fileUpload"
onChange={onChange} onChange={event => onImageUpload(event.target.files[0])}
fullWidth type="file"
multiline ref={anchor}
/> />
</CardContent>
</> </>
)} }
</Card> />
); {image === undefined ? (
} <CardContent>
); <div>
<div className={classes.imageContainer}>
<Skeleton />
</div>
</div>
</CardContent>
) : image === null ? (
<ImageUpload onImageUpload={onImageUpload} />
) : (
<CardContent>
<ImageTile image={image} onImageDelete={onImageDelete} />
</CardContent>
)}
{image && (
<>
<Hr />
<CardContent>
<TextField
name="backgroundImageAlt"
label={intl.formatMessage(commonMessages.description)}
helperText={intl.formatMessage({
defaultMessage: "(Optional)",
description: "field is optional"
})}
value={data.backgroundImageAlt}
onChange={onChange}
fullWidth
multiline
/>
</CardContent>
</>
)}
</Card>
);
};
CollectionImage.displayName = "CollectionImage"; CollectionImage.displayName = "CollectionImage";
export default CollectionImage; export default CollectionImage;

View file

@ -1,9 +1,4 @@
import { import { makeStyles } from "@material-ui/core/styles";
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import Table from "@material-ui/core/Table"; import Table from "@material-ui/core/Table";
import TableBody from "@material-ui/core/TableBody"; import TableBody from "@material-ui/core/TableBody";
import TableCell from "@material-ui/core/TableCell"; import TableCell from "@material-ui/core/TableCell";
@ -21,8 +16,8 @@ import { maybe, renderCollection } from "@saleor/misc";
import { ListActions, ListProps } from "@saleor/types"; import { ListActions, ListProps } from "@saleor/types";
import { CollectionList_collections_edges_node } from "../../types/CollectionList"; import { CollectionList_collections_edges_node } from "../../types/CollectionList";
const styles = (theme: Theme) => const useStyles = makeStyles(
createStyles({ theme => ({
[theme.breakpoints.up("lg")]: { [theme.breakpoints.up("lg")]: {
colAvailability: { colAvailability: {
width: 240 width: 240
@ -42,20 +37,18 @@ const styles = (theme: Theme) =>
tableRow: { tableRow: {
cursor: "pointer" as "pointer" cursor: "pointer" as "pointer"
} }
}); }),
{ name: "CollectionList" }
);
interface CollectionListProps interface CollectionListProps extends ListProps, ListActions {
extends ListProps,
ListActions,
WithStyles<typeof styles> {
collections: CollectionList_collections_edges_node[]; collections: CollectionList_collections_edges_node[];
} }
const numberOfColumns = 5; const numberOfColumns = 5;
const CollectionList = withStyles(styles, { name: "CollectionList" })( const CollectionList: React.FC<CollectionListProps> = props => {
({ const {
classes,
collections, collections,
disabled, disabled,
settings, settings,
@ -69,122 +62,121 @@ const CollectionList = withStyles(styles, { name: "CollectionList" })(
toggle, toggle,
toggleAll, toggleAll,
toolbar toolbar
}: CollectionListProps) => { } = props;
const intl = useIntl();
return ( const classes = useStyles(props);
<Table> const intl = useIntl();
<TableHead
colSpan={numberOfColumns} return (
selected={selected} <Table>
disabled={disabled} <TableHead
items={collections} colSpan={numberOfColumns}
toggleAll={toggleAll} selected={selected}
toolbar={toolbar} disabled={disabled}
> items={collections}
<TableCell className={classes.colName}> toggleAll={toggleAll}
<FormattedMessage defaultMessage="Category Name" /> toolbar={toolbar}
</TableCell> >
<TableCell className={classes.colProducts}> <TableCell className={classes.colName}>
<FormattedMessage defaultMessage="No. of Products" /> <FormattedMessage defaultMessage="Category Name" />
</TableCell> </TableCell>
<TableCell className={classes.colAvailability}> <TableCell className={classes.colProducts}>
<FormattedMessage <FormattedMessage defaultMessage="No. of Products" />
defaultMessage="Availability" </TableCell>
description="collection availability" <TableCell className={classes.colAvailability}>
/> <FormattedMessage
</TableCell> defaultMessage="Availability"
</TableHead> description="collection availability"
<TableFooter> />
<TableRow> </TableCell>
<TablePagination </TableHead>
colSpan={numberOfColumns} <TableFooter>
settings={settings} <TableRow>
hasNextPage={pageInfo && !disabled ? pageInfo.hasNextPage : false} <TablePagination
onNextPage={onNextPage} colSpan={numberOfColumns}
onUpdateListSettings={onUpdateListSettings} settings={settings}
hasPreviousPage={ hasNextPage={pageInfo && !disabled ? pageInfo.hasNextPage : false}
pageInfo && !disabled ? pageInfo.hasPreviousPage : false onNextPage={onNextPage}
} onUpdateListSettings={onUpdateListSettings}
onPreviousPage={onPreviousPage} hasPreviousPage={
/> pageInfo && !disabled ? pageInfo.hasPreviousPage : false
</TableRow> }
</TableFooter> onPreviousPage={onPreviousPage}
<TableBody> />
{renderCollection( </TableRow>
collections, </TableFooter>
collection => { <TableBody>
const isSelected = collection ? isChecked(collection.id) : false; {renderCollection(
return ( collections,
<TableRow collection => {
className={classes.tableRow} const isSelected = collection ? isChecked(collection.id) : false;
hover={!!collection} return (
onClick={collection ? onRowClick(collection.id) : undefined} <TableRow
key={collection ? collection.id : "skeleton"} className={classes.tableRow}
selected={isSelected} hover={!!collection}
data-tc="id" onClick={collection ? onRowClick(collection.id) : undefined}
data-tc-id={maybe(() => collection.id)} key={collection ? collection.id : "skeleton"}
selected={isSelected}
data-tc="id"
data-tc-id={maybe(() => collection.id)}
>
<TableCell padding="checkbox">
<Checkbox
checked={isSelected}
disabled={disabled}
disableClickPropagation
onChange={() => toggle(collection.id)}
/>
</TableCell>
<TableCell className={classes.colName} data-tc="name">
{maybe<React.ReactNode>(() => collection.name, <Skeleton />)}
</TableCell>
<TableCell className={classes.colProducts}>
{maybe<React.ReactNode>(
() => collection.products.totalCount,
<Skeleton />
)}
</TableCell>
<TableCell
className={classes.colAvailability}
data-tc="published"
data-tc-published={maybe(() => collection.isPublished)}
> >
<TableCell padding="checkbox"> {maybe(
<Checkbox () => (
checked={isSelected} <StatusLabel
disabled={disabled} status={collection.isPublished ? "success" : "error"}
disableClickPropagation label={
onChange={() => toggle(collection.id)} collection.isPublished
/> ? intl.formatMessage({
</TableCell> defaultMessage: "Published",
<TableCell className={classes.colName} data-tc="name"> description: "collection is published"
{maybe<React.ReactNode>( })
() => collection.name, : intl.formatMessage({
<Skeleton /> defaultMessage: "Not published",
)} description: "collection is not published"
</TableCell> })
<TableCell className={classes.colProducts}> }
{maybe<React.ReactNode>( />
() => collection.products.totalCount, ),
<Skeleton /> <Skeleton />
)} )}
</TableCell>
<TableCell
className={classes.colAvailability}
data-tc="published"
data-tc-published={maybe(() => collection.isPublished)}
>
{maybe(
() => (
<StatusLabel
status={collection.isPublished ? "success" : "error"}
label={
collection.isPublished
? intl.formatMessage({
defaultMessage: "Published",
description: "collection is published"
})
: intl.formatMessage({
defaultMessage: "Not published",
description: "collection is not published"
})
}
/>
),
<Skeleton />
)}
</TableCell>
</TableRow>
);
},
() => (
<TableRow>
<TableCell colSpan={numberOfColumns}>
<FormattedMessage defaultMessage="No collections found" />
</TableCell> </TableCell>
</TableRow> </TableRow>
) );
)} },
</TableBody> () => (
</Table> <TableRow>
); <TableCell colSpan={numberOfColumns}>
} <FormattedMessage defaultMessage="No collections found" />
); </TableCell>
</TableRow>
)
)}
</TableBody>
</Table>
);
};
CollectionList.displayName = "CollectionList"; CollectionList.displayName = "CollectionList";
export default CollectionList; export default CollectionList;

View file

@ -1,12 +1,7 @@
import Button from "@material-ui/core/Button"; import Button from "@material-ui/core/Button";
import Card from "@material-ui/core/Card"; import Card from "@material-ui/core/Card";
import IconButton from "@material-ui/core/IconButton"; import IconButton from "@material-ui/core/IconButton";
import { import { makeStyles } from "@material-ui/core/styles";
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import Table from "@material-ui/core/Table"; import Table from "@material-ui/core/Table";
import TableBody from "@material-ui/core/TableBody"; import TableBody from "@material-ui/core/TableBody";
import TableCell from "@material-ui/core/TableCell"; import TableCell from "@material-ui/core/TableCell";
@ -29,13 +24,13 @@ import { maybe, renderCollection } from "../../../misc";
import { ListActions, PageListProps } from "../../../types"; import { ListActions, PageListProps } from "../../../types";
import { CollectionDetails_collection } from "../../types/CollectionDetails"; import { CollectionDetails_collection } from "../../types/CollectionDetails";
const styles = (theme: Theme) => const useStyles = makeStyles(
createStyles({ theme => ({
colActions: { colActions: {
"&:last-child": { "&:last-child": {
paddingRight: 0 paddingRight: 0
}, },
width: 76 + theme.spacing.unit / 2 width: 76 + theme.spacing(0.5)
}, },
colName: { colName: {
paddingLeft: 0, paddingLeft: 0,
@ -56,21 +51,19 @@ const styles = (theme: Theme) =>
tableRow: { tableRow: {
cursor: "pointer" cursor: "pointer"
} }
}); }),
{ name: "CollectionProducts" }
);
export interface CollectionProductsProps export interface CollectionProductsProps extends PageListProps, ListActions {
extends PageListProps,
ListActions,
WithStyles<typeof styles> {
collection: CollectionDetails_collection; collection: CollectionDetails_collection;
onProductUnassign: (id: string, event: React.MouseEvent<any>) => void; onProductUnassign: (id: string, event: React.MouseEvent<any>) => void;
} }
const numberOfColumns = 5; const numberOfColumns = 5;
const CollectionProducts = withStyles(styles, { name: "CollectionProducts" })( const CollectionProducts: React.FC<CollectionProductsProps> = props => {
({ const {
classes,
collection, collection,
disabled, disabled,
onAdd, onAdd,
@ -84,165 +77,165 @@ const CollectionProducts = withStyles(styles, { name: "CollectionProducts" })(
toggle, toggle,
toggleAll, toggleAll,
toolbar toolbar
}: CollectionProductsProps) => { } = props;
const intl = useIntl();
return ( const classes = useStyles(props);
<Card> const intl = useIntl();
<CardTitle
title={
!!collection ? (
intl.formatMessage(
{
defaultMessage: "Products in {name}",
description: "products in collection"
},
{
name: maybe(() => collection.name, "...")
}
)
) : (
<Skeleton />
)
}
toolbar={
<Button
disabled={disabled}
variant="text"
color="primary"
onClick={onAdd}
>
<FormattedMessage
defaultMessage="Assign product"
description="button"
/>
</Button>
}
/>
<Table className={classes.table}>
<TableHead
colSpan={numberOfColumns}
selected={selected}
disabled={disabled}
items={maybe(() =>
collection.products.edges.map(edge => edge.node)
)}
toggleAll={toggleAll}
toolbar={toolbar}
>
<TableCell className={classes.colName}>
<span className={classes.colNameLabel}>
<FormattedMessage
defaultMessage="Name"
description="product name"
/>
</span>
</TableCell>
<TableCell className={classes.colType}>
<FormattedMessage
defaultMessage="Type"
description="product type"
/>
</TableCell>
<TableCell className={classes.colPublished}>
<FormattedMessage
defaultMessage="Published"
description="product is published"
/>
</TableCell>
<TableCell className={classes.colActions} />
</TableHead>
<TableFooter>
<TableRow>
<TablePagination
colSpan={numberOfColumns}
hasNextPage={maybe(() => pageInfo.hasNextPage)}
onNextPage={onNextPage}
hasPreviousPage={maybe(() => pageInfo.hasPreviousPage)}
onPreviousPage={onPreviousPage}
/>
</TableRow>
</TableFooter>
<TableBody>
{renderCollection(
maybe(() => collection.products.edges.map(edge => edge.node)),
product => {
const isSelected = product ? isChecked(product.id) : false;
return ( return (
<TableRow <Card>
className={classes.tableRow} <CardTitle
hover={!!product} title={
onClick={!!product ? onRowClick(product.id) : undefined} !!collection ? (
key={product ? product.id : "skeleton"} intl.formatMessage(
selected={isSelected} {
> defaultMessage: "Products in {name}",
<TableCell padding="checkbox"> description: "products in collection"
<Checkbox
checked={isSelected}
disabled={disabled}
disableClickPropagation
onChange={() => toggle(product.id)}
/>
</TableCell>
<TableCellAvatar
className={classes.colName}
thumbnail={maybe(() => product.thumbnail.url)}
>
{maybe<React.ReactNode>(() => product.name, <Skeleton />)}
</TableCellAvatar>
<TableCell className={classes.colType}>
{maybe<React.ReactNode>(
() => product.productType.name,
<Skeleton />
)}
</TableCell>
<TableCell className={classes.colPublished}>
{maybe(
() => (
<StatusLabel
label={
product.isPublished
? intl.formatMessage({
defaultMessage: "Published",
description: "product is published"
})
: intl.formatMessage({
defaultMessage: "Not published",
description: "product is not published"
})
}
status={product.isPublished ? "success" : "error"}
/>
),
<Skeleton />
)}
</TableCell>
<TableCell className={classes.colActions}>
<IconButton
disabled={!product}
onClick={event => onProductUnassign(product.id, event)}
>
<DeleteIcon color="primary" />
</IconButton>
</TableCell>
</TableRow>
);
}, },
() => ( {
<TableRow> name: maybe(() => collection.name, "...")
<TableCell /> }
<TableCell colSpan={numberOfColumns}> )
<FormattedMessage defaultMessage="No products found" /> ) : (
<Skeleton />
)
}
toolbar={
<Button
disabled={disabled}
variant="text"
color="primary"
onClick={onAdd}
>
<FormattedMessage
defaultMessage="Assign product"
description="button"
/>
</Button>
}
/>
<Table className={classes.table}>
<TableHead
colSpan={numberOfColumns}
selected={selected}
disabled={disabled}
items={maybe(() => collection.products.edges.map(edge => edge.node))}
toggleAll={toggleAll}
toolbar={toolbar}
>
<TableCell className={classes.colName}>
<span className={classes.colNameLabel}>
<FormattedMessage
defaultMessage="Name"
description="product name"
/>
</span>
</TableCell>
<TableCell className={classes.colType}>
<FormattedMessage
defaultMessage="Type"
description="product type"
/>
</TableCell>
<TableCell className={classes.colPublished}>
<FormattedMessage
defaultMessage="Published"
description="product is published"
/>
</TableCell>
<TableCell className={classes.colActions} />
</TableHead>
<TableFooter>
<TableRow>
<TablePagination
colSpan={numberOfColumns}
hasNextPage={maybe(() => pageInfo.hasNextPage)}
onNextPage={onNextPage}
hasPreviousPage={maybe(() => pageInfo.hasPreviousPage)}
onPreviousPage={onPreviousPage}
/>
</TableRow>
</TableFooter>
<TableBody>
{renderCollection(
maybe(() => collection.products.edges.map(edge => edge.node)),
product => {
const isSelected = product ? isChecked(product.id) : false;
return (
<TableRow
className={classes.tableRow}
hover={!!product}
onClick={!!product ? onRowClick(product.id) : undefined}
key={product ? product.id : "skeleton"}
selected={isSelected}
>
<TableCell padding="checkbox">
<Checkbox
checked={isSelected}
disabled={disabled}
disableClickPropagation
onChange={() => toggle(product.id)}
/>
</TableCell>
<TableCellAvatar
className={classes.colName}
thumbnail={maybe(() => product.thumbnail.url)}
>
{maybe<React.ReactNode>(() => product.name, <Skeleton />)}
</TableCellAvatar>
<TableCell className={classes.colType}>
{maybe<React.ReactNode>(
() => product.productType.name,
<Skeleton />
)}
</TableCell>
<TableCell className={classes.colPublished}>
{maybe(
() => (
<StatusLabel
label={
product.isPublished
? intl.formatMessage({
defaultMessage: "Published",
description: "product is published"
})
: intl.formatMessage({
defaultMessage: "Not published",
description: "product is not published"
})
}
status={product.isPublished ? "success" : "error"}
/>
),
<Skeleton />
)}
</TableCell>
<TableCell className={classes.colActions}>
<IconButton
disabled={!product}
onClick={event => onProductUnassign(product.id, event)}
>
<DeleteIcon color="primary" />
</IconButton>
</TableCell> </TableCell>
</TableRow> </TableRow>
) );
)} },
</TableBody> () => (
</Table> <TableRow>
</Card> <TableCell />
); <TableCell colSpan={numberOfColumns}>
} <FormattedMessage defaultMessage="No products found" />
); </TableCell>
</TableRow>
)
)}
</TableBody>
</Table>
</Card>
);
};
CollectionProducts.displayName = "CollectionProducts"; CollectionProducts.displayName = "CollectionProducts";
export default CollectionProducts; export default CollectionProducts;

View file

@ -231,7 +231,7 @@ export const CollectionDetails: React.FC<CollectionDetailsProps> = ({
onAdd={() => openModal("assign")} onAdd={() => openModal("assign")}
onBack={() => navigate(collectionListUrl())} onBack={() => navigate(collectionListUrl())}
disabled={loading} disabled={loading}
collection={data.collection} collection={maybe(() => data.collection)}
isFeatured={maybe( isFeatured={maybe(
() => () =>
data.shop.homepageCollection.id === data.collection.id, data.shop.homepageCollection.id === data.collection.id,
@ -349,10 +349,7 @@ export const CollectionDetails: React.FC<CollectionDetailsProps> = ({
> >
<DialogContentText> <DialogContentText>
<FormattedMessage <FormattedMessage
defaultMessage="Are you sure you want to unassign {counter, plural, defaultMessage="Are you sure you want to unassign {counter,plural,one{this product} other{{displayQuantity} products}}?"
one {this product}
other {{displayQuantity} products}
}?"
values={{ values={{
counter: maybe(() => params.ids.length), counter: maybe(() => params.ids.length),
displayQuantity: ( displayQuantity: (

View file

@ -268,10 +268,7 @@ export const CollectionList: React.FC<CollectionListProps> = ({ params }) => {
> >
<DialogContentText> <DialogContentText>
<FormattedMessage <FormattedMessage
defaultMessage="Are you sure you want to publish {counter, plural, defaultMessage="Are you sure you want to publish {counter,plural,one{this collection} other{{displayQuantity} collections}}?"
one {this collection}
other {{displayQuantity} collections}
}?"
values={{ values={{
counter: maybe(() => params.ids.length), counter: maybe(() => params.ids.length),
displayQuantity: ( displayQuantity: (
@ -306,10 +303,7 @@ export const CollectionList: React.FC<CollectionListProps> = ({ params }) => {
> >
<DialogContentText> <DialogContentText>
<FormattedMessage <FormattedMessage
defaultMessage="Are you sure you want to unpublish {counter, plural, defaultMessage="Are you sure you want to unpublish {counter,plural,one{this collection} other{{displayQuantity} collections}}?"
one {this collection}
other {{displayQuantity} collections}
}?"
values={{ values={{
counter: maybe(() => params.ids.length), counter: maybe(() => params.ids.length),
displayQuantity: ( displayQuantity: (
@ -343,10 +337,7 @@ export const CollectionList: React.FC<CollectionListProps> = ({ params }) => {
> >
<DialogContentText> <DialogContentText>
<FormattedMessage <FormattedMessage
defaultMessage="Are you sure you want to delete {counter, plural, defaultMessage="Are you sure you want to delete {counter,plural,one{this collection} other{{displayQuantity} collections}}?"
one {this collection}
other {{displayQuantity} collections}
}?"
values={{ values={{
counter: maybe(() => params.ids.length), counter: maybe(() => params.ids.length),
displayQuantity: ( displayQuantity: (

View file

@ -1,11 +1,6 @@
import Card from "@material-ui/core/Card"; import Card from "@material-ui/core/Card";
import CardContent from "@material-ui/core/CardContent"; import CardContent from "@material-ui/core/CardContent";
import { import { makeStyles } from "@material-ui/core/styles";
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import Typography from "@material-ui/core/Typography"; import Typography from "@material-ui/core/Typography";
import React from "react"; import React from "react";
import { FormattedMessage, useIntl } from "react-intl"; import { FormattedMessage, useIntl } from "react-intl";
@ -15,21 +10,23 @@ import { ControlledCheckbox } from "@saleor/components/ControlledCheckbox";
import { ShopInfo_shop_permissions } from "@saleor/components/Shop/types/ShopInfo"; import { ShopInfo_shop_permissions } from "@saleor/components/Shop/types/ShopInfo";
import Skeleton from "@saleor/components/Skeleton"; import Skeleton from "@saleor/components/Skeleton";
const styles = (theme: Theme) => const useStyles = makeStyles(
createStyles({ theme => ({
checkboxContainer: { checkboxContainer: {
marginTop: theme.spacing.unit marginTop: theme.spacing()
}, },
hr: { hr: {
backgroundColor: theme.overrides.MuiCard.root.borderColor, backgroundColor: theme.palette.divider,
border: "none", border: "none",
height: 1, height: 1,
marginBottom: 0, marginBottom: 0,
marginTop: 0 marginTop: 0
} }
}); }),
{ name: "AccountPermissions" }
);
interface AccountPermissionsProps extends WithStyles<typeof styles> { interface AccountPermissionsProps {
permissions: ShopInfo_shop_permissions[]; permissions: ShopInfo_shop_permissions[];
data: { data: {
hasFullAccess: boolean; hasFullAccess: boolean;
@ -39,89 +36,85 @@ interface AccountPermissionsProps extends WithStyles<typeof styles> {
onChange: (event: React.ChangeEvent<any>, cb?: () => void) => void; onChange: (event: React.ChangeEvent<any>, cb?: () => void) => void;
} }
const AccountPermissions = withStyles(styles, { name: "AccountPermissions" })( const AccountPermissions: React.FC<AccountPermissionsProps> = props => {
({ const { data, disabled, permissions, onChange } = props;
classes,
data,
disabled,
permissions,
onChange
}: AccountPermissionsProps) => {
const intl = useIntl();
const handleFullAccessChange = (event: React.ChangeEvent<any>) => const classes = useStyles(props);
onChange(event, () => const intl = useIntl();
onChange({
target: { const handleFullAccessChange = (event: React.ChangeEvent<any>) =>
name: "permissions", onChange(event, () =>
value: event.target.value ? permissions.map(perm => perm.code) : []
}
} as any)
);
const handlePermissionChange = (event: React.ChangeEvent<any>) => {
onChange({ onChange({
target: { target: {
name: "permissions", name: "permissions",
value: event.target.value value: event.target.value ? permissions.map(perm => perm.code) : []
? data.permissions.concat([event.target.name])
: data.permissions.filter(perm => perm !== event.target.name)
} }
} as any); } as any)
};
return (
<Card>
<CardTitle
title={intl.formatMessage({
defaultMessage: "Permissions",
description: "dialog header"
})}
/>
<CardContent>
<Typography>
<FormattedMessage defaultMessage="Expand or restrict user's permissions to access certain part of saleor system." />
</Typography>
<div className={classes.checkboxContainer}>
<ControlledCheckbox
checked={data.hasFullAccess}
disabled={disabled}
label={intl.formatMessage({
defaultMessage: "User has full access to the store",
description: "checkbox label"
})}
name="hasFullAccess"
onChange={handleFullAccessChange}
/>
</div>
</CardContent>
{!data.hasFullAccess && (
<>
<hr className={classes.hr} />
<CardContent>
{permissions === undefined ? (
<Skeleton />
) : (
permissions.map(perm => (
<div key={perm.code}>
<ControlledCheckbox
checked={
data.permissions.filter(
userPerm => userPerm === perm.code
).length === 1
}
disabled={disabled}
label={perm.name.replace(/\./, "")}
name={perm.code}
onChange={handlePermissionChange}
/>
</div>
))
)}
</CardContent>
</>
)}
</Card>
); );
} const handlePermissionChange = (event: React.ChangeEvent<any>) => {
); onChange({
target: {
name: "permissions",
value: event.target.value
? data.permissions.concat([event.target.name])
: data.permissions.filter(perm => perm !== event.target.name)
}
} as any);
};
return (
<Card>
<CardTitle
title={intl.formatMessage({
defaultMessage: "Permissions",
description: "dialog header"
})}
/>
<CardContent>
<Typography>
<FormattedMessage defaultMessage="Expand or restrict user's permissions to access certain part of saleor system." />
</Typography>
<div className={classes.checkboxContainer}>
<ControlledCheckbox
checked={data.hasFullAccess}
disabled={disabled}
label={intl.formatMessage({
defaultMessage: "User has full access to the store",
description: "checkbox label"
})}
name="hasFullAccess"
onChange={handleFullAccessChange}
/>
</div>
</CardContent>
{!data.hasFullAccess && (
<>
<hr className={classes.hr} />
<CardContent>
{permissions === undefined ? (
<Skeleton />
) : (
permissions.map(perm => (
<div key={perm.code}>
<ControlledCheckbox
checked={
data.permissions.filter(
userPerm => userPerm === perm.code
).length === 1
}
disabled={disabled}
label={perm.name.replace(/\./, "")}
name={perm.code}
onChange={handlePermissionChange}
/>
</div>
))
)}
</CardContent>
</>
)}
</Card>
);
};
AccountPermissions.displayName = "AccountPermissions"; AccountPermissions.displayName = "AccountPermissions";
export default AccountPermissions; export default AccountPermissions;

View file

@ -3,12 +3,7 @@ import Dialog from "@material-ui/core/Dialog";
import DialogActions from "@material-ui/core/DialogActions"; import DialogActions from "@material-ui/core/DialogActions";
import DialogContent from "@material-ui/core/DialogContent"; import DialogContent from "@material-ui/core/DialogContent";
import DialogTitle from "@material-ui/core/DialogTitle"; import DialogTitle from "@material-ui/core/DialogTitle";
import { import { makeStyles } from "@material-ui/core/styles";
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import classNames from "classnames"; import classNames from "classnames";
import React from "react"; import React from "react";
import { FormattedMessage, useIntl } from "react-intl"; import { FormattedMessage, useIntl } from "react-intl";
@ -18,8 +13,8 @@ import ConfirmButton, {
ConfirmButtonTransitionState ConfirmButtonTransitionState
} from "../ConfirmButton/ConfirmButton"; } from "../ConfirmButton/ConfirmButton";
const styles = (theme: Theme) => const useStyles = makeStyles(
createStyles({ theme => ({
deleteButton: { deleteButton: {
"&:hover": { "&:hover": {
backgroundColor: theme.palette.error.main backgroundColor: theme.palette.error.main
@ -27,12 +22,15 @@ const styles = (theme: Theme) =>
backgroundColor: theme.palette.error.main, backgroundColor: theme.palette.error.main,
color: theme.palette.error.contrastText color: theme.palette.error.contrastText
} }
}); }),
{ name: "ActionDialog" }
);
interface ActionDialogProps extends WithStyles<typeof styles> { interface ActionDialogProps {
children?: React.ReactNode; children?: React.ReactNode;
confirmButtonLabel?: string; confirmButtonLabel?: string;
confirmButtonState: ConfirmButtonTransitionState; confirmButtonState: ConfirmButtonTransitionState;
maxWidth?: "xs" | "sm" | "md" | "lg" | "xl" | false;
open: boolean; open: boolean;
title: string; title: string;
variant?: "default" | "delete"; variant?: "default" | "delete";
@ -40,46 +38,52 @@ interface ActionDialogProps extends WithStyles<typeof styles> {
onConfirm(); onConfirm();
} }
const ActionDialog = withStyles(styles, { name: "ActionDialog" })( const ActionDialog: React.FC<ActionDialogProps> = props => {
({ const {
children, children,
classes,
confirmButtonLabel, confirmButtonLabel,
confirmButtonState, confirmButtonState,
open, open,
title, title,
variant, variant,
onConfirm, onConfirm,
onClose onClose,
}: ActionDialogProps) => { ...rest
const intl = useIntl(); } = props;
return ( const classes = useStyles(props);
<Dialog onClose={onClose} open={open}> const intl = useIntl();
<DialogTitle>{title}</DialogTitle>
<DialogContent>{children}</DialogContent> return (
<DialogActions> <Dialog fullWidth onClose={onClose} open={open} {...rest}>
<Button onClick={onClose}> <DialogTitle>{title}</DialogTitle>
<FormattedMessage {...buttonMessages.back} /> <DialogContent>{children}</DialogContent>
</Button> <DialogActions>
<ConfirmButton <Button onClick={onClose}>
transitionState={confirmButtonState} <FormattedMessage {...buttonMessages.back} />
color="primary" </Button>
variant="contained" <ConfirmButton
onClick={onConfirm} transitionState={confirmButtonState}
className={classNames({ color="primary"
[classes.deleteButton]: variant === "delete" variant="contained"
})} onClick={onConfirm}
> className={classNames({
{confirmButtonLabel || [classes.deleteButton]: variant === "delete"
(variant === "delete" })}
? intl.formatMessage(buttonMessages.delete) >
: intl.formatMessage(buttonMessages.confirm))} {confirmButtonLabel ||
</ConfirmButton> (variant === "delete"
</DialogActions> ? intl.formatMessage(buttonMessages.delete)
</Dialog> : intl.formatMessage(buttonMessages.confirm))}
); </ConfirmButton>
} </DialogActions>
); </Dialog>
);
};
ActionDialog.defaultProps = {
maxWidth: "xs",
variant: "default"
};
ActionDialog.displayName = "ActionDialog"; ActionDialog.displayName = "ActionDialog";
export default ActionDialog; export default ActionDialog;

View file

@ -1,9 +1,4 @@
import { import { makeStyles } from "@material-ui/core/styles";
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import TextField from "@material-ui/core/TextField"; import TextField from "@material-ui/core/TextField";
import React from "react"; import React from "react";
import { useIntl } from "react-intl"; import { useIntl } from "react-intl";
@ -16,16 +11,15 @@ import SingleAutocompleteSelectField, {
SingleAutocompleteChoiceType SingleAutocompleteChoiceType
} from "../SingleAutocompleteSelectField"; } from "../SingleAutocompleteSelectField";
const styles = (theme: Theme) => const useStyles = makeStyles(theme => ({
createStyles({ root: {
root: { display: "grid",
display: "grid", gridColumnGap: theme.spacing(2),
gridColumnGap: `${theme.spacing.unit * 2}px`, gridTemplateColumns: "1fr 1fr"
gridTemplateColumns: "1fr 1fr" }
} }));
});
interface AddressEditProps extends WithStyles<typeof styles> { interface AddressEditProps {
countries: SingleAutocompleteChoiceType[]; countries: SingleAutocompleteChoiceType[];
countryDisplayValue: string; countryDisplayValue: string;
data: AddressTypeInput; data: AddressTypeInput;
@ -35,9 +29,8 @@ interface AddressEditProps extends WithStyles<typeof styles> {
onCountryChange(event: React.ChangeEvent<any>); onCountryChange(event: React.ChangeEvent<any>);
} }
const AddressEdit = withStyles(styles, { name: "AddressEdit" })( const AddressEdit: React.FC<AddressEditProps> = props => {
({ const {
classes,
countries, countries,
countryDisplayValue, countryDisplayValue,
data, data,
@ -45,164 +38,165 @@ const AddressEdit = withStyles(styles, { name: "AddressEdit" })(
errors, errors,
onChange, onChange,
onCountryChange onCountryChange
}: AddressEditProps) => { } = props;
const intl = useIntl(); const classes = useStyles(props);
return ( const intl = useIntl();
<>
<div className={classes.root}>
<div>
<TextField
disabled={disabled}
error={!!errors.firstName}
helperText={errors.firstName}
label={intl.formatMessage(commonMessages.firstName)}
name="firstName"
onChange={onChange}
value={data.firstName}
fullWidth
/>
</div>
<div>
<TextField
disabled={disabled}
error={!!errors.lastName}
helperText={errors.lastName}
label={intl.formatMessage(commonMessages.lastName)}
name="lastName"
onChange={onChange}
value={data.lastName}
fullWidth
/>
</div>
</div>
<FormSpacer />
<div className={classes.root}>
<div>
<TextField
disabled={disabled}
error={!!errors.companyName}
helperText={errors.companyName}
label={intl.formatMessage({
defaultMessage: "Company"
})}
name="companyName"
onChange={onChange}
value={data.companyName}
fullWidth
/>
</div>
<div>
<TextField
disabled={disabled}
error={!!errors.phone}
fullWidth
helperText={errors.phone}
label={intl.formatMessage({
defaultMessage: "Phone"
})}
name="phone"
value={data.phone}
onChange={onChange}
/>
</div>
</div>
<FormSpacer />
<TextField
disabled={disabled}
error={!!errors.streetAddress1}
helperText={errors.streetAddress1}
label={intl.formatMessage({
defaultMessage: "Address line 1"
})}
name="streetAddress1"
onChange={onChange}
value={data.streetAddress1}
fullWidth
/>
<FormSpacer />
<TextField
disabled={disabled}
error={!!errors.streetAddress2}
helperText={errors.streetAddress2}
label={intl.formatMessage({
defaultMessage: "Address line 2"
})}
name="streetAddress2"
onChange={onChange}
value={data.streetAddress2}
fullWidth
/>
<FormSpacer />
<div className={classes.root}>
<div>
<TextField
disabled={disabled}
error={!!errors.city}
helperText={errors.city}
label={intl.formatMessage({
defaultMessage: "City"
})}
name="city"
onChange={onChange}
value={data.city}
fullWidth
/>
</div>
<div>
<TextField
disabled={disabled}
error={!!errors.postalCode}
helperText={errors.postalCode}
label={intl.formatMessage({
defaultMessage: "ZIP / Postal code"
})}
name="postalCode"
onChange={onChange}
value={data.postalCode}
fullWidth
/>
</div>
</div>
<FormSpacer /> return (
<div className={classes.root}> <>
<div> <div className={classes.root}>
<SingleAutocompleteSelectField <div>
disabled={disabled} <TextField
displayValue={countryDisplayValue} disabled={disabled}
error={!!errors.country} error={!!errors.firstName}
helperText={errors.country} helperText={errors.firstName}
label={intl.formatMessage({ label={intl.formatMessage(commonMessages.firstName)}
defaultMessage: "Country" name="firstName"
})} onChange={onChange}
name="country" value={data.firstName}
onChange={onCountryChange} fullWidth
value={data.country} />
choices={countries}
InputProps={{
autoComplete: "off"
}}
/>
</div>
<div>
<TextField
disabled={disabled}
error={!!errors.countryArea}
helperText={errors.countryArea}
label={intl.formatMessage({
defaultMessage: "Country area"
})}
name="countryArea"
onChange={onChange}
value={data.countryArea}
fullWidth
/>
</div>
</div> </div>
</> <div>
); <TextField
} disabled={disabled}
); error={!!errors.lastName}
helperText={errors.lastName}
label={intl.formatMessage(commonMessages.lastName)}
name="lastName"
onChange={onChange}
value={data.lastName}
fullWidth
/>
</div>
</div>
<FormSpacer />
<div className={classes.root}>
<div>
<TextField
disabled={disabled}
error={!!errors.companyName}
helperText={errors.companyName}
label={intl.formatMessage({
defaultMessage: "Company"
})}
name="companyName"
onChange={onChange}
value={data.companyName}
fullWidth
/>
</div>
<div>
<TextField
disabled={disabled}
error={!!errors.phone}
fullWidth
helperText={errors.phone}
label={intl.formatMessage({
defaultMessage: "Phone"
})}
name="phone"
value={data.phone}
onChange={onChange}
/>
</div>
</div>
<FormSpacer />
<TextField
disabled={disabled}
error={!!errors.streetAddress1}
helperText={errors.streetAddress1}
label={intl.formatMessage({
defaultMessage: "Address line 1"
})}
name="streetAddress1"
onChange={onChange}
value={data.streetAddress1}
fullWidth
/>
<FormSpacer />
<TextField
disabled={disabled}
error={!!errors.streetAddress2}
helperText={errors.streetAddress2}
label={intl.formatMessage({
defaultMessage: "Address line 2"
})}
name="streetAddress2"
onChange={onChange}
value={data.streetAddress2}
fullWidth
/>
<FormSpacer />
<div className={classes.root}>
<div>
<TextField
disabled={disabled}
error={!!errors.city}
helperText={errors.city}
label={intl.formatMessage({
defaultMessage: "City"
})}
name="city"
onChange={onChange}
value={data.city}
fullWidth
/>
</div>
<div>
<TextField
disabled={disabled}
error={!!errors.postalCode}
helperText={errors.postalCode}
label={intl.formatMessage({
defaultMessage: "ZIP / Postal code"
})}
name="postalCode"
onChange={onChange}
value={data.postalCode}
fullWidth
/>
</div>
</div>
<FormSpacer />
<div className={classes.root}>
<div>
<SingleAutocompleteSelectField
disabled={disabled}
displayValue={countryDisplayValue}
error={!!errors.country}
helperText={errors.country}
label={intl.formatMessage({
defaultMessage: "Country"
})}
name="country"
onChange={onCountryChange}
value={data.country}
choices={countries}
InputProps={{
autoComplete: "off"
}}
/>
</div>
<div>
<TextField
disabled={disabled}
error={!!errors.countryArea}
helperText={errors.countryArea}
label={intl.formatMessage({
defaultMessage: "Country area"
})}
name="countryArea"
onChange={onChange}
value={data.countryArea}
fullWidth
/>
</div>
</div>
</>
);
};
AddressEdit.displayName = "AddressEdit"; AddressEdit.displayName = "AddressEdit";
export default AddressEdit; export default AddressEdit;

View file

@ -18,23 +18,23 @@ const AddressFormatter: React.FC<AddressFormatterProps> = ({ address }) => {
fontStyle: "inherit" fontStyle: "inherit"
}} }}
> >
<Typography component="span"> <Typography component="p">
{address.firstName} {address.lastName} {address.firstName} {address.lastName}
</Typography> </Typography>
{address.companyName && ( {address.companyName && (
<Typography component="span">{address.companyName}</Typography> <Typography component="p">{address.companyName}</Typography>
)} )}
<Typography component="span"> <Typography component="p">
{address.streetAddress1} {address.streetAddress1}
<br /> <br />
{address.streetAddress2} {address.streetAddress2}
</Typography> </Typography>
<Typography component="span"> <Typography component="p">
{" "} {" "}
{address.postalCode} {address.city} {address.postalCode} {address.city}
{address.cityArea ? ", " + address.cityArea : ""} {address.cityArea ? ", " + address.cityArea : ""}
</Typography> </Typography>
<Typography component="span"> <Typography component="p">
{address.countryArea {address.countryArea
? address.countryArea + ", " + address.country.country ? address.countryArea + ", " + address.country.country
: address.country.country} : address.country.country}

View file

@ -1,10 +1,5 @@
import Portal from "@material-ui/core/Portal"; import Portal from "@material-ui/core/Portal";
import { import { makeStyles } from "@material-ui/core/styles";
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import Typography from "@material-ui/core/Typography"; import Typography from "@material-ui/core/Typography";
import ArrowBackIcon from "@material-ui/icons/ArrowBack"; import ArrowBackIcon from "@material-ui/icons/ArrowBack";
import React from "react"; import React from "react";
@ -16,45 +11,44 @@ export interface AppHeaderProps {
onBack(); onBack();
} }
const styles = (theme: Theme) => const useStyles = makeStyles(theme => ({
createStyles({ backArrow: {
backArrow: { fontSize: 30
fontSize: 30 },
menuButton: {
flex: "0 0 auto",
marginLeft: -theme.spacing(2),
marginRight: theme.spacing(),
marginTop: -theme.spacing(2)
},
root: {
"&:hover": {
color: theme.typography.body1.color
}, },
menuButton: { alignItems: "center",
flex: "0 0 auto", color: theme.palette.grey[500],
marginLeft: theme.spacing.unit * -2, cursor: "pointer",
marginRight: theme.spacing.unit, display: "flex",
marginTop: -theme.spacing.unit * 2 marginTop: theme.spacing(0.5),
}, transition: theme.transitions.duration.standard + "ms"
root: { },
"&:hover": { skeleton: {
color: theme.typography.body2.color marginBottom: theme.spacing(2),
}, width: "10rem"
alignItems: "center", },
color: theme.palette.grey[500], title: {
cursor: "pointer", color: "inherit",
display: "flex", flex: 1,
marginTop: theme.spacing.unit / 2, marginLeft: theme.spacing(),
transition: theme.transitions.duration.standard + "ms" textTransform: "uppercase"
}, }
skeleton: { }));
marginBottom: theme.spacing.unit * 2, const AppHeader: React.FC<AppHeaderProps> = props => {
width: "10rem" const { children, onBack } = props;
},
title: { const classes = useStyles(props);
color: "inherit",
flex: 1, return (
marginLeft: theme.spacing.unit,
textTransform: "uppercase"
}
});
const AppHeader = withStyles(styles, { name: "AppHeader" })(
({
children,
classes,
onBack
}: AppHeaderProps & WithStyles<typeof styles>) => (
<AppHeaderContext.Consumer> <AppHeaderContext.Consumer>
{anchor => {anchor =>
anchor ? ( anchor ? (
@ -71,7 +65,7 @@ const AppHeader = withStyles(styles, { name: "AppHeader" })(
) : null ) : null
} }
</AppHeaderContext.Consumer> </AppHeaderContext.Consumer>
) );
); };
AppHeader.displayName = "AppHeader"; AppHeader.displayName = "AppHeader";
export default AppHeader; export default AppHeader;

View file

@ -1,2 +1,2 @@
export { default } from './AppHeader'; export { default } from "./AppHeader";
export * from './AppHeader'; export * from "./AppHeader";

View file

@ -8,12 +8,7 @@ import MenuItem from "@material-ui/core/MenuItem";
import Menu from "@material-ui/core/MenuList"; import Menu from "@material-ui/core/MenuList";
import Paper from "@material-ui/core/Paper"; import Paper from "@material-ui/core/Paper";
import Popper from "@material-ui/core/Popper"; import Popper from "@material-ui/core/Popper";
import { import { makeStyles } from "@material-ui/core/styles";
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import classNames from "classnames"; import classNames from "classnames";
import React from "react"; import React from "react";
import SVG from "react-inlinesvg"; import SVG from "react-inlinesvg";
@ -41,8 +36,8 @@ import createMenuStructure from "./menuStructure";
import ResponsiveDrawer from "./ResponsiveDrawer"; import ResponsiveDrawer from "./ResponsiveDrawer";
import ThemeSwitch from "./ThemeSwitch"; import ThemeSwitch from "./ThemeSwitch";
const styles = (theme: Theme) => const useStyles = makeStyles(
createStyles({ theme => ({
appAction: { appAction: {
[theme.breakpoints.down("sm")]: { [theme.breakpoints.down("sm")]: {
left: 0, left: 0,
@ -56,15 +51,15 @@ const styles = (theme: Theme) =>
}, },
appLoader: { appLoader: {
height: appLoaderHeight, height: appLoaderHeight,
marginBottom: theme.spacing.unit * 2, marginBottom: theme.spacing(2),
zIndex: 1201 zIndex: 1201
}, },
appLoaderPlaceholder: { appLoaderPlaceholder: {
height: appLoaderHeight, height: appLoaderHeight,
marginBottom: theme.spacing.unit * 2 marginBottom: theme.spacing(2)
}, },
arrow: { arrow: {
marginLeft: theme.spacing.unit * 2, marginLeft: theme.spacing(2),
transition: theme.transitions.duration.standard + "ms" transition: theme.transitions.duration.standard + "ms"
}, },
content: { content: {
@ -82,12 +77,12 @@ const styles = (theme: Theme) =>
paddingLeft: drawerWidth paddingLeft: drawerWidth
}, },
darkThemeSwitch: { darkThemeSwitch: {
marginRight: theme.spacing.unit * 2 marginRight: theme.spacing(2)
}, },
header: { header: {
display: "flex", display: "flex",
height: 40, height: 40,
marginBottom: theme.spacing.unit * 3 marginBottom: theme.spacing(3)
}, },
isMenuSmall: { isMenuSmall: {
"& path": { "& path": {
@ -186,8 +181,8 @@ const styles = (theme: Theme) =>
borderRadius: "50%", borderRadius: "50%",
cursor: "pointer", cursor: "pointer",
height: 42, height: 42,
left: theme.spacing.unit, left: theme.spacing(),
marginRight: theme.spacing.unit * 2, marginRight: theme.spacing(2),
position: "relative", position: "relative",
transform: "rotate(0deg)", transform: "rotate(0deg)",
transition: `${theme.transitions.duration.shorter}ms ease-in-out`, transition: `${theme.transitions.duration.shorter}ms ease-in-out`,
@ -236,7 +231,7 @@ const styles = (theme: Theme) =>
padding: 0 padding: 0
}, },
background: theme.palette.background.paper, background: theme.palette.background.paper,
padding: `0 ${theme.spacing.unit * 4}px` padding: `0 ${theme.spacing(4)}px`
}, },
spacer: { spacer: {
flex: 1 flex: 1
@ -260,259 +255,240 @@ const styles = (theme: Theme) =>
flex: 1, flex: 1,
flexGrow: 1, flexGrow: 1,
marginLeft: 0, marginLeft: 0,
paddingBottom: theme.spacing.unit, paddingBottom: theme.spacing(),
[theme.breakpoints.up("sm")]: { [theme.breakpoints.up("sm")]: {
paddingBottom: theme.spacing.unit * 3 paddingBottom: theme.spacing(3)
} }
}, },
viewContainer: { viewContainer: {
minHeight: `calc(100vh - ${theme.spacing.unit * 2 + minHeight: `calc(100vh - ${theme.spacing(2) + appLoaderHeight + 70}px)`
appLoaderHeight +
70}px)`
} }
}); }),
{
name: "AppLayout"
}
);
interface AppLayoutProps { interface AppLayoutProps {
children: React.ReactNode; children: React.ReactNode;
} }
const AppLayout = withStyles(styles, { const AppLayout = withRouter<AppLayoutProps & RouteComponentProps<any>, any>(
name: "AppLayout" ({ children, location }: AppLayoutProps & RouteComponentProps<any>) => {
})( const classes = useStyles({});
withRouter<AppLayoutProps & RouteComponentProps<any>, any>( const { isDark, toggleTheme } = useTheme();
({ const [isMenuSmall, setMenuSmall] = useLocalStorage("isMenuSmall", false);
classes, const [isDrawerOpened, setDrawerState] = React.useState(false);
children, const [isMenuOpened, setMenuState] = React.useState(false);
location const appActionAnchor = React.useRef<HTMLDivElement>();
}: AppLayoutProps & const appHeaderAnchor = React.useRef<HTMLDivElement>();
WithStyles<typeof styles> & const anchor = React.useRef<HTMLDivElement>();
RouteComponentProps<any>) => { const { logout, user } = useUser();
const { isDark, toggleTheme } = useTheme(); const navigate = useNavigator();
const [isMenuSmall, setMenuSmall] = useLocalStorage("isMenuSmall", false); const intl = useIntl();
const [isDrawerOpened, setDrawerState] = React.useState(false);
const [isMenuOpened, setMenuState] = React.useState(false);
const appActionAnchor = React.useRef<HTMLDivElement>();
const appHeaderAnchor = React.useRef<HTMLDivElement>();
const anchor = React.useRef<HTMLDivElement>();
const { logout, user } = useUser();
const navigate = useNavigator();
const intl = useIntl();
const menuStructure = createMenuStructure(intl); const menuStructure = createMenuStructure(intl);
const configurationMenu = createConfigurationMenu(intl); const configurationMenu = createConfigurationMenu(intl);
const userPermissions = maybe(() => user.permissions, []); const userPermissions = maybe(() => user.permissions, []);
const renderConfigure = configurationMenu.some(section => const renderConfigure = configurationMenu.some(section =>
section.menuItems.some( section.menuItems.some(
menuItem => menuItem =>
!!userPermissions.find( !!userPermissions.find(
userPermission => userPermission.code === menuItem.permission userPermission => userPermission.code === menuItem.permission
) )
) )
); );
const handleLogout = () => { const handleLogout = () => {
setMenuState(false); setMenuState(false);
logout(); logout();
}; };
const handleViewerProfile = () => { const handleViewerProfile = () => {
setMenuState(false); setMenuState(false);
navigate(staffMemberDetailsUrl(user.id)); navigate(staffMemberDetailsUrl(user.id));
}; };
const handleMenuItemClick = ( const handleMenuItemClick = (url: string, event: React.MouseEvent<any>) => {
url: string, event.stopPropagation();
event: React.MouseEvent<any> event.preventDefault();
) => { setDrawerState(false);
event.stopPropagation(); navigate(url);
event.preventDefault(); };
setDrawerState(false);
navigate(url);
};
const handleIsMenuSmall = () => { const handleIsMenuSmall = () => {
setMenuSmall(!isMenuSmall); setMenuSmall(!isMenuSmall);
}; };
return ( return (
<AppProgressProvider> <AppProgressProvider>
{({ isProgress }) => ( {({ isProgress }) => (
<AppHeaderContext.Provider value={appHeaderAnchor}> <AppHeaderContext.Provider value={appHeaderAnchor}>
<AppActionContext.Provider value={appActionAnchor}> <AppActionContext.Provider value={appActionAnchor}>
<div className={classes.root}> <div className={classes.root}>
<div className={classes.sideBar}> <div className={classes.sideBar}>
<ResponsiveDrawer <ResponsiveDrawer
onClose={() => setDrawerState(false)} onClose={() => setDrawerState(false)}
open={isDrawerOpened} open={isDrawerOpened}
small={!isMenuSmall} small={!isMenuSmall}
>
<div
className={classNames(classes.logo, {
[classes.logoSmall]: isMenuSmall,
[classes.logoDark]: isDark
})}
>
<SVG
src={
isMenuSmall ? saleorDarkLogoSmall : saleorDarkLogo
}
/>
</div>
<Hidden smDown>
<div
className={classNames(classes.isMenuSmall, {
[classes.isMenuSmallHide]: isMenuSmall,
[classes.isMenuSmallDark]: isDark
})}
onClick={handleIsMenuSmall}
>
<SVG src={menuArrowIcon} />
</div>
</Hidden>
<MenuList
className={
isMenuSmall ? classes.menuSmall : classes.menu
}
menuItems={menuStructure}
isMenuSmall={!isMenuSmall}
location={location.pathname}
user={user}
renderConfigure={renderConfigure}
onMenuItemClick={handleMenuItemClick}
/>
</ResponsiveDrawer>
</div>
<div
className={classNames(classes.content, {
[classes.contentToggle]: isMenuSmall
})}
> >
{isProgress ? ( <div
<LinearProgress className={classNames(classes.logo, {
className={classes.appLoader} [classes.logoSmall]: isMenuSmall,
color="primary" [classes.logoDark]: isDark
})}
>
<SVG
src={isMenuSmall ? saleorDarkLogoSmall : saleorDarkLogo}
/> />
) : ( </div>
<div className={classes.appLoaderPlaceholder} /> <Hidden smDown>
)} <div
<div className={classes.viewContainer}> className={classNames(classes.isMenuSmall, {
<div> [classes.isMenuSmallHide]: isMenuSmall,
<Container> [classes.isMenuSmallDark]: isDark
<div className={classes.header}> })}
onClick={handleIsMenuSmall}
>
<SVG src={menuArrowIcon} />
</div>
</Hidden>
<MenuList
className={isMenuSmall ? classes.menuSmall : classes.menu}
menuItems={menuStructure}
isMenuSmall={!isMenuSmall}
location={location.pathname}
user={user}
renderConfigure={renderConfigure}
onMenuItemClick={handleMenuItemClick}
/>
</ResponsiveDrawer>
</div>
<div
className={classNames(classes.content, {
[classes.contentToggle]: isMenuSmall
})}
>
{isProgress ? (
<LinearProgress
className={classes.appLoader}
color="primary"
/>
) : (
<div className={classes.appLoaderPlaceholder} />
)}
<div className={classes.viewContainer}>
<div>
<Container>
<div className={classes.header}>
<div
className={classNames(classes.menuIcon, {
[classes.menuIconOpen]: isDrawerOpened,
[classes.menuIconDark]: isDark
})}
onClick={() => setDrawerState(!isDrawerOpened)}
>
<span />
<span />
<span />
<span />
</div>
<div ref={appHeaderAnchor} />
<div className={classes.spacer} />
<div className={classes.userBar}>
<ThemeSwitch
className={classes.darkThemeSwitch}
checked={isDark}
onClick={toggleTheme}
/>
<div <div
className={classNames(classes.menuIcon, { className={classes.userMenuContainer}
[classes.menuIconOpen]: isDrawerOpened, ref={anchor}
[classes.menuIconDark]: isDark
})}
onClick={() => setDrawerState(!isDrawerOpened)}
> >
<span /> <Chip
<span /> avatar={
<span /> user.avatar && (
<span /> <Avatar alt="user" src={user.avatar.url} />
</div> )
<div ref={appHeaderAnchor} /> }
<div className={classes.spacer} /> className={classes.userChip}
<div className={classes.userBar}> label={
<ThemeSwitch <>
className={classes.darkThemeSwitch} {user.email}
checked={isDark} <ArrowDropdown
onClick={toggleTheme} className={classNames(classes.arrow, {
[classes.rotate]: isMenuOpened
})}
/>
</>
}
onClick={() => setMenuState(!isMenuOpened)}
/> />
<div <Popper
className={classes.userMenuContainer} className={classes.popover}
ref={anchor} open={isMenuOpened}
anchorEl={anchor.current}
transition
disablePortal
placement="bottom-end"
> >
<Chip {({ TransitionProps, placement }) => (
avatar={ <Grow
user.avatar && ( {...TransitionProps}
<Avatar style={{
alt="user" transformOrigin:
src={user.avatar.url} placement === "bottom"
/> ? "right top"
) : "right bottom"
} }}
className={classes.userChip} >
label={ <Paper>
<> <ClickAwayListener
{user.email} onClickAway={() => setMenuState(false)}
<ArrowDropdown mouseEvent="onClick"
className={classNames(classes.arrow, { >
[classes.rotate]: isMenuOpened <Menu>
})} <MenuItem
/> className={classes.userMenuItem}
</> onClick={handleViewerProfile}
} >
onClick={() => setMenuState(!isMenuOpened)} <FormattedMessage
/> defaultMessage="Account Settings"
<Popper description="button"
className={classes.popover} />
open={isMenuOpened} </MenuItem>
anchorEl={anchor.current} <MenuItem
transition className={classes.userMenuItem}
disablePortal onClick={handleLogout}
placement="bottom-end" >
> <FormattedMessage
{({ TransitionProps, placement }) => ( defaultMessage="Log out"
<Grow description="button"
{...TransitionProps} />
style={{ </MenuItem>
transformOrigin: </Menu>
placement === "bottom" </ClickAwayListener>
? "right top" </Paper>
: "right bottom" </Grow>
}} )}
> </Popper>
<Paper>
<ClickAwayListener
onClickAway={() =>
setMenuState(false)
}
mouseEvent="onClick"
>
<Menu>
<MenuItem
className={classes.userMenuItem}
onClick={handleViewerProfile}
>
<FormattedMessage
defaultMessage="Account Settings"
description="button"
/>
</MenuItem>
<MenuItem
className={classes.userMenuItem}
onClick={handleLogout}
>
<FormattedMessage
defaultMessage="Log out"
description="button"
/>
</MenuItem>
</Menu>
</ClickAwayListener>
</Paper>
</Grow>
)}
</Popper>
</div>
</div> </div>
</div> </div>
</Container> </div>
</div> </Container>
<main className={classes.view}>{children}</main>
</div> </div>
<div className={classes.appAction} ref={appActionAnchor} /> <main className={classes.view}>{children}</main>
</div> </div>
<div className={classes.appAction} ref={appActionAnchor} />
</div> </div>
</AppActionContext.Provider> </div>
</AppHeaderContext.Provider> </AppActionContext.Provider>
)} </AppHeaderContext.Provider>
</AppProgressProvider> )}
); </AppProgressProvider>
} );
) }
); );
export default AppLayout; export default AppLayout;

View file

@ -1,9 +1,4 @@
import { import { makeStyles } from "@material-ui/core/styles";
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import Typography from "@material-ui/core/Typography"; import Typography from "@material-ui/core/Typography";
import classNames from "classnames"; import classNames from "classnames";
import React from "react"; import React from "react";
@ -24,92 +19,41 @@ import { orderDraftListUrl, orderListUrl } from "../../orders/urls";
import MenuNested from "./MenuNested"; import MenuNested from "./MenuNested";
import { IMenuItem } from "./menuStructure"; import { IMenuItem } from "./menuStructure";
const styles = (theme: Theme) => const useStyles = makeStyles(theme => ({
createStyles({ menuIcon: {
menuIcon: { "& svg": {
"& svg": { height: 32,
height: 32, width: 32
width: 32
},
display: "inline-block",
position: "relative",
top: 8
}, },
menuIconDark: { display: "inline-block",
"& path": { position: "relative",
fill: theme.palette.common.white top: 8
} },
menuIconDark: {
"& path": {
fill: theme.palette.common.white
}
},
menuIconSmall: {
left: -5
},
menuIsActive: {
boxShadow: "0px 0px 12px 1px rgba(0,0,0,0.2)"
},
menuItemHover: {
"& p": {
fontSize: 14,
transition: "color 0.5s ease, opacity 0.3s ease-out"
}, },
menuIconSmall: { "& path": {
left: -5 transition: "fill 0.5s ease"
}, },
menuIsActive: { "&:hover": {
boxShadow: "0px 0px 12px 1px rgba(0,0,0,0.2)"
},
menuItemHover: {
"& p": { "& p": {
fontSize: 14,
transition: "color 0.5s ease, opacity 0.3s ease-out"
},
"& path": {
transition: "fill 0.5s ease"
},
"&:hover": {
"& p": {
color: theme.palette.primary.main
},
"& path": {
fill: theme.palette.primary.main
},
"&:before": {
borderLeft: `solid 2px ${theme.palette.primary.main}`,
content: "''",
height: 33,
left: -20,
position: "absolute",
top: 8
},
color: theme.palette.primary.main
},
cursor: "pointer",
position: "relative"
},
menuList: {
display: "flex",
flexDirection: "column",
height: "100%",
marginLeft: theme.spacing.unit * 4,
marginTop: theme.spacing.unit * 2,
paddingBottom: theme.spacing.unit * 3
},
menuListItem: {
alignItems: "center",
display: "block",
marginBottom: theme.spacing.unit * 5,
paddingLeft: 0,
textDecoration: "none",
transition: theme.transitions.duration.standard + "ms"
},
menuListItemActive: {
"& $menuListItemText": {
color: theme.palette.primary.main color: theme.palette.primary.main
}, },
"& path": { "& path": {
color: theme.palette.primary.main,
fill: theme.palette.primary.main fill: theme.palette.primary.main
}
},
menuListItemOpen: {
"&:after": {
borderBottom: `10px solid transparent`,
borderLeft: `10px solid ${theme.palette.background.paper}`,
borderTop: `10px solid transparent`,
content: "''",
height: 0,
position: "absolute",
right: -35,
top: 15,
width: 0
}, },
"&:before": { "&:before": {
borderLeft: `solid 2px ${theme.palette.primary.main}`, borderLeft: `solid 2px ${theme.palette.primary.main}`,
@ -119,47 +63,97 @@ const styles = (theme: Theme) =>
position: "absolute", position: "absolute",
top: 8 top: 8
}, },
position: "relative" color: theme.palette.primary.main
}, },
menuListItemText: { cursor: "pointer",
"&:hover": { position: "relative"
color: theme.palette.primary.main },
}, menuList: {
bottom: 0, display: "flex",
cursor: "pointer", flexDirection: "column",
fontSize: "1rem", height: "100%",
fontWeight: 500, marginLeft: theme.spacing(4),
left: 30, marginTop: theme.spacing(2),
opacity: 1, paddingBottom: theme.spacing(3)
paddingLeft: 16, },
position: "absolute", menuListItem: {
textTransform: "uppercase", alignItems: "center",
transition: "opacity 0.5s ease" display: "block",
marginBottom: theme.spacing(5),
paddingLeft: 0,
textDecoration: "none",
transition: theme.transitions.duration.standard + "ms"
},
menuListItemActive: {
"& $menuListItemText": {
color: theme.palette.primary.main
}, },
menuListItemTextHide: { "& path": {
bottom: 0, color: theme.palette.primary.main,
left: 30, fill: theme.palette.primary.main
opacity: 0,
position: "absolute"
},
subMenu: {
padding: "0 15px"
},
subMenuDrawer: {
background: "#000",
cursor: "pointer",
height: "100vh",
left: 0,
opacity: 0.2,
position: "absolute",
top: 0,
width: 0,
zIndex: -2
},
subMenuDrawerOpen: {
width: `100vw`
} }
}); },
menuListItemOpen: {
"&:after": {
borderBottom: `10px solid transparent`,
borderLeft: `10px solid ${theme.palette.background.paper}`,
borderTop: `10px solid transparent`,
content: "''",
height: 0,
position: "absolute",
right: -35,
top: 15,
width: 0
},
"&:before": {
borderLeft: `solid 2px ${theme.palette.primary.main}`,
content: "''",
height: 33,
left: -20,
position: "absolute",
top: 8
},
position: "relative"
},
menuListItemText: {
"&:hover": {
color: theme.palette.primary.main
},
bottom: 0,
cursor: "pointer",
fontSize: "1rem",
fontWeight: 500,
left: 30,
opacity: 1,
paddingLeft: 16,
position: "absolute",
textTransform: "uppercase",
transition: "opacity 0.5s ease"
},
menuListItemTextHide: {
bottom: 0,
left: 30,
opacity: 0,
position: "absolute"
},
subMenu: {
padding: "0 15px"
},
subMenuDrawer: {
background: "#000",
cursor: "pointer",
height: "100vh",
left: 0,
opacity: 0.2,
position: "absolute",
top: 0,
width: 0,
zIndex: -2
},
subMenuDrawerOpen: {
width: `100vw`
}
}));
interface MenuListProps { interface MenuListProps {
className?: string; className?: string;
@ -176,9 +170,8 @@ export interface IActiveSubMenu {
label: string | null; label: string | null;
} }
const MenuList = withStyles(styles, { name: "MenuList" })( const MenuList: React.FC<MenuListProps> = props => {
({ const {
classes,
className, className,
menuItems, menuItems,
isMenuSmall, isMenuSmall,
@ -186,134 +179,89 @@ const MenuList = withStyles(styles, { name: "MenuList" })(
user, user,
renderConfigure, renderConfigure,
onMenuItemClick onMenuItemClick
}: MenuListProps & WithStyles<typeof styles>) => { } = props;
const { isDark } = useTheme();
const [activeSubMenu, setActiveSubMenu] = React.useState<IActiveSubMenu>({ const classes = useStyles(props);
const { isDark } = useTheme();
const [activeSubMenu, setActiveSubMenu] = React.useState<IActiveSubMenu>({
isActive: false,
label: null
});
const intl = useIntl();
const configutationMenu = createConfigurationMenu(intl).map(menu => {
menu.menuItems.map(item =>
user.permissions.map(perm => perm.code).includes(item.permission)
);
});
const handleSubMenu = itemLabel => {
setActiveSubMenu({
isActive:
itemLabel === activeSubMenu.label ? !activeSubMenu.isActive : true,
label: itemLabel
});
};
const closeSubMenu = (menuItemUrl, event) => {
setActiveSubMenu({
isActive: false, isActive: false,
label: null label: null
}); });
const intl = useIntl(); if (menuItemUrl && event) {
onMenuItemClick(menuItemUrl, event);
event.stopPropagation();
event.preventDefault();
}
};
const configutationMenu = createConfigurationMenu(intl).map(menu => { return (
menu.menuItems.map(item => <div
user.permissions.map(perm => perm.code).includes(item.permission) className={classNames(className, {
); [classes.menuIsActive]: activeSubMenu.isActive
}); })}
>
{/* FIXME: this .split("?")[0] looks gross */}
{menuItems.map(menuItem => {
const isActive = (menuItem: IMenuItem) =>
location.split("?")[0] === orderDraftListUrl().split("?")[0] &&
menuItem.url.split("?")[0] === orderListUrl().split("?")[0]
? false
: !!matchPath(location.split("?")[0], {
exact: menuItem.url.split("?")[0] === "/",
path: menuItem.url.split("?")[0]
});
const handleSubMenu = itemLabel => { if (
setActiveSubMenu({ menuItem.permission &&
isActive: !user.permissions.map(perm => perm.code).includes(menuItem.permission)
itemLabel === activeSubMenu.label ? !activeSubMenu.isActive : true, ) {
label: itemLabel return null;
}); }
};
const closeSubMenu = (menuItemUrl, event) => { if (!menuItem.url) {
setActiveSubMenu({ const isAnyChildActive = menuItem.children.reduce(
isActive: false, (acc, child) => acc || isActive(child),
label: null false
}); );
if (menuItemUrl && event) {
onMenuItemClick(menuItemUrl, event);
event.stopPropagation();
event.preventDefault();
}
};
return (
<div
className={classNames(className, {
[classes.menuIsActive]: activeSubMenu.isActive
})}
>
{/* FIXME: this .split("?")[0] looks gross */}
{menuItems.map(menuItem => {
const isActive = (menuItem: IMenuItem) =>
location.split("?")[0] === orderDraftListUrl().split("?")[0] &&
menuItem.url.split("?")[0] === orderListUrl().split("?")[0]
? false
: !!matchPath(location.split("?")[0], {
exact: menuItem.url.split("?")[0] === "/",
path: menuItem.url.split("?")[0]
});
if (
menuItem.permission &&
!user.permissions
.map(perm => perm.code)
.includes(menuItem.permission)
) {
return null;
}
if (!menuItem.url) {
const isAnyChildActive = menuItem.children.reduce(
(acc, child) => acc || isActive(child),
false
);
return (
<div
className={classNames(classes.menuListItem, {
[classes.menuListItemActive]: isAnyChildActive
})}
key={menuItem.label}
>
<div
className={classNames(classes.menuItemHover, {
[classes.menuListItemOpen]:
menuItem.ariaLabel === activeSubMenu.label &&
activeSubMenu.isActive
})}
data-tc={menuItem.label}
onClick={() => handleSubMenu(menuItem.ariaLabel)}
>
<SVG
className={classNames(classes.menuIcon, {
[classes.menuIconDark]: isDark,
[classes.menuIconSmall]: !isMenuSmall
})}
src={menuItem.icon}
/>
<Typography
aria-label={menuItem.ariaLabel}
className={classNames(classes.menuListItemText, {
[classes.menuListItemTextHide]: !isMenuSmall
})}
>
{menuItem.label}
</Typography>
</div>
<MenuNested
activeItem={activeSubMenu}
closeSubMenu={setActiveSubMenu}
menuItem={menuItem}
onMenuItemClick={onMenuItemClick}
handleSubMenu={handleSubMenu}
title={menuItem.label}
icon={menuItem.icon}
ariaLabel={menuItem.ariaLabel}
/>
<div
onClick={event => closeSubMenu(null, event)}
className={classNames(classes.subMenuDrawer, {
[classes.subMenuDrawerOpen]: activeSubMenu.isActive
})}
/>
</div>
);
}
return ( return (
<a <div
className={classNames(classes.menuListItem, { className={classNames(classes.menuListItem, {
[classes.menuListItemActive]: isActive(menuItem) [classes.menuListItemActive]: isAnyChildActive
})} })}
href={createHref(menuItem.url)}
onClick={event => closeSubMenu(menuItem.url, event)}
key={menuItem.label} key={menuItem.label}
> >
<div className={classes.menuItemHover}> <div
className={classNames(classes.menuItemHover, {
[classes.menuListItemOpen]:
menuItem.ariaLabel === activeSubMenu.label &&
activeSubMenu.isActive
})}
data-tc={menuItem.label}
onClick={() => handleSubMenu(menuItem.ariaLabel)}
>
<SVG <SVG
className={classNames(classes.menuIcon, { className={classNames(classes.menuIcon, {
[classes.menuIconDark]: isDark, [classes.menuIconDark]: isDark,
@ -330,14 +278,34 @@ const MenuList = withStyles(styles, { name: "MenuList" })(
{menuItem.label} {menuItem.label}
</Typography> </Typography>
</div> </div>
</a> <MenuNested
activeItem={activeSubMenu}
closeSubMenu={setActiveSubMenu}
menuItem={menuItem}
onMenuItemClick={onMenuItemClick}
handleSubMenu={handleSubMenu}
title={menuItem.label}
icon={menuItem.icon}
ariaLabel={menuItem.ariaLabel}
/>
<div
onClick={event => closeSubMenu(null, event)}
className={classNames(classes.subMenuDrawer, {
[classes.subMenuDrawerOpen]: activeSubMenu.isActive
})}
/>
</div>
); );
})} }
{renderConfigure && configutationMenu.length > 0 && (
return (
<a <a
className={classes.menuListItem} className={classNames(classes.menuListItem, {
href={createHref(configurationMenuUrl)} [classes.menuListItemActive]: isActive(menuItem)
onClick={event => closeSubMenu(configurationMenuUrl, event)} })}
href={createHref(menuItem.url)}
onClick={event => closeSubMenu(menuItem.url, event)}
key={menuItem.label}
> >
<div className={classes.menuItemHover}> <div className={classes.menuItemHover}>
<SVG <SVG
@ -345,21 +313,48 @@ const MenuList = withStyles(styles, { name: "MenuList" })(
[classes.menuIconDark]: isDark, [classes.menuIconDark]: isDark,
[classes.menuIconSmall]: !isMenuSmall [classes.menuIconSmall]: !isMenuSmall
})} })}
src={configureIcon} src={menuItem.icon}
/> />
<Typography <Typography
aria-label="configuration" aria-label={menuItem.ariaLabel}
className={classNames(classes.menuListItemText, { className={classNames(classes.menuListItemText, {
[classes.menuListItemTextHide]: !isMenuSmall [classes.menuListItemTextHide]: !isMenuSmall
})} })}
> >
<FormattedMessage {...sectionNames.configuration} /> {menuItem.label}
</Typography> </Typography>
</div> </div>
</a> </a>
)} );
</div> })}
); {renderConfigure && configutationMenu.length > 0 && (
} <a
); className={classes.menuListItem}
href={createHref(configurationMenuUrl)}
onClick={event => closeSubMenu(configurationMenuUrl, event)}
>
<div className={classes.menuItemHover}>
<SVG
className={classNames(classes.menuIcon, {
[classes.menuIconDark]: isDark,
[classes.menuIconSmall]: !isMenuSmall
})}
src={configureIcon}
/>
<Typography
aria-label="configuration"
className={classNames(classes.menuListItemText, {
[classes.menuListItemTextHide]: !isMenuSmall
})}
>
<FormattedMessage {...sectionNames.configuration} />
</Typography>
</div>
</a>
)}
</div>
);
};
MenuList.displayName = "MenuList";
export default MenuList; export default MenuList;

View file

@ -1,10 +1,5 @@
import Hidden from "@material-ui/core/Hidden"; import Hidden from "@material-ui/core/Hidden";
import { import { makeStyles } from "@material-ui/core/styles";
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import Typography from "@material-ui/core/Typography"; import Typography from "@material-ui/core/Typography";
import classNames from "classnames"; import classNames from "classnames";
import React from "react"; import React from "react";
@ -17,89 +12,88 @@ import { drawerWidthExpanded } from "./consts";
import { IActiveSubMenu } from "./MenuList"; import { IActiveSubMenu } from "./MenuList";
import { IMenuItem } from "./menuStructure"; import { IMenuItem } from "./menuStructure";
const styles = (theme: Theme) => const useStyles = makeStyles(theme => ({
createStyles({ menuListNested: {
menuListNested: { background: theme.palette.background.paper,
background: theme.palette.background.paper, height: "100vh",
height: "100vh", position: "absolute",
position: "absolute", right: 0,
right: 0, top: 0,
top: 0, transition: `right ${theme.transitions.duration.shorter}ms ease`,
transition: `right ${theme.transitions.duration.shorter}ms ease`, width: 300,
width: 300, zIndex: -1
zIndex: -1 },
menuListNestedClose: {
"& svg": {
fill: theme.palette.primary.main,
left: 7,
position: "relative",
top: -2
}, },
menuListNestedClose: { border: `solid 1px #EAEAEA`,
"& svg": { borderRadius: "100%",
fill: theme.palette.primary.main, cursor: "pointer",
left: 7, height: 32,
position: "relative", position: "absolute",
top: -2 right: 32,
}, top: 35,
border: `solid 1px #EAEAEA`, transform: "rotate(180deg)",
borderRadius: "100%", width: 32
cursor: "pointer", },
height: 32, menuListNestedCloseDark: {
position: "absolute", border: `solid 1px #252728`
right: 32, },
top: 35, menuListNestedHide: {
transform: "rotate(180deg)", opacity: 0
width: 32 },
menuListNestedIcon: {
"& path": {
fill: "initial"
}, },
menuListNestedCloseDark: { "& svg": { height: 32, position: "relative", top: 7, width: 32 }
border: `solid 1px #252728` },
}, menuListNestedIconDark: {
menuListNestedHide: { "& path": {
opacity: 0 fill: theme.palette.common.white
}, }
menuListNestedIcon: { },
"& path": { menuListNestedItem: {
fill: "initial" "&:hover": {
}, "& p": {
"& svg": { height: 32, position: "relative", top: 7, width: 32 } color: theme.palette.primary.main
},
menuListNestedIconDark: {
"& path": {
fill: theme.palette.common.white
} }
}, },
menuListNestedItem: { display: "block",
"&:hover": { marginBottom: theme.spacing(2),
"& p": { padding: "0px 30px",
color: theme.palette.primary.main textDecoration: "none"
} },
}, menuListNestedOpen: {
display: "block", [theme.breakpoints.down("sm")]: {
marginBottom: theme.spacing.unit * 2, right: 0,
padding: "0px 30px", width: drawerWidthExpanded,
textDecoration: "none" zIndex: 2
}, },
menuListNestedOpen: { right: -300,
[theme.breakpoints.down("sm")]: { zIndex: -1
right: 0, },
width: drawerWidthExpanded, subHeader: {
zIndex: 2 borderBottom: "solid 1px #EAEAEA",
}, margin: "30px",
right: -300, marginBottom: 39,
zIndex: -1 paddingBottom: 22
},
subHeaderDark: {
borderBottom: "solid 1px #252728"
},
subHeaderTitle: {
[theme.breakpoints.up("md")]: {
paddingLeft: 0
}, },
subHeader: { display: "inline",
borderBottom: "solid 1px #EAEAEA", paddingLeft: 10
margin: "30px", }
marginBottom: 39, }));
paddingBottom: 22
},
subHeaderDark: {
borderBottom: "solid 1px #252728"
},
subHeaderTitle: {
[theme.breakpoints.up("md")]: {
paddingLeft: 0
},
display: "inline",
paddingLeft: 10
}
});
export interface MenuNestedProps { export interface MenuNestedProps {
activeItem: IActiveSubMenu; activeItem: IActiveSubMenu;
@ -112,86 +106,85 @@ export interface MenuNestedProps {
onMenuItemClick: (url: string, event: React.MouseEvent<any>) => void; onMenuItemClick: (url: string, event: React.MouseEvent<any>) => void;
} }
const MenuNested = withStyles(styles, { name: "MenuNested" })( const MenuNested: React.FC<MenuNestedProps> = props => {
({ const {
activeItem, activeItem,
ariaLabel, ariaLabel,
classes,
closeSubMenu, closeSubMenu,
icon, icon,
menuItem, menuItem,
onMenuItemClick, onMenuItemClick,
title title
}: MenuNestedProps & WithStyles<typeof styles>) => { } = props;
const menuItems = menuItem.children; const classes = useStyles(props);
const { isDark } = useTheme();
const closeMenu = (menuItemUrl, event) => { const menuItems = menuItem.children;
onMenuItemClick(menuItemUrl, event); const { isDark } = useTheme();
closeSubMenu({ const closeMenu = (menuItemUrl, event) => {
isActive: false, onMenuItemClick(menuItemUrl, event);
label: null closeSubMenu({
}); isActive: false,
event.stopPropagation(); label: null
event.preventDefault(); });
}; event.stopPropagation();
return ( event.preventDefault();
<> };
<div return (
className={classNames(classes.menuListNested, { <>
[classes.menuListNestedOpen]: <div
activeItem.label === ariaLabel && activeItem.isActive className={classNames(classes.menuListNested, {
[classes.menuListNestedOpen]:
activeItem.label === ariaLabel && activeItem.isActive
})}
>
<Typography
className={classNames(classes.subHeader, {
[classes.subHeaderDark]: isDark
})} })}
variant="h5"
> >
<Typography <Hidden mdUp>
className={classNames(classes.subHeader, { <SVG
[classes.subHeaderDark]: isDark className={classNames(classes.menuListNestedIcon, {
})} [classes.menuListNestedIconDark]: isDark
variant="h5" })}
src={icon}
/>
</Hidden>
<div className={classes.subHeaderTitle}>{title}</div>
<Hidden mdUp>
<div
className={classNames(classes.menuListNestedClose, {
[classes.menuListNestedCloseDark]: isDark
})}
data-tc={ariaLabel}
onClick={() =>
closeSubMenu({
isActive: false,
label: null
})
}
>
<SVG src={menuArrowIcon} />
</div>
</Hidden>
</Typography>
{menuItems.map(item => (
<a
className={classNames(classes.menuListNestedItem)}
href={createHref(item.url)}
data-tc={ariaLabel}
onClick={event => closeMenu(item.url, event)}
key={item.label}
> >
<Hidden mdUp> <Typography aria-label={item.ariaLabel}>{item.label}</Typography>
<SVG </a>
className={classNames(classes.menuListNestedIcon, { ))}
[classes.menuListNestedIconDark]: isDark </div>
})} </>
src={icon} );
/> };
</Hidden>
<div className={classes.subHeaderTitle}>{title}</div> MenuNested.displayName = "MenuNested";
<Hidden mdUp>
<div
className={classNames(classes.menuListNestedClose, {
[classes.menuListNestedCloseDark]: isDark
})}
data-tc={ariaLabel}
onClick={() =>
closeSubMenu({
isActive: false,
label: null
})
}
>
<SVG src={menuArrowIcon} />
</div>
</Hidden>
</Typography>
{menuItems.map(item => {
return (
<a
className={classNames(classes.menuListNestedItem)}
href={createHref(item.url)}
data-tc={ariaLabel}
onClick={event => closeMenu(item.url, event)}
key={item.label}
>
<Typography aria-label={item.ariaLabel}>
{item.label}
</Typography>
</a>
);
})}
</div>
</>
);
}
);
export default MenuNested; export default MenuNested;

View file

@ -1,16 +1,11 @@
import Drawer from "@material-ui/core/Drawer"; import Drawer from "@material-ui/core/Drawer";
import Hidden from "@material-ui/core/Hidden"; import Hidden from "@material-ui/core/Hidden";
import { import { makeStyles } from "@material-ui/core/styles";
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import React from "react"; import React from "react";
import { drawerWidth, drawerWidthExpanded } from "./consts"; import { drawerWidth, drawerWidthExpanded } from "./consts";
const styles = (theme: Theme) => const useStyles = makeStyles(
createStyles({ theme => ({
drawerDesktop: { drawerDesktop: {
backgroundColor: theme.palette.background.paper, backgroundColor: theme.palette.background.paper,
border: "none", border: "none",
@ -29,17 +24,23 @@ const styles = (theme: Theme) =>
drawerMobile: { drawerMobile: {
width: drawerWidthExpanded width: drawerWidthExpanded
} }
}); }),
{ name: "ResponsiveDrawer" }
);
interface ResponsiveDrawerProps extends WithStyles<typeof styles> { interface ResponsiveDrawerProps {
children?: React.ReactNode; children?: React.ReactNode;
open: boolean; open: boolean;
small: boolean; small: boolean;
onClose?(); onClose?();
} }
const ResponsiveDrawer = withStyles(styles, { name: "ResponsiveDrawer" })( const ResponsiveDrawer: React.FC<ResponsiveDrawerProps> = props => {
({ children, classes, onClose, open, small }: ResponsiveDrawerProps) => ( const { children, onClose, open, small } = props;
const classes = useStyles(props);
return (
<> <>
<Hidden smDown> <Hidden smDown>
<Drawer <Drawer
@ -63,6 +64,6 @@ const ResponsiveDrawer = withStyles(styles, { name: "ResponsiveDrawer" })(
</Drawer> </Drawer>
</Hidden> </Hidden>
</> </>
) );
); };
export default ResponsiveDrawer; export default ResponsiveDrawer;

View file

@ -1,43 +1,51 @@
import { Theme, withStyles } from "@material-ui/core/styles"; import { makeStyles } from "@material-ui/core/styles";
import Switch, { SwitchProps } from "@material-ui/core/Switch"; import Switch, { SwitchProps } from "@material-ui/core/Switch";
import React from "react"; import React from "react";
import MoonIcon from "../../icons/Moon"; import MoonIcon from "../../icons/Moon";
import SunIcon from "../../icons/Sun"; import SunIcon from "../../icons/Sun";
const switchStyles = (theme: Theme) => ({ const useStyles = makeStyles(
bar: { theme => ({
"$colorPrimary$checked + &": { checked: {
backgroundColor: theme.palette.background.paper "& svg": {
background: theme.palette.primary.main,
color: theme.palette.background.paper
}
}, },
background: theme.palette.background.paper colorPrimary: {},
}, root: {
checked: { "& svg": {
"& svg": { background: theme.palette.primary.main,
background: theme.palette.primary.main, borderRadius: "100%",
color: theme.palette.background.paper height: 20,
width: 20
}
},
track: {
"$colorPrimary$checked + &": {
backgroundColor: theme.palette.background.paper
},
background: theme.palette.background.paper
} }
}, }),
colorPrimary: {}, {
root: { name: "ThemeSwitch"
"& svg": {
background: theme.palette.primary.main,
borderRadius: "100%",
height: 20,
width: 20
},
width: 58
} }
}); );
const ThemeSwitch = withStyles(switchStyles, { const ThemeSwitch: React.FC<SwitchProps> = props => {
name: "ThemeSwitch" const classes = useStyles(props);
})((props: SwitchProps) => (
<Switch return (
{...props} <Switch
color="primary" {...props}
icon={<SunIcon />} classes={classes}
checkedIcon={<MoonIcon />} color="primary"
/> icon={<SunIcon />}
)); checkedIcon={<MoonIcon />}
/>
);
};
ThemeSwitch.displayName = "ThemeSwitch"; ThemeSwitch.displayName = "ThemeSwitch";
export default ThemeSwitch; export default ThemeSwitch;

View file

@ -1,2 +1,2 @@
export { default } from './AppLayout'; export { default } from "./AppLayout";
export * from './AppLayout'; export * from "./AppLayout";

View file

@ -4,7 +4,7 @@ import Dialog from "@material-ui/core/Dialog";
import DialogActions from "@material-ui/core/DialogActions"; import DialogActions from "@material-ui/core/DialogActions";
import DialogContent from "@material-ui/core/DialogContent"; import DialogContent from "@material-ui/core/DialogContent";
import DialogTitle from "@material-ui/core/DialogTitle"; import DialogTitle from "@material-ui/core/DialogTitle";
import { createStyles, withStyles, WithStyles } from "@material-ui/core/styles"; import { makeStyles } from "@material-ui/core/styles";
import Table from "@material-ui/core/Table"; import Table from "@material-ui/core/Table";
import TableBody from "@material-ui/core/TableBody"; import TableBody from "@material-ui/core/TableBody";
import TableCell from "@material-ui/core/TableCell"; import TableCell from "@material-ui/core/TableCell";
@ -27,7 +27,7 @@ export interface FormData {
query: string; query: string;
} }
const styles = createStyles({ const useStyles = makeStyles({
avatar: { avatar: {
"&:first-child": { "&:first-child": {
paddingLeft: 0 paddingLeft: 0
@ -44,7 +44,7 @@ const styles = createStyles({
} }
}); });
interface AssignCategoriesDialogProps extends WithStyles<typeof styles> { interface AssignCategoriesDialogProps {
categories: SearchCategories_search_edges_node[]; categories: SearchCategories_search_edges_node[];
confirmButtonState: ConfirmButtonTransitionState; confirmButtonState: ConfirmButtonTransitionState;
open: boolean; open: boolean;
@ -71,11 +71,8 @@ function handleCategoryAssign(
} }
} }
const AssignCategoriesDialog = withStyles(styles, { const AssignCategoriesDialog: React.FC<AssignCategoriesDialogProps> = props => {
name: "AssignCategoriesDialog" const {
})(
({
classes,
confirmButtonState, confirmButtonState,
open, open,
loading, loading,
@ -83,102 +80,103 @@ const AssignCategoriesDialog = withStyles(styles, {
onClose, onClose,
onFetch, onFetch,
onSubmit onSubmit
}: AssignCategoriesDialogProps) => { } = props;
const intl = useIntl(); const classes = useStyles(props);
const [query, onQueryChange] = useSearchQuery(onFetch);
const [selectedCategories, setSelectedCategories] = React.useState<
SearchCategories_search_edges_node[]
>([]);
const handleSubmit = () => onSubmit(selectedCategories); const intl = useIntl();
const [query, onQueryChange] = useSearchQuery(onFetch);
const [selectedCategories, setSelectedCategories] = React.useState<
SearchCategories_search_edges_node[]
>([]);
return ( const handleSubmit = () => onSubmit(selectedCategories);
<Dialog
open={open} return (
onClose={onClose} <Dialog
classes={{ paper: classes.overflow }} open={open}
fullWidth onClose={onClose}
maxWidth="sm" classes={{ paper: classes.overflow }}
> fullWidth
<DialogTitle> maxWidth="sm"
>
<DialogTitle>
<FormattedMessage
defaultMessage="Assign Categories"
description="dialog header"
/>
</DialogTitle>
<DialogContent className={classes.overflow}>
<TextField
name="query"
value={query}
onChange={onQueryChange}
label={intl.formatMessage({
defaultMessage: "Search Categories"
})}
placeholder={intl.formatMessage({
defaultMessage: "Search by category name, etc..."
})}
fullWidth
InputProps={{
autoComplete: "off",
endAdornment: loading && <CircularProgress size={16} />
}}
/>
<FormSpacer />
<Table>
<TableBody>
{categories &&
categories.map(category => {
const isSelected = !!selectedCategories.find(
selectedCategories => selectedCategories.id === category.id
);
return (
<TableRow key={category.id}>
<TableCell
padding="checkbox"
className={classes.checkboxCell}
>
<Checkbox
checked={isSelected}
onChange={() =>
handleCategoryAssign(
category,
isSelected,
selectedCategories,
setSelectedCategories
)
}
/>
</TableCell>
<TableCell className={classes.wideCell}>
{category.name}
</TableCell>
</TableRow>
);
})}
</TableBody>
</Table>
</DialogContent>
<DialogActions>
<Button onClick={onClose}>
<FormattedMessage {...buttonMessages.back} />
</Button>
<ConfirmButton
transitionState={confirmButtonState}
color="primary"
variant="contained"
type="submit"
onClick={handleSubmit}
>
<FormattedMessage <FormattedMessage
defaultMessage="Assign Categories" defaultMessage="Assign categories"
description="dialog header" description="button"
/> />
</DialogTitle> </ConfirmButton>
<DialogContent className={classes.overflow}> </DialogActions>
<TextField </Dialog>
name="query" );
value={query} };
onChange={onQueryChange}
label={intl.formatMessage({
defaultMessage: "Search Categories"
})}
placeholder={intl.formatMessage({
defaultMessage: "Search by category name, etc..."
})}
fullWidth
InputProps={{
autoComplete: "off",
endAdornment: loading && <CircularProgress size={16} />
}}
/>
<FormSpacer />
<Table>
<TableBody>
{categories &&
categories.map(category => {
const isSelected = !!selectedCategories.find(
selectedCategories => selectedCategories.id === category.id
);
return (
<TableRow key={category.id}>
<TableCell
padding="checkbox"
className={classes.checkboxCell}
>
<Checkbox
checked={isSelected}
onChange={() =>
handleCategoryAssign(
category,
isSelected,
selectedCategories,
setSelectedCategories
)
}
/>
</TableCell>
<TableCell className={classes.wideCell}>
{category.name}
</TableCell>
</TableRow>
);
})}
</TableBody>
</Table>
</DialogContent>
<DialogActions>
<Button onClick={onClose}>
<FormattedMessage {...buttonMessages.back} />
</Button>
<ConfirmButton
transitionState={confirmButtonState}
color="primary"
variant="contained"
type="submit"
onClick={handleSubmit}
>
<FormattedMessage
defaultMessage="Assign categories"
description="button"
/>
</ConfirmButton>
</DialogActions>
</Dialog>
);
}
);
AssignCategoriesDialog.displayName = "AssignCategoriesDialog"; AssignCategoriesDialog.displayName = "AssignCategoriesDialog";
export default AssignCategoriesDialog; export default AssignCategoriesDialog;

View file

@ -4,7 +4,7 @@ import Dialog from "@material-ui/core/Dialog";
import DialogActions from "@material-ui/core/DialogActions"; import DialogActions from "@material-ui/core/DialogActions";
import DialogContent from "@material-ui/core/DialogContent"; import DialogContent from "@material-ui/core/DialogContent";
import DialogTitle from "@material-ui/core/DialogTitle"; import DialogTitle from "@material-ui/core/DialogTitle";
import { createStyles, withStyles, WithStyles } from "@material-ui/core/styles"; import { makeStyles } from "@material-ui/core/styles";
import Table from "@material-ui/core/Table"; import Table from "@material-ui/core/Table";
import TableBody from "@material-ui/core/TableBody"; import TableBody from "@material-ui/core/TableBody";
import TableCell from "@material-ui/core/TableCell"; import TableCell from "@material-ui/core/TableCell";
@ -27,7 +27,7 @@ export interface FormData {
query: string; query: string;
} }
const styles = createStyles({ const useStyles = makeStyles({
avatar: { avatar: {
"&:first-child": { "&:first-child": {
paddingLeft: 0 paddingLeft: 0
@ -44,7 +44,7 @@ const styles = createStyles({
} }
}); });
interface AssignCollectionDialogProps extends WithStyles<typeof styles> { interface AssignCollectionDialogProps {
collections: SearchCollections_search_edges_node[]; collections: SearchCollections_search_edges_node[];
confirmButtonState: ConfirmButtonTransitionState; confirmButtonState: ConfirmButtonTransitionState;
open: boolean; open: boolean;
@ -71,11 +71,8 @@ function handleCollectionAssign(
} }
} }
const AssignCollectionDialog = withStyles(styles, { const AssignCollectionDialog: React.FC<AssignCollectionDialogProps> = props => {
name: "AssignCollectionDialog" const {
})(
({
classes,
confirmButtonState, confirmButtonState,
open, open,
loading, loading,
@ -83,103 +80,103 @@ const AssignCollectionDialog = withStyles(styles, {
onClose, onClose,
onFetch, onFetch,
onSubmit onSubmit
}: AssignCollectionDialogProps) => { } = props;
const intl = useIntl(); const classes = useStyles(props);
const [query, onQueryChange] = useSearchQuery(onFetch);
const [selectedCollections, setSelectedCollections] = React.useState<
SearchCollections_search_edges_node[]
>([]);
const handleSubmit = () => onSubmit(selectedCollections); const intl = useIntl();
const [query, onQueryChange] = useSearchQuery(onFetch);
const [selectedCollections, setSelectedCollections] = React.useState<
SearchCollections_search_edges_node[]
>([]);
return ( const handleSubmit = () => onSubmit(selectedCollections);
<Dialog
onClose={onClose} return (
open={open} <Dialog
classes={{ paper: classes.overflow }} onClose={onClose}
fullWidth open={open}
maxWidth="sm" classes={{ paper: classes.overflow }}
> fullWidth
<DialogTitle> maxWidth="sm"
>
<DialogTitle>
<FormattedMessage
defaultMessage="Assign Collection"
description="dialog header"
/>
</DialogTitle>
<DialogContent className={classes.overflow}>
<TextField
name="query"
value={query}
onChange={onQueryChange}
label={intl.formatMessage({
defaultMessage: "Search Collection"
})}
placeholder={intl.formatMessage({
defaultMessage: "Search by collection name, etc..."
})}
fullWidth
InputProps={{
autoComplete: "off",
endAdornment: loading && <CircularProgress size={16} />
}}
/>
<FormSpacer />
<Table>
<TableBody>
{collections &&
collections.map(collection => {
const isSelected = !!selectedCollections.find(
selectedCollection => selectedCollection.id === collection.id
);
return (
<TableRow key={collection.id}>
<TableCell
padding="checkbox"
className={classes.checkboxCell}
>
<Checkbox
checked={isSelected}
onChange={() =>
handleCollectionAssign(
collection,
isSelected,
selectedCollections,
setSelectedCollections
)
}
/>
</TableCell>
<TableCell className={classes.wideCell}>
{collection.name}
</TableCell>
</TableRow>
);
})}
</TableBody>
</Table>
</DialogContent>
<DialogActions>
<Button onClick={onClose}>
<FormattedMessage {...buttonMessages.back} />
</Button>
<ConfirmButton
transitionState={confirmButtonState}
color="primary"
variant="contained"
type="submit"
onClick={handleSubmit}
>
<FormattedMessage <FormattedMessage
defaultMessage="Assign Collection" defaultMessage="Assign collections"
description="dialog header" description="button"
/> />
</DialogTitle> </ConfirmButton>
<DialogContent className={classes.overflow}> </DialogActions>
<TextField </Dialog>
name="query" );
value={query} };
onChange={onQueryChange}
label={intl.formatMessage({
defaultMessage: "Search Collection"
})}
placeholder={intl.formatMessage({
defaultMessage: "Search by collection name, etc..."
})}
fullWidth
InputProps={{
autoComplete: "off",
endAdornment: loading && <CircularProgress size={16} />
}}
/>
<FormSpacer />
<Table>
<TableBody>
{collections &&
collections.map(collection => {
const isSelected = !!selectedCollections.find(
selectedCollection =>
selectedCollection.id === collection.id
);
return (
<TableRow key={collection.id}>
<TableCell
padding="checkbox"
className={classes.checkboxCell}
>
<Checkbox
checked={isSelected}
onChange={() =>
handleCollectionAssign(
collection,
isSelected,
selectedCollections,
setSelectedCollections
)
}
/>
</TableCell>
<TableCell className={classes.wideCell}>
{collection.name}
</TableCell>
</TableRow>
);
})}
</TableBody>
</Table>
</DialogContent>
<DialogActions>
<Button onClick={onClose}>
<FormattedMessage {...buttonMessages.back} />
</Button>
<ConfirmButton
transitionState={confirmButtonState}
color="primary"
variant="contained"
type="submit"
onClick={handleSubmit}
>
<FormattedMessage
defaultMessage="Assign collections"
description="button"
/>
</ConfirmButton>
</DialogActions>
</Dialog>
);
}
);
AssignCollectionDialog.displayName = "AssignCollectionDialog"; AssignCollectionDialog.displayName = "AssignCollectionDialog";
export default AssignCollectionDialog; export default AssignCollectionDialog;

View file

@ -4,7 +4,7 @@ import Dialog from "@material-ui/core/Dialog";
import DialogActions from "@material-ui/core/DialogActions"; import DialogActions from "@material-ui/core/DialogActions";
import DialogContent from "@material-ui/core/DialogContent"; import DialogContent from "@material-ui/core/DialogContent";
import DialogTitle from "@material-ui/core/DialogTitle"; import DialogTitle from "@material-ui/core/DialogTitle";
import { createStyles, withStyles, WithStyles } from "@material-ui/core/styles"; import { makeStyles } from "@material-ui/core/styles";
import Table from "@material-ui/core/Table"; import Table from "@material-ui/core/Table";
import TableBody from "@material-ui/core/TableBody"; import TableBody from "@material-ui/core/TableBody";
import TableCell from "@material-ui/core/TableCell"; import TableCell from "@material-ui/core/TableCell";
@ -29,7 +29,7 @@ export interface FormData {
query: string; query: string;
} }
const styles = createStyles({ const useStyles = makeStyles({
avatar: { avatar: {
"&:first-child": { "&:first-child": {
paddingLeft: 0 paddingLeft: 0
@ -77,11 +77,8 @@ function handleProductAssign(
} }
} }
const AssignProductDialog = withStyles(styles, { const AssignProductDialog: React.FC<AssignProductDialogProps> = props => {
name: "AssignProductDialog" const {
})(
({
classes,
confirmButtonState, confirmButtonState,
open, open,
loading, loading,
@ -89,109 +86,110 @@ const AssignProductDialog = withStyles(styles, {
onClose, onClose,
onFetch, onFetch,
onSubmit onSubmit
}: AssignProductDialogProps & WithStyles<typeof styles>) => { } = props;
const intl = useIntl(); const classes = useStyles(props);
const [query, onQueryChange] = useSearchQuery(onFetch);
const [selectedProducts, setSelectedProducts] = React.useState<
SearchProducts_search_edges_node[]
>([]);
const handleSubmit = () => onSubmit(selectedProducts); const intl = useIntl();
const [query, onQueryChange] = useSearchQuery(onFetch);
const [selectedProducts, setSelectedProducts] = React.useState<
SearchProducts_search_edges_node[]
>([]);
return ( const handleSubmit = () => onSubmit(selectedProducts);
<Dialog
onClose={onClose}
open={open}
classes={{ paper: classes.overflow }}
fullWidth
maxWidth="sm"
>
<DialogTitle>
<FormattedMessage
defaultMessage="Assign Product"
description="dialog header"
/>
</DialogTitle>
<DialogContent>
<TextField
name="query"
value={query}
onChange={onQueryChange}
label={intl.formatMessage({
defaultMessage: "Search Products"
})}
placeholder={intl.formatMessage({
defaultMessage:
"Search by product name, attribute, product type etc..."
})}
fullWidth
InputProps={{
autoComplete: "off",
endAdornment: loading && <CircularProgress size={16} />
}}
/>
<FormSpacer />
<div className={classes.scrollArea}>
<Table>
<TableBody>
{products &&
products.map(product => {
const isSelected = selectedProducts.some(
selectedProduct => selectedProduct.id === product.id
);
return ( return (
<TableRow key={product.id}> <Dialog
<TableCellAvatar onClose={onClose}
className={classes.avatar} open={open}
thumbnail={maybe(() => product.thumbnail.url)} classes={{ paper: classes.overflow }}
fullWidth
maxWidth="sm"
>
<DialogTitle>
<FormattedMessage
defaultMessage="Assign Product"
description="dialog header"
/>
</DialogTitle>
<DialogContent>
<TextField
name="query"
value={query}
onChange={onQueryChange}
label={intl.formatMessage({
defaultMessage: "Search Products"
})}
placeholder={intl.formatMessage({
defaultMessage:
"Search by product name, attribute, product type etc..."
})}
fullWidth
InputProps={{
autoComplete: "off",
endAdornment: loading && <CircularProgress size={16} />
}}
/>
<FormSpacer />
<div className={classes.scrollArea}>
<Table>
<TableBody>
{products &&
products.map(product => {
const isSelected = selectedProducts.some(
selectedProduct => selectedProduct.id === product.id
);
return (
<TableRow key={product.id}>
<TableCellAvatar
className={classes.avatar}
thumbnail={maybe(() => product.thumbnail.url)}
/>
<TableCell className={classes.wideCell}>
{product.name}
</TableCell>
<TableCell
padding="checkbox"
className={classes.checkboxCell}
>
<Checkbox
checked={isSelected}
onChange={() =>
handleProductAssign(
product,
isSelected,
selectedProducts,
setSelectedProducts
)
}
/> />
<TableCell className={classes.wideCell}> </TableCell>
{product.name} </TableRow>
</TableCell> );
<TableCell })}
padding="checkbox" </TableBody>
className={classes.checkboxCell} </Table>
> </div>
<Checkbox </DialogContent>
checked={isSelected} <DialogActions>
onChange={() => <Button onClick={onClose}>
handleProductAssign( <FormattedMessage {...buttonMessages.back} />
product, </Button>
isSelected, <ConfirmButton
selectedProducts, transitionState={confirmButtonState}
setSelectedProducts color="primary"
) variant="contained"
} type="submit"
/> onClick={handleSubmit}
</TableCell> >
</TableRow> <FormattedMessage
); defaultMessage="Assign products"
})} description="button"
</TableBody> />
</Table> </ConfirmButton>
</div> </DialogActions>
</DialogContent> </Dialog>
<DialogActions> );
<Button onClick={onClose}> };
<FormattedMessage {...buttonMessages.back} />
</Button>
<ConfirmButton
transitionState={confirmButtonState}
color="primary"
variant="contained"
type="submit"
onClick={handleSubmit}
>
<FormattedMessage
defaultMessage="Assign products"
description="button"
/>
</ConfirmButton>
</DialogActions>
</Dialog>
);
}
);
AssignProductDialog.displayName = "AssignProductDialog"; AssignProductDialog.displayName = "AssignProductDialog";
export default AssignProductDialog; export default AssignProductDialog;

View file

@ -1,12 +1,7 @@
import CircularProgress from "@material-ui/core/CircularProgress"; import CircularProgress from "@material-ui/core/CircularProgress";
import MenuItem from "@material-ui/core/MenuItem"; import MenuItem from "@material-ui/core/MenuItem";
import Paper from "@material-ui/core/Paper"; import Paper from "@material-ui/core/Paper";
import { import { makeStyles } from "@material-ui/core/styles";
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import TextField from "@material-ui/core/TextField"; import TextField from "@material-ui/core/TextField";
import ArrowBack from "@material-ui/icons/ArrowBack"; import ArrowBack from "@material-ui/icons/ArrowBack";
import Downshift from "downshift"; import Downshift from "downshift";
@ -43,31 +38,27 @@ const DebounceAutocomplete: React.ComponentType<
DebounceProps<string> DebounceProps<string>
> = Debounce; > = Debounce;
const styles = (theme: Theme) => const useStyles = makeStyles(theme => ({
createStyles({ container: {
container: { flexGrow: 1,
flexGrow: 1, position: "relative"
position: "relative" },
}, menuBack: {
menuBack: { marginLeft: -theme.spacing(0.5),
marginLeft: -theme.spacing.unit / 2, marginRight: theme.spacing(1)
marginRight: theme.spacing.unit },
}, paper: {
paper: { left: 0,
left: 0, marginTop: theme.spacing(),
marginTop: theme.spacing.unit, padding: theme.spacing(),
padding: theme.spacing.unit, position: "absolute",
position: "absolute", right: 0,
right: 0, zIndex: 2
zIndex: 2 },
}, root: {}
root: {} }));
}); const AutocompleteSelectMenu: React.FC<AutocompleteSelectMenuProps> = props => {
const AutocompleteSelectMenu = withStyles(styles, { const {
name: "AutocompleteSelectMenu"
})(
({
classes,
disabled, disabled,
displayValue, displayValue,
error, error,
@ -79,117 +70,118 @@ const AutocompleteSelectMenu = withStyles(styles, {
placeholder, placeholder,
onChange, onChange,
onInputChange onInputChange
}: AutocompleteSelectMenuProps & WithStyles<typeof styles>) => { } = props;
const [inputValue, setInputValue] = React.useState(displayValue || ""); const classes = useStyles(props);
const [menuPath, setMenuPath] = React.useState<number[]>([]);
const handleChange = (value: string) => const [inputValue, setInputValue] = React.useState(displayValue || "");
onChange({ const [menuPath, setMenuPath] = React.useState<number[]>([]);
target: {
name,
value
}
} as any);
// Validate if option values are duplicated const handleChange = (value: string) =>
React.useEffect(() => { onChange({
if (!validateMenuOptions(options)) { target: {
throw validationError; name,
value
} }
}, []); } as any);
// Navigate back to main menu after input field change // Validate if option values are duplicated
React.useEffect(() => setMenuPath([]), [options]); React.useEffect(() => {
if (!validateMenuOptions(options)) {
throw validationError;
}
}, []);
// Reset input value after displayValue change // Navigate back to main menu after input field change
React.useEffect(() => setInputValue(displayValue), [displayValue]); React.useEffect(() => setMenuPath([]), [options]);
return ( // Reset input value after displayValue change
<DebounceAutocomplete debounceFn={onInputChange}> React.useEffect(() => setInputValue(displayValue), [displayValue]);
{debounceFn => (
<Downshift return (
itemToString={item => (item ? item.label : "")} <DebounceAutocomplete debounceFn={onInputChange}>
onSelect={handleChange} {debounceFn => (
> <Downshift
{({ getItemProps, isOpen, openMenu, closeMenu, selectItem }) => { itemToString={item => (item ? item.label : "")}
return ( onSelect={handleChange}
<div className={classes.container}> >
<TextField {({ getItemProps, isOpen, openMenu, closeMenu, selectItem }) => {
InputProps={{ return (
endAdornment: loading && <CircularProgress size={16} />, <div className={classes.container}>
id: undefined, <TextField
onBlur: () => { InputProps={{
closeMenu(); endAdornment: loading && <CircularProgress size={16} />,
setMenuPath([]); id: undefined,
setInputValue(displayValue); onBlur: () => {
}, closeMenu();
onChange: event => { setMenuPath([]);
debounceFn(event.target.value); setInputValue(displayValue);
setInputValue(event.target.value); },
}, onChange: event => {
onFocus: () => openMenu(), debounceFn(event.target.value);
placeholder setInputValue(event.target.value);
}} },
disabled={disabled} onFocus: () => openMenu(),
error={error} placeholder
helperText={helperText} }}
label={label} disabled={disabled}
fullWidth={true} error={error}
value={inputValue} helperText={helperText}
/> label={label}
{isOpen && ( fullWidth={true}
<Paper className={classes.paper} square> value={inputValue}
{options.length ? ( />
<> {isOpen && (
{menuPath.length > 0 && ( <Paper className={classes.paper} square>
<MenuItem {options.length ? (
component="div" <>
{...getItemProps({ {menuPath.length > 0 && (
item: null <MenuItem
})} component="div"
onClick={() => {...getItemProps({
setMenuPath( item: null
menuPath.slice(0, menuPath.length - 2) })}
) onClick={() =>
} setMenuPath(
> menuPath.slice(0, menuPath.length - 2)
<ArrowBack className={classes.menuBack} /> )
<FormattedMessage {...buttonMessages.back} /> }
</MenuItem> >
)} <ArrowBack className={classes.menuBack} />
{(menuPath.length <FormattedMessage {...buttonMessages.back} />
? getMenuItemByPath(options, menuPath).children </MenuItem>
: options )}
).map((suggestion, index) => ( {(menuPath.length
<MenuItem ? getMenuItemByPath(options, menuPath).children
key={suggestion.value} : options
component="div" ).map((suggestion, index) => (
{...getItemProps({ item: suggestion })} <MenuItem
onClick={() => key={suggestion.value}
suggestion.value component="div"
? selectItem(suggestion.value) {...getItemProps({ item: suggestion })}
: setMenuPath([...menuPath, index]) onClick={() =>
} suggestion.value
> ? selectItem(suggestion.value)
{suggestion.label} : setMenuPath([...menuPath, index])
</MenuItem> }
))} >
</> {suggestion.label}
) : ( </MenuItem>
<MenuItem disabled component="div"> ))}
<FormattedMessage defaultMessage="No results" /> </>
</MenuItem> ) : (
)} <MenuItem disabled component="div">
</Paper> <FormattedMessage defaultMessage="No results" />
)} </MenuItem>
</div> )}
); </Paper>
}} )}
</Downshift> </div>
)} );
</DebounceAutocomplete> }}
); </Downshift>
} )}
); </DebounceAutocomplete>
);
};
AutocompleteSelectMenu.displayName = "AutocompleteSelectMenu"; AutocompleteSelectMenu.displayName = "AutocompleteSelectMenu";
export default AutocompleteSelectMenu; export default AutocompleteSelectMenu;

View file

@ -1,2 +1,2 @@
export { default } from './AutocompleteSelectMenu'; export { default } from "./AutocompleteSelectMenu";
export * from './AutocompleteSelectMenu'; export * from "./AutocompleteSelectMenu";

View file

@ -1,12 +1,7 @@
import IconButton from "@material-ui/core/IconButton"; import IconButton from "@material-ui/core/IconButton";
import Menu from "@material-ui/core/Menu"; import Menu from "@material-ui/core/Menu";
import MenuItem from "@material-ui/core/MenuItem"; import MenuItem from "@material-ui/core/MenuItem";
import { import { makeStyles } from "@material-ui/core/styles";
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import MoreVertIcon from "@material-ui/icons/MoreVert"; import MoreVertIcon from "@material-ui/icons/MoreVert";
import React from "react"; import React from "react";
@ -23,80 +18,73 @@ export interface CardMenuProps {
menuItems: CardMenuItem[]; menuItems: CardMenuItem[];
} }
const styles = (theme: Theme) => const useStyles = makeStyles(theme => ({
createStyles({ iconButton: {
iconButton: { background: theme.palette.background.paper,
background: theme.palette.background.paper, borderRadius: "100%",
borderRadius: "100%", height: 32,
height: 32, padding: 0,
padding: 0, width: 32
width: 32
}
});
const CardMenu = withStyles(styles, {
name: "CardMenu"
})(
({
className,
classes,
disabled,
menuItems
}: CardMenuProps & WithStyles<typeof styles>) => {
const [anchorEl, setAnchor] = React.useState<HTMLElement | null>(null);
const handleClick = (event: React.MouseEvent<any>) => {
setAnchor(event.currentTarget);
};
const handleClose = () => {
setAnchor(null);
};
const handleMenuClick = (menuItemIndex: number) => {
menuItems[menuItemIndex].onSelect();
handleClose();
};
const open = !!anchorEl;
return (
<div className={className}>
<IconButton
aria-label="More"
aria-owns={open ? "long-menu" : null}
aria-haspopup="true"
className={classes.iconButton}
color="primary"
disabled={disabled}
onClick={handleClick}
>
<MoreVertIcon />
</IconButton>
<Menu
id="long-menu"
anchorEl={anchorEl}
open={open}
onClose={handleClose}
PaperProps={{
style: {
maxHeight: ITEM_HEIGHT * 4.5
// width: 200
}
}}
>
{menuItems.map((menuItem, menuItemIndex) => (
<MenuItem
onClick={() => handleMenuClick(menuItemIndex)}
key={menuItem.label}
>
{menuItem.label}
</MenuItem>
))}
</Menu>
</div>
);
} }
); }));
const CardMenu: React.FC<CardMenuProps> = props => {
const { className, disabled, menuItems } = props;
const classes = useStyles(props);
const [anchorEl, setAnchor] = React.useState<HTMLElement | null>(null);
const handleClick = (event: React.MouseEvent<any>) => {
setAnchor(event.currentTarget);
};
const handleClose = () => {
setAnchor(null);
};
const handleMenuClick = (menuItemIndex: number) => {
menuItems[menuItemIndex].onSelect();
handleClose();
};
const open = !!anchorEl;
return (
<div className={className}>
<IconButton
aria-label="More"
aria-owns={open ? "long-menu" : null}
aria-haspopup="true"
className={classes.iconButton}
color="primary"
disabled={disabled}
onClick={handleClick}
>
<MoreVertIcon />
</IconButton>
<Menu
id="long-menu"
anchorEl={anchorEl}
open={open}
onClose={handleClose}
PaperProps={{
style: {
maxHeight: ITEM_HEIGHT * 4.5
// width: 200
}
}}
>
{menuItems.map((menuItem, menuItemIndex) => (
<MenuItem
onClick={() => handleMenuClick(menuItemIndex)}
key={menuItem.label}
>
{menuItem.label}
</MenuItem>
))}
</Menu>
</div>
);
};
CardMenu.displayName = "CardMenu"; CardMenu.displayName = "CardMenu";
export default CardMenu; export default CardMenu;

View file

@ -1,29 +1,25 @@
import { import { makeStyles } from "@material-ui/core/styles";
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import React from "react"; import React from "react";
const styles = (theme: Theme) => const useStyles = makeStyles(theme => ({
createStyles({ spacer: {
spacer: { [theme.breakpoints.down("sm")]: {
[theme.breakpoints.down("sm")]: { marginTop: theme.spacing(1)
marginTop: theme.spacing.unit },
}, marginTop: theme.spacing(3)
marginTop: theme.spacing.unit * 3 }
} }));
});
interface CardSpacerProps extends WithStyles<typeof styles> { interface CardSpacerProps {
children?: React.ReactNode; children?: React.ReactNode;
} }
export const CardSpacer = withStyles(styles, { name: "CardSpacer" })( export const CardSpacer: React.FC<CardSpacerProps> = props => {
({ classes, children }: CardSpacerProps) => ( const { children } = props;
<div className={classes.spacer}>{children}</div>
) const classes = useStyles(props);
);
return <div className={classes.spacer}>{children}</div>;
};
CardSpacer.displayName = "CardSpacer"; CardSpacer.displayName = "CardSpacer";
export default CardSpacer; export default CardSpacer;

View file

@ -1,42 +1,36 @@
import { import { makeStyles } from "@material-ui/core/styles";
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import Typography from "@material-ui/core/Typography"; import Typography from "@material-ui/core/Typography";
import classNames from "classnames"; import classNames from "classnames";
import React from "react"; import React from "react";
const styles = (theme: Theme) => const useStyles = makeStyles(theme => ({
createStyles({ children: theme.mixins.gutters({}),
children: theme.mixins.gutters({}), constantHeight: {
constantHeight: { height: 56
height: 56 },
}, hr: {
hr: { border: "none",
border: "none", borderTop: `1px solid ${theme.palette.divider}`,
borderTop: `1px solid ${theme.overrides.MuiCard.root.borderColor}`, height: 0,
height: 0, marginBottom: 0,
marginBottom: 0, marginTop: 0,
marginTop: 0, width: "100%"
width: "100%" },
}, root: theme.mixins.gutters({
root: theme.mixins.gutters({ alignItems: "center",
alignItems: "center", display: "flex",
display: "flex", minHeight: 56
minHeight: 56 }),
}), title: {
title: { flex: 1,
flex: 1, lineHeight: 1
lineHeight: 1 },
}, toolbar: {
toolbar: { marginRight: -theme.spacing(1)
marginRight: -theme.spacing.unit }
} }));
});
interface CardTitleProps extends WithStyles<typeof styles> { interface CardTitleProps {
children?: React.ReactNode; children?: React.ReactNode;
className?: string; className?: string;
height?: "default" | "const"; height?: "default" | "const";
@ -45,24 +39,27 @@ interface CardTitleProps extends WithStyles<typeof styles> {
onClick?: (event: React.MouseEvent<any>) => void; onClick?: (event: React.MouseEvent<any>) => void;
} }
const CardTitle = withStyles(styles, { name: "CardTitle" })( const CardTitle: React.FC<CardTitleProps> = props => {
({ const {
classes,
className, className,
children, children,
height, height,
title, title,
toolbar, toolbar,
onClick, onClick,
...props ...rest
}: CardTitleProps) => ( } = props;
const classes = useStyles(props);
return (
<> <>
<div <div
className={classNames(classes.root, { className={classNames(classes.root, {
[className]: !!className, [className]: !!className,
[classes.constantHeight]: height === "const" [classes.constantHeight]: height === "const"
})} })}
{...props} {...rest}
> >
<Typography <Typography
className={classes.title} className={classes.title}
@ -77,7 +74,7 @@ const CardTitle = withStyles(styles, { name: "CardTitle" })(
<div className={classes.children}>{children}</div> <div className={classes.children}>{children}</div>
<hr className={classes.hr} /> <hr className={classes.hr} />
</> </>
) );
); };
CardTitle.displayName = "CardTitle"; CardTitle.displayName = "CardTitle";
export default CardTitle; export default CardTitle;

View file

@ -1,12 +1,6 @@
import { Omit } from "@material-ui/core";
import ButtonBase from "@material-ui/core/ButtonBase"; import ButtonBase from "@material-ui/core/ButtonBase";
import { CheckboxProps as MuiCheckboxProps } from "@material-ui/core/Checkbox"; import { CheckboxProps as MuiCheckboxProps } from "@material-ui/core/Checkbox";
import { import { makeStyles } from "@material-ui/core/styles";
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import { fade } from "@material-ui/core/styles/colorManipulator"; import { fade } from "@material-ui/core/styles/colorManipulator";
import classNames from "classnames"; import classNames from "classnames";
import React from "react"; import React from "react";
@ -25,116 +19,116 @@ export type CheckboxProps = Omit<
onChange?: (event: React.ChangeEvent<any>) => void; onChange?: (event: React.ChangeEvent<any>) => void;
}; };
const styles = (theme: Theme) => const useStyles = makeStyles(theme => ({
createStyles({ box: {
box: { "&$checked": {
"&$checked": {
"&:before": {
background: theme.palette.primary.main,
color: theme.palette.background.paper,
content: '"\\2713"',
fontWeight: "bold",
textAlign: "center"
},
borderColor: theme.palette.primary.main
},
"&$disabled": {
borderColor: theme.palette.grey[200]
},
"&$indeterminate": {
"&:before": {
background: theme.palette.primary.main,
height: 2,
top: 5
},
borderColor: theme.palette.primary.main
},
"&:before": { "&:before": {
background: "rgba(0, 0, 0, 0)", background: theme.palette.primary.main,
content: '""', color: theme.palette.background.paper,
height: 14, content: '"\\2713"',
left: -1, fontWeight: "bold",
position: "absolute", textAlign: "center"
top: -1,
transition: theme.transitions.duration.short + "ms",
width: 14
}, },
borderColor: theme.palette.primary.main
WebkitAppearance: "none", },
border: `1px solid ${theme.palette.action.active}`, "&$disabled": {
boxSizing: "border-box", borderColor: theme.palette.grey[200]
cursor: "pointer", },
"&$indeterminate": {
"&:before": {
background: theme.palette.primary.main,
height: 2,
top: 5
},
borderColor: theme.palette.primary.main
},
"&:before": {
background: "rgba(0, 0, 0, 0)",
content: '""',
height: 14, height: 14,
outline: "0", left: -1,
position: "relative", position: "absolute",
userSelect: "none", top: -1,
transition: theme.transitions.duration.short + "ms",
width: 14 width: 14
}, },
checked: {},
disabled: {}, WebkitAppearance: "none",
indeterminate: {}, border: `1px solid ${theme.palette.action.active}`,
root: { boxSizing: "border-box",
"&:hover": { cursor: "pointer",
background: fade(theme.palette.primary.main, 0.1) height: 14,
}, outline: "0",
alignSelf: "start", position: "relative",
borderRadius: "100%", userSelect: "none",
cursor: "pointer", width: 14
display: "flex", },
height: 30, checked: {},
justifyContent: "center", disabled: {},
margin: "5px 9px", indeterminate: {},
width: 30 root: {
} "&:hover": {
}); background: fade(theme.palette.primary.main, 0.1)
const Checkbox = withStyles(styles, { name: "Checkbox" })( },
({ alignSelf: "start",
borderRadius: "100%",
cursor: "pointer",
display: "flex",
height: 30,
justifyContent: "center",
margin: "5px 9px",
width: 30
}
}));
const Checkbox: React.FC<CheckboxProps> = props => {
const {
checked, checked,
className, className,
classes,
disabled, disabled,
disableClickPropagation, disableClickPropagation,
indeterminate, indeterminate,
onChange, onChange,
value, value,
name, name,
...props ...rest
}: CheckboxProps & WithStyles<typeof styles>) => { } = props;
const inputRef = React.useRef<HTMLInputElement>(null); const classes = useStyles(props);
const handleClick = React.useCallback(
disableClickPropagation
? event => {
event.stopPropagation();
inputRef.current.click();
}
: () => inputRef.current.click(),
[]
);
return ( const inputRef = React.useRef<HTMLInputElement>(null);
<ButtonBase const handleClick = React.useCallback(
{...props} disableClickPropagation
centerRipple ? event => {
className={classNames(classes.root, className)} event.stopPropagation();
inputRef.current.click();
}
: () => inputRef.current.click(),
[]
);
return (
<ButtonBase
{...rest}
centerRipple
className={classNames(classes.root, className)}
disabled={disabled}
onClick={handleClick}
>
<input
className={classNames(classes.box, {
[classes.checked]: checked,
[classes.disabled]: disabled,
[classes.indeterminate]: indeterminate
})}
disabled={disabled} disabled={disabled}
onClick={handleClick} type="checkbox"
> name={name}
<input value={checked !== undefined && checked.toString()}
className={classNames(classes.box, { ref={inputRef}
[classes.checked]: checked, onChange={onChange}
[classes.disabled]: disabled, />
[classes.indeterminate]: indeterminate </ButtonBase>
})} );
disabled={disabled} };
type="checkbox"
name={name}
value={checked !== undefined && checked.toString()}
ref={inputRef}
onChange={onChange}
/>
</ButtonBase>
);
}
);
Checkbox.displayName = "Checkbox"; Checkbox.displayName = "Checkbox";
export default Checkbox; export default Checkbox;

View file

@ -1,2 +1,2 @@
export { default } from './Checkbox'; export { default } from "./Checkbox";
export * from './Checkbox'; export * from "./Checkbox";

View file

@ -1,9 +1,4 @@
import { import { makeStyles } from "@material-ui/core/styles";
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import { fade } from "@material-ui/core/styles/colorManipulator"; import { fade } from "@material-ui/core/styles/colorManipulator";
import Typography from "@material-ui/core/Typography"; import Typography from "@material-ui/core/Typography";
import CloseIcon from "@material-ui/icons/Close"; import CloseIcon from "@material-ui/icons/Close";
@ -16,32 +11,30 @@ export interface ChipProps {
onClose?: () => void; onClose?: () => void;
} }
const styles = (theme: Theme) => const useStyles = makeStyles(theme => ({
createStyles({ closeIcon: {
closeIcon: { cursor: "pointer",
cursor: "pointer", fontSize: 16,
fontSize: 16, marginLeft: theme.spacing(),
marginLeft: theme.spacing.unit, verticalAlign: "middle"
verticalAlign: "middle" },
}, label: {
label: { color: theme.palette.common.white
color: theme.palette.common.white },
}, root: {
root: { background: fade(theme.palette.secondary.main, 0.8),
background: fade(theme.palette.secondary.main, 0.8), borderRadius: 8,
borderRadius: 8, display: "inline-block",
display: "inline-block", marginRight: theme.spacing(2),
marginRight: theme.spacing.unit * 2, padding: "6px 12px"
padding: "6px 12px" }
} }));
}); const Chip: React.FC<ChipProps> = props => {
const Chip = withStyles(styles, { name: "Chip" })( const { className, label, onClose } = props;
({
classes, const classes = useStyles(props);
className,
label, return (
onClose
}: ChipProps & WithStyles<typeof styles>) => (
<div className={classNames(classes.root, className)}> <div className={classNames(classes.root, className)}>
<Typography className={classes.label} variant="caption"> <Typography className={classes.label} variant="caption">
{label} {label}
@ -50,7 +43,7 @@ const Chip = withStyles(styles, { name: "Chip" })(
)} )}
</Typography> </Typography>
</div> </div>
) );
); };
Chip.displayName = "Chip"; Chip.displayName = "Chip";
export default Chip; export default Chip;

View file

@ -1,2 +1,2 @@
export { default } from './Chip'; export { default } from "./Chip";
export * from './Chip'; export * from "./Chip";

View file

@ -1,9 +1,8 @@
import ClickAwayListener from "@material-ui/core/ClickAwayListener"; import ClickAwayListener from "@material-ui/core/ClickAwayListener";
import Grow from "@material-ui/core/Grow"; import Grow from "@material-ui/core/Grow";
import Popper from "@material-ui/core/Popper"; import Popper from "@material-ui/core/Popper";
import { Theme } from "@material-ui/core/styles";
import { fade } from "@material-ui/core/styles/colorManipulator"; import { fade } from "@material-ui/core/styles/colorManipulator";
import makeStyles from "@material-ui/styles/makeStyles"; import makeStyles from "@material-ui/core/styles/makeStyles";
import React from "react"; import React from "react";
import useStateFromProps from "@saleor/hooks/useStateFromProps"; import useStateFromProps from "@saleor/hooks/useStateFromProps";
@ -26,10 +25,10 @@ export interface ColumnPickerProps
} }
const useStyles = makeStyles( const useStyles = makeStyles(
(theme: Theme) => ({ theme => ({
popper: { popper: {
boxShadow: `0px 5px 10px 0 ${fade(theme.palette.common.black, 0.05)}`, boxShadow: `0px 5px 10px 0 ${fade(theme.palette.common.black, 0.05)}`,
marginTop: theme.spacing.unit * 2, marginTop: theme.spacing(2),
zIndex: 1 zIndex: 1
} }
}), }),

View file

@ -1,8 +1,7 @@
import Button from "@material-ui/core/Button"; import Button from "@material-ui/core/Button";
import { Theme } from "@material-ui/core/styles";
import { fade } from "@material-ui/core/styles/colorManipulator"; import { fade } from "@material-ui/core/styles/colorManipulator";
import makeStyles from "@material-ui/core/styles/makeStyles";
import ArrowDropDownIcon from "@material-ui/icons/ArrowDropDown"; import ArrowDropDownIcon from "@material-ui/icons/ArrowDropDown";
import makeStyles from "@material-ui/styles/makeStyles";
import classNames from "classnames"; import classNames from "classnames";
import React from "react"; import React from "react";
import { FormattedMessage } from "react-intl"; import { FormattedMessage } from "react-intl";
@ -14,16 +13,16 @@ interface ColumnPickerButtonProps {
} }
const useStyles = makeStyles( const useStyles = makeStyles(
(theme: Theme) => ({ theme => ({
icon: { icon: {
marginLeft: theme.spacing.unit * 2, marginLeft: theme.spacing(2),
transition: theme.transitions.duration.short + "ms" transition: theme.transitions.duration.short + "ms"
}, },
root: { root: {
"& span": { "& span": {
color: theme.palette.primary.main color: theme.palette.primary.main
}, },
paddingRight: theme.spacing.unit paddingRight: theme.spacing(1)
}, },
rootActive: { rootActive: {
background: fade(theme.palette.primary.main, 0.1) background: fade(theme.palette.primary.main, 0.1)

View file

@ -2,9 +2,8 @@ import Button from "@material-ui/core/Button";
import Card from "@material-ui/core/Card"; import Card from "@material-ui/core/Card";
import CardContent from "@material-ui/core/CardContent"; import CardContent from "@material-ui/core/CardContent";
import CircularProgress from "@material-ui/core/CircularProgress"; import CircularProgress from "@material-ui/core/CircularProgress";
import { Theme } from "@material-ui/core/styles"; import makeStyles from "@material-ui/core/styles/makeStyles";
import Typography from "@material-ui/core/Typography"; import Typography from "@material-ui/core/Typography";
import makeStyles from "@material-ui/styles/makeStyles";
import classNames from "classnames"; import classNames from "classnames";
import React from "react"; import React from "react";
import InfiniteScroll from "react-infinite-scroller"; import InfiniteScroll from "react-infinite-scroller";
@ -31,7 +30,7 @@ export interface ColumnPickerContentProps extends Partial<FetchMoreProps> {
onSave: () => void; onSave: () => void;
} }
const useStyles = makeStyles((theme: Theme) => ({ const useStyles = makeStyles(theme => ({
actionBar: { actionBar: {
display: "flex", display: "flex",
justifyContent: "space-between" justifyContent: "space-between"
@ -41,28 +40,28 @@ const useStyles = makeStyles((theme: Theme) => ({
transition: theme.transitions.duration.short + "ms" transition: theme.transitions.duration.short + "ms"
}, },
cancelButton: { cancelButton: {
marginRight: theme.spacing.unit * 2 marginRight: theme.spacing(2)
}, },
content: { content: {
display: "grid", display: "grid",
gridColumnGap: theme.spacing.unit * 3, gridColumnGap: theme.spacing(3),
gridTemplateColumns: "repeat(3, 1fr)", gridTemplateColumns: "repeat(3, 1fr)",
maxHeight: 256, maxHeight: 256,
overflowX: "visible", overflowX: "visible",
overflowY: "scroll", overflowY: "scroll",
padding: `${theme.spacing.unit * 2}px ${theme.spacing.unit * 3}px` padding: theme.spacing(2, 3)
}, },
contentContainer: { contentContainer: {
padding: 0 padding: 0
}, },
dropShadow: { dropShadow: {
boxShadow: `0px -5px 10px 0px ${theme.overrides.MuiCard.root.borderColor}` boxShadow: `0px -5px 10px 0px ${theme.palette.divider}`
}, },
loadMoreLoaderContainer: { loadMoreLoaderContainer: {
alignItems: "center", alignItems: "center",
display: "flex", display: "flex",
gridColumnEnd: "span 3", gridColumnEnd: "span 3",
height: theme.spacing.unit * 3, height: theme.spacing(3),
justifyContent: "center" justifyContent: "center"
}, },
root: { root: {

View file

@ -1,11 +1,10 @@
import { Omit } from "@material-ui/core";
import Button, { ButtonProps } from "@material-ui/core/Button"; import Button, { ButtonProps } from "@material-ui/core/Button";
import CircularProgress from "@material-ui/core/CircularProgress"; import CircularProgress from "@material-ui/core/CircularProgress";
import { import {
createStyles, createStyles,
Theme, Theme,
withStyles, WithStyles,
WithStyles withStyles
} from "@material-ui/core/styles"; } from "@material-ui/core/styles";
import CheckIcon from "@material-ui/icons/Check"; import CheckIcon from "@material-ui/icons/Check";
import { buttonMessages } from "@saleor/intl"; import { buttonMessages } from "@saleor/intl";

View file

@ -1,35 +1,31 @@
import { import { makeStyles } from "@material-ui/core/styles";
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import classNames from "classnames"; import classNames from "classnames";
import React from "react"; import React from "react";
const styles = (theme: Theme) => const useStyles = makeStyles(theme => ({
createStyles({ root: {
root: { [theme.breakpoints.up("lg")]: {
[theme.breakpoints.up("lg")]: { marginLeft: "auto",
marginLeft: "auto", marginRight: "auto",
marginRight: "auto", maxWidth: theme.breakpoints.width("lg")
maxWidth: theme.breakpoints.width("lg") },
}, [theme.breakpoints.up("sm")]: {
[theme.breakpoints.up("sm")]: { padding: theme.spacing(0, 3)
padding: `0 ${theme.spacing.unit * 3}px` },
}, padding: theme.spacing(0, 1)
padding: `0 ${theme.spacing.unit}px` }
} }));
});
interface ContainerProps extends WithStyles<typeof styles> { interface ContainerProps {
className?: string; className?: string;
} }
export const Container = withStyles(styles, { export const Container: React.FC<ContainerProps> = props => {
name: "Container" const { className, ...rest } = props;
})(({ classes, className, ...props }: ContainerProps) => (
<div className={classNames(classes.root, className)} {...props} /> const classes = useStyles(props);
));
return <div className={classNames(classes.root, className)} {...rest} />;
};
Container.displayName = "Container"; Container.displayName = "Container";
export default Container; export default Container;

View file

@ -1,19 +1,18 @@
import { createStyles, Theme, withStyles, WithStyles } from "@material-ui/core"; import { makeStyles } from "@material-ui/core";
import FormControlLabel from "@material-ui/core/FormControlLabel"; import FormControlLabel from "@material-ui/core/FormControlLabel";
import Switch from "@material-ui/core/Switch"; import Switch from "@material-ui/core/Switch";
import React from "react"; import React from "react";
const styles = (theme: Theme) => const useStyles = makeStyles(theme => ({
createStyles({ label: {
label: { marginLeft: theme.spacing(3.5)
marginLeft: theme.spacing.unit * 3.5 },
}, labelText: {
labelText: { fontSize: 14
fontSize: 14 }
} }));
});
interface ControlledSwitchProps extends WithStyles<typeof styles> { interface ControlledSwitchProps {
checked: boolean; checked: boolean;
disabled?: boolean; disabled?: boolean;
label: string | React.ReactNode; label: string | React.ReactNode;
@ -23,11 +22,8 @@ interface ControlledSwitchProps extends WithStyles<typeof styles> {
onChange?(event: React.ChangeEvent<any>); onChange?(event: React.ChangeEvent<any>);
} }
export const ControlledSwitch = withStyles(styles, { export const ControlledSwitch: React.FC<ControlledSwitchProps> = props => {
name: "ControlledSwitch" const {
})(
({
classes,
checked, checked,
disabled, disabled,
onChange, onChange,
@ -35,7 +31,11 @@ export const ControlledSwitch = withStyles(styles, {
name, name,
secondLabel, secondLabel,
uncheckedLabel uncheckedLabel
}: ControlledSwitchProps) => ( } = props;
const classes = useStyles(props);
return (
<FormControlLabel <FormControlLabel
control={ control={
<Switch <Switch
@ -65,7 +65,7 @@ export const ControlledSwitch = withStyles(styles, {
} }
disabled={disabled} disabled={disabled}
/> />
) );
); };
ControlledSwitch.displayName = "ControlledSwitch"; ControlledSwitch.displayName = "ControlledSwitch";
export default ControlledSwitch; export default ControlledSwitch;

View file

@ -2,12 +2,7 @@ import Button from "@material-ui/core/Button";
import Card from "@material-ui/core/Card"; import Card from "@material-ui/core/Card";
import CardContent from "@material-ui/core/CardContent"; import CardContent from "@material-ui/core/CardContent";
import IconButton from "@material-ui/core/IconButton"; import IconButton from "@material-ui/core/IconButton";
import { import { makeStyles } from "@material-ui/core/styles";
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import Table from "@material-ui/core/Table"; import Table from "@material-ui/core/Table";
import TableBody from "@material-ui/core/TableBody"; import TableBody from "@material-ui/core/TableBody";
import TableCell from "@material-ui/core/TableCell"; import TableCell from "@material-ui/core/TableCell";
@ -32,158 +27,155 @@ export interface CountryListProps {
onCountryUnassign: (country: string) => void; onCountryUnassign: (country: string) => void;
} }
const styles = (theme: Theme) => const useStyles = makeStyles(theme => ({
createStyles({ iconCell: {
iconCell: { "&:last-child": {
"&:last-child": { paddingRight: 0
paddingRight: 0
},
width: 48 + theme.spacing.unit / 2
}, },
indicator: { width: 48 + theme.spacing(2)
color: theme.palette.text.disabled, },
display: "inline-block", indicator: {
left: 0, color: theme.palette.text.disabled,
marginRight: theme.spacing.unit * 2, display: "inline-block",
position: "absolute" left: 0,
marginRight: theme.spacing(0.5),
position: "absolute"
},
offsetCell: {
"&:first-child": {
paddingLeft: theme.spacing(3)
}, },
offsetCell: { position: "relative"
"&:first-child": { },
paddingLeft: theme.spacing.unit * 3 pointer: {
}, cursor: "pointer"
position: "relative" },
root: {
"&:last-child": {
paddingBottom: 0
}, },
pointer: { paddingTop: 0
cursor: "pointer" },
}, rotate: {
root: { transform: "rotate(180deg)"
"&:last-child": { },
paddingBottom: 0 textRight: {
}, textAlign: "right"
paddingTop: 0 },
}, toLeft: {
rotate: { "&:first-child": {
transform: "rotate(180deg)" paddingLeft: 0
},
textRight: {
textAlign: "right"
},
toLeft: {
"&:first-child": {
paddingLeft: 0
}
},
wideColumn: {
width: "100%"
} }
}); },
wideColumn: {
width: "100%"
}
}));
const CountryList = withStyles(styles, { const CountryList: React.FC<CountryListProps> = props => {
name: "CountryList" const {
})(
({
classes,
countries, countries,
disabled, disabled,
emptyText, emptyText,
title, title,
onCountryAssign, onCountryAssign,
onCountryUnassign onCountryUnassign
}: CountryListProps & WithStyles<typeof styles>) => { } = props;
const [isCollapsed, setCollapseStatus] = React.useState(true); const classes = useStyles(props);
const toggleCollapse = () => setCollapseStatus(!isCollapsed);
return ( const [isCollapsed, setCollapseStatus] = React.useState(true);
<Card> const toggleCollapse = () => setCollapseStatus(!isCollapsed);
<CardTitle
title={title} return (
toolbar={ <Card>
<Button color="primary" onClick={onCountryAssign}> <CardTitle
<FormattedMessage title={title}
defaultMessage="Assign countries" toolbar={
description="button" <Button color="primary" onClick={onCountryAssign}>
/> <FormattedMessage
</Button> defaultMessage="Assign countries"
} description="button"
/> />
<CardContent className={classes.root}> </Button>
<Table> }
<TableBody> />
<TableRow className={classes.pointer} onClick={toggleCollapse}> <CardContent className={classes.root}>
<TableCell <Table>
className={classNames(classes.wideColumn, classes.toLeft)} <TableBody>
> <TableRow className={classes.pointer} onClick={toggleCollapse}>
<FormattedMessage <TableCell
defaultMessage="{number} Countries" className={classNames(classes.wideColumn, classes.toLeft)}
description="number of countries" >
values={{ <FormattedMessage
number: maybe(() => countries.length.toString(), "...") defaultMessage="{number} Countries"
}} description="number of countries"
values={{
number: maybe(() => countries.length.toString(), "...")
}}
/>
</TableCell>
<TableCell
className={classNames(classes.textRight, classes.iconCell)}
>
<IconButton>
<ArrowDropDownIcon
className={classNames({
[classes.rotate]: !isCollapsed
})}
/> />
</TableCell> </IconButton>
<TableCell </TableCell>
className={classNames(classes.textRight, classes.iconCell)} </TableRow>
> {!isCollapsed &&
<IconButton> renderCollection(
<ArrowDropDownIcon countries,
className={classNames({ (country, countryIndex) => (
[classes.rotate]: !isCollapsed <TableRow key={country ? country.code : "skeleton"}>
})} <TableCell className={classes.offsetCell}>
/> {maybe<React.ReactNode>(
</IconButton> () => (
</TableCell> <>
</TableRow> {(countryIndex === 0 ||
{!isCollapsed && countries[countryIndex].country[0] !==
renderCollection( countries[countryIndex - 1].country[0]) && (
countries, <span className={classes.indicator}>
(country, countryIndex) => ( {country.country[0]}
<TableRow key={country ? country.code : "skeleton"}> </span>
<TableCell className={classes.offsetCell}> )}
{maybe<React.ReactNode>( {country.country}
() => ( </>
<> ),
{(countryIndex === 0 || <Skeleton />
countries[countryIndex].country[0] !== )}
countries[countryIndex - 1].country[0]) && ( </TableCell>
<span className={classes.indicator}> <TableCell
{country.country[0]} className={classNames(
</span> classes.textRight,
)} classes.iconCell
{country.country} )}
</> >
), <IconButton
<Skeleton /> color="primary"
)} disabled={!country || disabled}
</TableCell> onClick={() => onCountryUnassign(country.code)}
<TableCell
className={classNames(
classes.textRight,
classes.iconCell
)}
> >
<IconButton <DeleteIcon />
color="primary" </IconButton>
disabled={!country || disabled} </TableCell>
onClick={() => onCountryUnassign(country.code)} </TableRow>
> ),
<DeleteIcon /> () => (
</IconButton> <TableRow>
</TableCell> <TableCell className={classes.toLeft} colSpan={2}>
</TableRow> {emptyText}
), </TableCell>
() => ( </TableRow>
<TableRow> )
<TableCell className={classes.toLeft} colSpan={2}> )}
{emptyText} </TableBody>
</TableCell> </Table>
</TableRow> </CardContent>
) </Card>
)} );
</TableBody> };
</Table>
</CardContent>
</Card>
);
}
);
export default CountryList; export default CountryList;

View file

@ -1,7 +1,7 @@
import React from "react"; import React from "react";
export interface DebounceProps<T> { export interface DebounceProps<T> {
children: ((props: (...args: T[]) => void) => React.ReactNode); children: (props: (...args: T[]) => void) => React.ReactNode;
debounceFn: (...args: T[]) => void; debounceFn: (...args: T[]) => void;
time?: number; time?: number;
} }

View file

@ -1,2 +1,2 @@
export { default } from './DeleteFilterTabDialog'; export { default } from "./DeleteFilterTabDialog";
export * from './DeleteFilterTabDialog'; export * from "./DeleteFilterTabDialog";

View file

@ -1,11 +1,6 @@
import Card from "@material-ui/core/Card"; import Card from "@material-ui/core/Card";
import CardContent from "@material-ui/core/CardContent"; import CardContent from "@material-ui/core/CardContent";
import { import { makeStyles } from "@material-ui/core/styles";
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import TableCell from "@material-ui/core/TableCell"; import TableCell from "@material-ui/core/TableCell";
import TextField, { TextFieldProps } from "@material-ui/core/TextField"; import TextField, { TextFieldProps } from "@material-ui/core/TextField";
import Typography from "@material-ui/core/Typography"; import Typography from "@material-ui/core/Typography";
@ -14,38 +9,37 @@ import React from "react";
import useForm from "@saleor/hooks/useForm"; import useForm from "@saleor/hooks/useForm";
const styles = (theme: Theme) => const useStyles = makeStyles(theme => ({
createStyles({ card: {
card: { border: `1px solid ${theme.palette.divider}`
border: `1px solid ${theme.overrides.MuiCard.root.borderColor}` },
}, container: {
container: { position: "relative"
position: "relative" },
}, overlay: {
overlay: { cursor: "pointer",
cursor: "pointer", height: "100vh",
height: "100vh", left: 0,
left: 0, position: "fixed",
position: "fixed", top: 0,
top: 0, width: "100vw",
width: "100vw", zIndex: 1
zIndex: 1 },
}, root: {
root: { left: 0,
left: 0, minWidth: theme.spacing(20),
minWidth: theme.spacing.unit * 20, position: "absolute",
position: "absolute", top: 0,
top: 0, width: `calc(100% + ${theme.spacing(4)}px)`,
width: `calc(100% + ${4 * theme.spacing.unit}px)`, zIndex: 2
zIndex: 2 },
}, text: {
text: { cursor: "pointer",
cursor: "pointer", fontSize: "0.8125rem"
fontSize: "0.8125rem" }
} }));
});
interface EditableTableCellProps extends WithStyles<typeof styles> { interface EditableTableCellProps {
className?: string; className?: string;
defaultValue?: string; defaultValue?: string;
focused?: boolean; focused?: boolean;
@ -54,54 +48,52 @@ interface EditableTableCellProps extends WithStyles<typeof styles> {
onConfirm(value: string): any; onConfirm(value: string): any;
} }
export const EditableTableCell = withStyles(styles, { export const EditableTableCell: React.FC<EditableTableCellProps> = props => {
name: "EditableTableCell" const {
})(
({
classes,
className, className,
defaultValue, defaultValue,
focused, focused,
InputProps, InputProps,
value, value,
onConfirm onConfirm
}: EditableTableCellProps) => { } = props;
const handleConfirm = (data: { value: string }) => { const classes = useStyles(props);
disable();
onConfirm(data.value);
};
const [opened, setOpenStatus] = React.useState(focused); const handleConfirm = (data: { value: string }) => {
const { change, data } = useForm({ value }, [], handleConfirm); disable();
const enable = () => setOpenStatus(true); onConfirm(data.value);
const disable = () => setOpenStatus(false); };
return ( const [opened, setOpenStatus] = React.useState(focused);
<TableCell className={classNames(classes.container, className)}> const { change, data } = useForm({ value }, [], handleConfirm);
{opened && <div className={classes.overlay} onClick={disable} />} const enable = () => setOpenStatus(true);
<Typography variant="caption" onClick={enable} className={classes.text}> const disable = () => setOpenStatus(false);
{value || defaultValue}
</Typography> return (
{opened && ( <TableCell className={classNames(classes.container, className)}>
<div className={classes.root}> {opened && <div className={classes.overlay} onClick={disable} />}
<Card className={classes.card}> <Typography variant="caption" onClick={enable} className={classes.text}>
<CardContent> {value || defaultValue}
<TextField </Typography>
name="value" {opened && (
autoFocus <div className={classes.root}>
fullWidth <Card className={classes.card}>
onChange={change} <CardContent>
value={data.value} <TextField
variant="standard" name="value"
{...InputProps} autoFocus
/> fullWidth
</CardContent> onChange={change}
</Card> value={data.value}
</div> variant="standard"
)} {...InputProps}
</TableCell> />
); </CardContent>
} </Card>
); </div>
)}
</TableCell>
);
};
EditableTableCell.displayName = "EditableTableCell"; EditableTableCell.displayName = "EditableTableCell";
export default EditableTableCell; export default EditableTableCell;

View file

@ -13,7 +13,7 @@ const ErrorMessageCard: React.FC<ErrorMessageCardProps> = ({ message }) => (
<Typography variant="h5" component="h2"> <Typography variant="h5" component="h2">
<FormattedMessage defaultMessage="Error" description="header" /> <FormattedMessage defaultMessage="Error" description="header" />
</Typography> </Typography>
<Typography variant="body2">{message}</Typography> <Typography variant="body1">{message}</Typography>
</CardContent> </CardContent>
</Card> </Card>
); );

View file

@ -1,10 +1,5 @@
import Button from "@material-ui/core/Button"; import Button from "@material-ui/core/Button";
import { import { makeStyles } from "@material-ui/core/styles";
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import Typography from "@material-ui/core/Typography"; import Typography from "@material-ui/core/Typography";
import React from "react"; import React from "react";
import SVG from "react-inlinesvg"; import SVG from "react-inlinesvg";
@ -12,57 +7,60 @@ import { FormattedMessage } from "react-intl";
import notFoundImage from "@assets/images/what.svg"; import notFoundImage from "@assets/images/what.svg";
export interface ErrorPageProps extends WithStyles<typeof styles> { export interface ErrorPageProps {
onBack: () => void; onBack: () => void;
} }
const styles = (theme: Theme) => const useStyles = makeStyles(theme => ({
createStyles({ bottomHeader: {
bottomHeader: { fontWeight: 600 as 600,
fontWeight: 600 as 600, textTransform: "uppercase"
textTransform: "uppercase" },
button: {
marginTop: theme.spacing(2),
padding: 20
},
container: {
[theme.breakpoints.down("sm")]: {
gridTemplateColumns: "1fr",
padding: theme.spacing(3),
width: "100%"
}, },
button: { display: "grid",
marginTop: theme.spacing.unit * 2, gridTemplateColumns: "1fr 487px",
padding: 20 margin: "0 auto",
width: 830
},
innerContainer: {
[theme.breakpoints.down("sm")]: {
order: 1,
textAlign: "center"
}, },
container: { display: "flex",
[theme.breakpoints.down("sm")]: { flexDirection: "column",
gridTemplateColumns: "1fr", justifyContent: "center"
padding: theme.spacing.unit * 3, },
width: "100%" notFoundImage: {
}, "& svg": {
display: "grid", width: "100%"
gridTemplateColumns: "1fr 487px",
margin: "0 auto",
width: 830
},
innerContainer: {
[theme.breakpoints.down("sm")]: {
order: 1,
textAlign: "center"
},
display: "flex",
flexDirection: "column",
justifyContent: "center"
},
notFoundImage: {
"& svg": {
width: "100%"
}
},
root: {
alignItems: "center",
display: "flex",
height: "calc(100vh - 88px)"
},
upperHeader: {
fontWeight: 600 as 600
} }
}); },
root: {
alignItems: "center",
display: "flex",
height: "calc(100vh - 88px)"
},
upperHeader: {
fontWeight: 600 as 600
}
}));
const ErrorPage = withStyles(styles, { name: "NotFoundPage" })( const ErrorPage: React.FC<ErrorPageProps> = props => {
({ classes, onBack }: ErrorPageProps) => ( const { onBack } = props;
const classes = useStyles(props);
return (
<div className={classes.root}> <div className={classes.root}>
<div className={classes.container}> <div className={classes.container}>
<div className={classes.innerContainer}> <div className={classes.innerContainer}>
@ -99,7 +97,7 @@ const ErrorPage = withStyles(styles, { name: "NotFoundPage" })(
</div> </div>
</div> </div>
</div> </div>
) );
); };
ErrorPage.displayName = "ErrorPage"; ErrorPage.displayName = "ErrorPage";
export default ErrorPage; export default ErrorPage;

View file

@ -1,55 +1,53 @@
import { import { makeStyles } from "@material-ui/core/styles";
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import classNames from "classnames"; import classNames from "classnames";
import React from "react"; import React from "react";
const styles = (theme: Theme) => const useStyles = makeStyles(theme => ({
createStyles({ action: {
action: { flex: "0 0 auto"
flex: "0 0 auto" },
}, grid: {
grid: { padding: theme.spacing(2)
padding: theme.spacing.unit * 2 },
}, menuButton: {
menuButton: { flex: "0 0 auto",
flex: "0 0 auto", marginLeft: -theme.spacing(2),
marginLeft: theme.spacing.unit * -2, marginRight: theme.spacing(3),
marginRight: theme.spacing.unit * 3, marginTop: -theme.spacing(2)
marginTop: -theme.spacing.unit * 2 },
}, root: {
root: { alignItems: "center",
alignItems: "center", display: "flex",
display: "flex", marginBottom: theme.spacing(3)
marginBottom: theme.spacing.unit * 3 },
}, subtitle: {
subtitle: { alignItems: "center",
alignItems: "center", display: "flex",
display: "flex", marginBottom: theme.spacing(2)
marginBottom: theme.spacing.unit * 2 },
}, title: {
title: { flex: 1,
flex: 1, paddingBottom: theme.spacing(2)
paddingBottom: theme.spacing.unit * 2 }
} }));
});
interface ExtendedPageHeaderProps extends WithStyles<typeof styles> { interface ExtendedPageHeaderProps {
children?: React.ReactNode; children?: React.ReactNode;
className?: string; className?: string;
title?: React.ReactNode; title?: React.ReactNode;
} }
const ExtendedPageHeader = withStyles(styles, { name: "ExtendedPageHeader" })( const ExtendedPageHeader: React.FC<ExtendedPageHeaderProps> = props => {
({ children, classes, className, title }: ExtendedPageHeaderProps) => ( const { children, className, title } = props;
const classes = useStyles(props);
return (
<div className={classNames(classes.root, className)}> <div className={classNames(classes.root, className)}>
{title} {title}
<div className={classes.action}>{children}</div> <div className={classes.action}>{children}</div>
</div> </div>
) );
); };
ExtendedPageHeader.displayName = "ExtendedPageHeader"; ExtendedPageHeader.displayName = "ExtendedPageHeader";
export default ExtendedPageHeader; export default ExtendedPageHeader;

View file

@ -1,36 +1,31 @@
import { createStyles, withStyles, WithStyles } from "@material-ui/core/styles"; import { makeStyles } from "@material-ui/core/styles";
import Typography, { TypographyProps } from "@material-ui/core/Typography"; import Typography, { TypographyProps } from "@material-ui/core/Typography";
import React from "react"; import React from "react";
const styles = createStyles({ const useStyles = makeStyles({
link: { link: {
textDecoration: "none" textDecoration: "none"
} }
}); });
interface ExternalLinkProps interface ExternalLinkProps extends React.HTMLProps<HTMLAnchorElement> {
extends React.HTMLProps<HTMLAnchorElement>,
WithStyles<typeof styles> {
href: string; href: string;
className?: string; className?: string;
typographyProps?: TypographyProps; typographyProps?: TypographyProps;
} }
const ExternalLink = withStyles(styles, { name: "ExternalLink" })( const ExternalLink: React.FC<ExternalLinkProps> = props => {
({ const { className, children, href, typographyProps, ...rest } = props;
classes,
className, const classes = useStyles(props);
children,
href, return (
typographyProps, <a href={href} className={classes.link} {...rest}>
...props
}: ExternalLinkProps) => (
<a href={href} className={classes.link} {...props}>
<Typography className={className} color="primary" {...typographyProps}> <Typography className={className} color="primary" {...typographyProps}>
{children} {children}
</Typography> </Typography>
</a> </a>
) );
); };
ExternalLink.displayName = "ExternalLink"; ExternalLink.displayName = "ExternalLink";
export default ExternalLink; export default ExternalLink;

View file

@ -1,10 +1,10 @@
import Button from "@material-ui/core/Button"; import Button from "@material-ui/core/Button";
import { createStyles, withStyles, WithStyles } from "@material-ui/core/styles"; import { makeStyles } from "@material-ui/core/styles";
import TextField from "@material-ui/core/TextField"; import TextField from "@material-ui/core/TextField";
import React from "react"; import React from "react";
import { FormattedMessage } from "react-intl"; import { FormattedMessage } from "react-intl";
const styles = createStyles({ const useStyles = makeStyles({
fileUploadField: { fileUploadField: {
display: "none" display: "none"
}, },
@ -16,15 +16,19 @@ const styles = createStyles({
} }
}); });
interface FileUploadProps extends WithStyles<typeof styles> { interface FileUploadProps {
disabled?: boolean; disabled?: boolean;
name?: string; name?: string;
value?: any; value?: any;
onChange?(event: React.ChangeEvent<any>); onChange?(event: React.ChangeEvent<any>);
} }
const FileUpload = withStyles(styles, { name: "FileUpload" })( const FileUpload: React.FC<FileUploadProps> = props => {
({ classes, disabled, name, value, onChange }: FileUploadProps) => ( const { disabled, name, value, onChange } = props;
const classes = useStyles(props);
return (
<div className={classes.root}> <div className={classes.root}>
<input <input
disabled={disabled} disabled={disabled}
@ -48,7 +52,7 @@ const FileUpload = withStyles(styles, { name: "FileUpload" })(
/> />
</Button> </Button>
</div> </div>
) );
); };
FileUpload.displayName = "FileUpload"; FileUpload.displayName = "FileUpload";
export default FileUpload; export default FileUpload;

View file

@ -2,12 +2,7 @@ import ButtonBase from "@material-ui/core/ButtonBase";
import Grow from "@material-ui/core/Grow"; import Grow from "@material-ui/core/Grow";
import Paper from "@material-ui/core/Paper"; import Paper from "@material-ui/core/Paper";
import Popper from "@material-ui/core/Popper"; import Popper from "@material-ui/core/Popper";
import { import { makeStyles } from "@material-ui/core/styles";
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import { fade } from "@material-ui/core/styles/colorManipulator"; import { fade } from "@material-ui/core/styles/colorManipulator";
import Typography from "@material-ui/core/Typography"; import Typography from "@material-ui/core/Typography";
import ArrowDropDownIcon from "@material-ui/icons/ArrowDropDown"; import ArrowDropDownIcon from "@material-ui/icons/ArrowDropDown";
@ -26,130 +21,120 @@ export interface FilterProps<TFilterKeys = string> {
onFilterAdd: (filter: FilterContentSubmitData) => void; onFilterAdd: (filter: FilterContentSubmitData) => void;
} }
const styles = (theme: Theme) => const useStyles = makeStyles(theme => ({
createStyles({ addFilterButton: {
addFilterButton: { "&$filterButton": {
"&$filterButton": { "&:hover, &:focus": {
"&:hover, &:focus": {
backgroundColor: fade(theme.palette.primary.main, 0.1)
},
backgroundColor: theme.palette.background.paper,
border: `1px solid ${theme.palette.primary.main}`,
cursor: "pointer",
marginBottom: 0,
marginRight: theme.spacing.unit * 2,
marginTop: 0,
transition: theme.transitions.duration.short + "ms"
}
},
addFilterButtonActive: {
"&$addFilterButton": {
backgroundColor: fade(theme.palette.primary.main, 0.1) backgroundColor: fade(theme.palette.primary.main, 0.1)
}
},
addFilterIcon: {
transition: theme.transitions.duration.short + "ms"
},
addFilterText: {
color: theme.palette.primary.main,
fontSize: 14,
fontWeight: 600 as 600,
marginRight: 4,
textTransform: "uppercase"
},
filterButton: {
alignItems: "center",
backgroundColor: fade(theme.palette.primary.main, 0.6),
borderRadius: "4px",
display: "flex",
height: "45px",
justifyContent: "space-around",
margin: `0 ${theme.spacing.unit * 2}px ${theme.spacing.unit}px`,
marginLeft: 0,
padding: "0 16px",
position: "relative",
top: -5
},
paper: {
"& p": {
paddingBottom: 10
}, },
marginTop: theme.spacing.unit * 2, backgroundColor: theme.palette.background.paper,
padding: theme.spacing.unit * 2, border: `1px solid ${theme.palette.primary.main}`,
width: 240 cursor: "pointer",
}, marginBottom: 0,
popover: { marginRight: theme.spacing(2),
zIndex: 1 marginTop: 0,
}, transition: theme.transitions.duration.short + "ms"
rotate: {
transform: "rotate(180deg)"
} }
}); },
const Filter = withStyles(styles, { name: "Filter" })( addFilterButtonActive: {
({ "&$addFilterButton": {
classes, backgroundColor: fade(theme.palette.primary.main, 0.1)
currencySymbol, }
filterLabel, },
menu, addFilterIcon: {
onFilterAdd transition: theme.transitions.duration.short + "ms"
}: FilterProps & WithStyles<typeof styles>) => { },
const anchor = React.useRef<HTMLDivElement>(); addFilterText: {
const [isFilterMenuOpened, setFilterMenuOpened] = React.useState(false); color: theme.palette.primary.main,
fontSize: 14,
return ( fontWeight: 600 as 600,
<div ref={anchor}> marginRight: 4,
<ButtonBase textTransform: "uppercase"
className={classNames(classes.filterButton, classes.addFilterButton, { },
[classes.addFilterButtonActive]: isFilterMenuOpened filterButton: {
})} alignItems: "center",
onClick={() => setFilterMenuOpened(!isFilterMenuOpened)} backgroundColor: fade(theme.palette.primary.main, 0.6),
> borderRadius: "4px",
<Typography className={classes.addFilterText}> display: "flex",
<FormattedMessage height: 40,
defaultMessage="Add Filter" justifyContent: "space-around",
description="button" margin: theme.spacing(2, 1),
/> marginLeft: 0,
</Typography> padding: theme.spacing(0, 2),
<ArrowDropDownIcon position: "relative"
color="primary" },
className={classNames(classes.addFilterIcon, { paper: {
[classes.rotate]: isFilterMenuOpened "& p": {
})} paddingBottom: 10
/> },
</ButtonBase> marginTop: theme.spacing(2),
<Popper padding: theme.spacing(2),
className={classes.popover} width: 240
open={isFilterMenuOpened} },
anchorEl={anchor.current} popover: {
transition zIndex: 1
disablePortal },
placement="bottom-start" rotate: {
> transform: "rotate(180deg)"
{({ TransitionProps, placement }) => (
<Grow
{...TransitionProps}
style={{
transformOrigin:
placement === "bottom" ? "right top" : "right bottom"
}}
>
<Paper className={classes.paper}>
<Typography>{filterLabel}</Typography>
<FilterContent
currencySymbol={currencySymbol}
filters={menu}
onSubmit={data => {
onFilterAdd(data);
setFilterMenuOpened(false);
}}
/>
</Paper>
</Grow>
)}
</Popper>
</div>
);
} }
); }));
const Filter: React.FC<FilterProps> = props => {
const { currencySymbol, filterLabel, menu, onFilterAdd } = props;
const classes = useStyles(props);
const anchor = React.useRef<HTMLDivElement>();
const [isFilterMenuOpened, setFilterMenuOpened] = React.useState(false);
return (
<div ref={anchor}>
<ButtonBase
className={classNames(classes.filterButton, classes.addFilterButton, {
[classes.addFilterButtonActive]: isFilterMenuOpened
})}
onClick={() => setFilterMenuOpened(!isFilterMenuOpened)}
>
<Typography className={classes.addFilterText}>
<FormattedMessage defaultMessage="Add Filter" description="button" />
</Typography>
<ArrowDropDownIcon
color="primary"
className={classNames(classes.addFilterIcon, {
[classes.rotate]: isFilterMenuOpened
})}
/>
</ButtonBase>
<Popper
className={classes.popover}
open={isFilterMenuOpened}
anchorEl={anchor.current}
transition
disablePortal
placement="bottom-start"
>
{({ TransitionProps, placement }) => (
<Grow
{...TransitionProps}
style={{
transformOrigin:
placement === "bottom" ? "right top" : "right bottom"
}}
>
<Paper className={classes.paper}>
<Typography>{filterLabel}</Typography>
<FilterContent
currencySymbol={currencySymbol}
filters={menu}
onSubmit={data => {
onFilterAdd(data);
setFilterMenuOpened(false);
}}
/>
</Paper>
</Grow>
)}
</Popper>
</div>
);
};
Filter.displayName = "Filter"; Filter.displayName = "Filter";
export default Filter; export default Filter;

View file

@ -1,6 +1,6 @@
import { Theme } from "@material-ui/core/styles"; import { makeStyles } from "@material-ui/core/styles";
import TextField, { TextFieldProps } from "@material-ui/core/TextField"; import TextField, { TextFieldProps } from "@material-ui/core/TextField";
import { makeStyles } from "@material-ui/styles"; import classNames from "classnames";
import React from "react"; import React from "react";
import { FilterContentSubmitData, IFilter } from "../Filter"; import { FilterContentSubmitData, IFilter } from "../Filter";
@ -8,7 +8,7 @@ import Filter from "./Filter";
const useInputStyles = makeStyles({ const useInputStyles = makeStyles({
input: { input: {
padding: "10px 12px" padding: "10.5px 12px"
}, },
root: { root: {
flex: 1 flex: 1
@ -17,6 +17,7 @@ const useInputStyles = makeStyles({
const Search: React.FC<TextFieldProps> = props => { const Search: React.FC<TextFieldProps> = props => {
const classes = useInputStyles({}); const classes = useInputStyles({});
return ( return (
<TextField <TextField
{...props} {...props}
@ -29,13 +30,14 @@ const Search: React.FC<TextFieldProps> = props => {
}; };
const useStyles = makeStyles( const useStyles = makeStyles(
(theme: Theme) => ({ theme => ({
actionContainer: { actionContainer: {
display: "flex", display: "flex",
flexWrap: "wrap", flexWrap: "wrap",
padding: `${theme.spacing.unit * 1.5}px ${theme.spacing.unit * 3}px ${ padding: theme.spacing(1, 3)
theme.spacing.unit },
}px` searchOnly: {
paddingBottom: theme.spacing(1.5)
} }
}), }),
{ {
@ -62,7 +64,7 @@ export const FilterActionsOnlySearch: React.FC<
const classes = useStyles(props); const classes = useStyles(props);
return ( return (
<div className={classes.actionContainer}> <div className={classNames(classes.actionContainer, classes.searchOnly)}>
<Search <Search
fullWidth fullWidth
placeholder={placeholder} placeholder={placeholder}

View file

@ -3,7 +3,7 @@ import Typography from "@material-ui/core/Typography";
import React from "react"; import React from "react";
import { FormattedMessage, useIntl } from "react-intl"; import { FormattedMessage, useIntl } from "react-intl";
import { makeStyles } from "@material-ui/styles"; import { makeStyles } from "@material-ui/core/styles";
import { getMenuItemByValue, isLeaf, walkToRoot } from "../../utils/menu"; import { getMenuItemByValue, isLeaf, walkToRoot } from "../../utils/menu";
import FormSpacer from "../FormSpacer"; import FormSpacer from "../FormSpacer";
import SingleSelectField from "../SingleSelectField"; import SingleSelectField from "../SingleSelectField";

View file

@ -1,6 +1,6 @@
import { makeStyles } from "@material-ui/core/styles";
import TextField from "@material-ui/core/TextField"; import TextField from "@material-ui/core/TextField";
import Typography from "@material-ui/core/Typography"; import Typography from "@material-ui/core/Typography";
import { makeStyles } from "@material-ui/styles";
import React from "react"; import React from "react";
import { FormattedMessage, useIntl } from "react-intl"; import { FormattedMessage, useIntl } from "react-intl";

View file

@ -1,5 +1,4 @@
import { Theme } from "@material-ui/core/styles"; import { makeStyles } from "@material-ui/core/styles";
import { makeStyles } from "@material-ui/styles";
import React from "react"; import React from "react";
import { FormattedMessage } from "react-intl"; import { FormattedMessage } from "react-intl";
@ -17,7 +16,7 @@ export interface FilterSearchProps extends SearchPageProps {
} }
const useStyles = makeStyles( const useStyles = makeStyles(
(theme: Theme) => ({ theme => ({
tabAction: { tabAction: {
display: "inline-block" display: "inline-block"
}, },
@ -25,8 +24,8 @@ const useStyles = makeStyles(
borderBottom: `1px solid ${theme.palette.divider}`, borderBottom: `1px solid ${theme.palette.divider}`,
display: "flex", display: "flex",
justifyContent: "flex-end", justifyContent: "flex-end",
marginTop: theme.spacing.unit, marginTop: theme.spacing(),
padding: `0 ${theme.spacing.unit * 3}px ${theme.spacing.unit}px` padding: theme.spacing(0, 1, 3, 1)
} }
}), }),
{ {

View file

@ -1,2 +1,2 @@
export { default } from './FilterBar'; export { default } from "./FilterBar";
export * from './FilterBar'; export * from "./FilterBar";

View file

@ -1,27 +1,23 @@
import { import { makeStyles } from "@material-ui/core/styles";
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import React from "react"; import React from "react";
const styles = (theme: Theme) => const useStyles = makeStyles(theme => ({
createStyles({ spacer: {
spacer: { marginTop: theme.spacing(3)
marginTop: theme.spacing.unit * 3 }
} }));
});
interface FormSpacerProps extends WithStyles<typeof styles> { interface FormSpacerProps {
children?: React.ReactNode; children?: React.ReactNode;
} }
export const FormSpacer = withStyles(styles, { name: "FormSpacer" })( export const FormSpacer: React.FC<FormSpacerProps> = props => {
({ classes, children }: FormSpacerProps) => ( const { children } = props;
<div className={classes.spacer}>{children}</div>
) const classes = useStyles(props);
);
return <div className={classes.spacer}>{children}</div>;
};
FormSpacer.displayName = "FormSpacer"; FormSpacer.displayName = "FormSpacer";
export default FormSpacer; export default FormSpacer;

View file

@ -1,43 +1,41 @@
import { import { makeStyles } from "@material-ui/core/styles";
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import classNames from "classnames"; import classNames from "classnames";
import React from "react"; import React from "react";
export type GridVariant = "default" | "inverted" | "uniform"; export type GridVariant = "default" | "inverted" | "uniform";
export interface GridProps extends WithStyles<typeof styles> { export interface GridProps {
children: React.ReactNodeArray | React.ReactNode; children: React.ReactNodeArray | React.ReactNode;
className?: string; className?: string;
variant?: GridVariant; variant?: GridVariant;
} }
const styles = (theme: Theme) => const useStyles = makeStyles(theme => ({
createStyles({ default: {
default: { gridTemplateColumns: "9fr 4fr"
gridTemplateColumns: "9fr 4fr" },
}, inverted: {
inverted: { gridTemplateColumns: "4fr 9fr"
gridTemplateColumns: "4fr 9fr" },
}, root: {
root: { display: "grid",
display: "grid", gridColumnGap: theme.spacing(3),
gridColumnGap: theme.spacing.unit * 3 + "px", gridRowGap: theme.spacing(3),
gridRowGap: theme.spacing.unit * 3 + "px", [theme.breakpoints.down("sm")]: {
[theme.breakpoints.down("sm")]: { gridRowGap: theme.spacing(1),
gridRowGap: theme.spacing.unit + "px", gridTemplateColumns: "1fr"
gridTemplateColumns: "1fr"
}
},
uniform: {
gridTemplateColumns: "1fr 1fr"
} }
}); },
uniform: {
gridTemplateColumns: "1fr 1fr"
}
}));
export const Grid = withStyles(styles, { name: "Grid" })( export const Grid: React.FC<GridProps> = props => {
({ className, children, classes, variant }: GridProps) => ( const { className, children, variant } = props;
const classes = useStyles(props);
return (
<div <div
className={classNames(className, classes.root, { className={classNames(className, classes.root, {
[classes.default]: variant === "default", [classes.default]: variant === "default",
@ -47,8 +45,8 @@ export const Grid = withStyles(styles, { name: "Grid" })(
> >
{children} {children}
</div> </div>
) );
); };
Grid.displayName = "Grid"; Grid.displayName = "Grid";
Grid.defaultProps = { Grid.defaultProps = {
variant: "default" variant: "default"

View file

@ -1,9 +1,4 @@
import { import { makeStyles } from "@material-ui/core/styles";
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import classNames from "classnames"; import classNames from "classnames";
import React from "react"; import React from "react";
@ -11,22 +6,23 @@ interface HrProps {
className?: string; className?: string;
} }
const styles = (theme: Theme) => const useStyles = makeStyles(theme => ({
createStyles({ root: {
root: { backgroundColor: theme.palette.divider,
backgroundColor: theme.overrides.MuiCard.root.borderColor, border: "none",
border: "none", display: "block",
display: "block", height: 1,
height: 1, margin: 0,
margin: 0, width: "100%"
width: "100%" }
} }));
});
export const Hr = withStyles(styles, { name: "Hr" })( export const Hr: React.FC<HrProps> = props => {
({ className, classes }: HrProps & WithStyles<typeof styles>) => ( const { className } = props;
<hr className={classNames(classes.root, className)} />
) const classes = useStyles(props);
);
return <hr className={classNames(classes.root, className)} />;
};
Hr.displayName = "Hr"; Hr.displayName = "Hr";
export default Hr; export default Hr;

View file

@ -1,10 +1,5 @@
import IconButton from "@material-ui/core/IconButton"; import IconButton from "@material-ui/core/IconButton";
import { import { makeStyles } from "@material-ui/core/styles";
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import TableCell from "@material-ui/core/TableCell"; import TableCell from "@material-ui/core/TableCell";
import React from "react"; import React from "react";
@ -17,23 +12,26 @@ export interface IconButtonTableCellProps {
onClick: () => void; onClick: () => void;
} }
const styles = (theme: Theme) => const useStyles = makeStyles(theme => ({
createStyles({ root: {
root: { "&:last-child": {
"&:last-child": { paddingRight: 0
paddingRight: 0 },
}, paddingRight: 0,
paddingRight: 0, width: ICONBUTTON_SIZE + theme.spacing(0.5)
width: ICONBUTTON_SIZE + theme.spacing.unit / 2 }
} }));
}); const IconButtonTableCell: React.FC<IconButtonTableCellProps> = props => {
const IconButtonTableCell = withStyles(styles, { name: "IconButtonTableCell" })( const {
({
children, children,
classes,
disabled, disabled,
onClick onClick
}: IconButtonTableCellProps & WithStyles<typeof styles>) => ( } = props;
const classes = useStyles(props);
return (
<TableCell className={classes.root}> <TableCell className={classes.root}>
<IconButton <IconButton
color="primary" color="primary"
@ -43,7 +41,7 @@ const IconButtonTableCell = withStyles(styles, { name: "IconButtonTableCell" })(
{children} {children}
</IconButton> </IconButton>
</TableCell> </TableCell>
) );
); };
IconButtonTableCell.displayName = "IconButtonTableCell"; IconButtonTableCell.displayName = "IconButtonTableCell";
export default IconButtonTableCell; export default IconButtonTableCell;

View file

@ -1,2 +1,2 @@
export { default } from './IconButtonTableCell'; export { default } from "./IconButtonTableCell";
export * from './IconButtonTableCell'; export * from "./IconButtonTableCell";

View file

@ -1,55 +1,49 @@
import { import { makeStyles } from "@material-ui/core/styles";
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import React from "react"; import React from "react";
import IconButton from "@material-ui/core/IconButton"; import IconButton from "@material-ui/core/IconButton";
import DeleteIcon from "@material-ui/icons/Delete"; import DeleteIcon from "@material-ui/icons/Delete";
import EditIcon from "@material-ui/icons/Edit"; import EditIcon from "@material-ui/icons/Edit";
const styles = (theme: Theme) => const useStyles = makeStyles(theme => ({
createStyles({ image: {
image: { height: "100%",
height: "100%", objectFit: "contain",
objectFit: "contain", userSelect: "none",
userSelect: "none", width: "100%"
width: "100%" },
imageContainer: {
"&:hover, &.dragged": {
"& $imageOverlay": {
display: "block"
}
}, },
imageContainer: { background: theme.palette.background.paper,
"&:hover, &.dragged": { border: `1px solid ${theme.palette.divider}`,
"& $imageOverlay": { borderRadius: theme.spacing(),
display: "block" height: 148,
} overflow: "hidden",
}, padding: theme.spacing(2),
background: theme.palette.background.paper, position: "relative",
border: `1px solid ${theme.overrides.MuiCard.root.borderColor}`, width: 148
borderRadius: theme.spacing.unit, },
height: 148, imageOverlay: {
overflow: "hidden", background: "rgba(0, 0, 0, 0.6)",
padding: theme.spacing.unit * 2, cursor: "move",
position: "relative", display: "none",
width: 148 height: 148,
}, left: 0,
imageOverlay: { position: "absolute",
background: "rgba(0, 0, 0, 0.6)", top: 0,
cursor: "move", width: 148
display: "none", },
height: 148, imageOverlayToolbar: {
left: 0, display: "flex",
position: "absolute", justifyContent: "flex-end"
top: 0, }
width: 148 }));
},
imageOverlayToolbar: {
display: "flex",
justifyContent: "flex-end"
}
});
interface ImageTileProps extends WithStyles<typeof styles> { interface ImageTileProps {
image: { image: {
alt?: string; alt?: string;
url: string; url: string;
@ -58,8 +52,12 @@ interface ImageTileProps extends WithStyles<typeof styles> {
onImageEdit?: (event: React.ChangeEvent<any>) => void; onImageEdit?: (event: React.ChangeEvent<any>) => void;
} }
const ImageTile = withStyles(styles, { name: "ImageTile" })( const ImageTile: React.FC<ImageTileProps> = props => {
({ classes, onImageDelete, onImageEdit, image }: ImageTileProps) => ( const { onImageDelete, onImageEdit, image } = props;
const classes = useStyles(props);
return (
<div className={classes.imageContainer} data-tc="product-image"> <div className={classes.imageContainer} data-tc="product-image">
<div className={classes.imageOverlay}> <div className={classes.imageOverlay}>
<div className={classes.imageOverlayToolbar}> <div className={classes.imageOverlayToolbar}>
@ -77,7 +75,7 @@ const ImageTile = withStyles(styles, { name: "ImageTile" })(
</div> </div>
<img className={classes.image} src={image.url} alt={image.alt} /> <img className={classes.image} src={image.url} alt={image.alt} />
</div> </div>
) );
); };
ImageTile.displayName = "ImageTile"; ImageTile.displayName = "ImageTile";
export default ImageTile; export default ImageTile;

View file

@ -1,9 +1,4 @@
import { import { makeStyles } from "@material-ui/core/styles";
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import { fade } from "@material-ui/core/styles/colorManipulator"; import { fade } from "@material-ui/core/styles/colorManipulator";
import Typography from "@material-ui/core/Typography"; import Typography from "@material-ui/core/Typography";
import classNames from "classnames"; import classNames from "classnames";
@ -22,55 +17,58 @@ interface ImageUploadProps {
onImageUpload: (file: File) => void; onImageUpload: (file: File) => void;
} }
const styles = (theme: Theme) => const useStyles = makeStyles(theme => ({
createStyles({ containerDragActive: {
containerDragActive: { background: fade(theme.palette.primary.main, 0.1),
background: fade(theme.palette.primary.main, 0.1), color: theme.palette.primary.main
color: theme.palette.primary.main },
}, fileField: {
fileField: { display: "none"
display: "none" },
}, imageContainer: {
imageContainer: { background: "#ffffff",
background: "#ffffff", border: "1px solid #eaeaea",
border: "1px solid #eaeaea", borderRadius: theme.spacing(),
borderRadius: theme.spacing.unit, height: 148,
height: 148, justifySelf: "start",
justifySelf: "start", overflow: "hidden",
overflow: "hidden", padding: theme.spacing(2),
padding: theme.spacing.unit * 2, position: "relative",
position: "relative", transition: theme.transitions.duration.standard + "s",
transition: theme.transitions.duration.standard + "s", width: 148
width: 148 },
}, photosIcon: {
photosIcon: { height: "64px",
height: "64px", margin: "0 auto",
margin: "0 auto", width: "64px"
width: "64px" },
}, photosIconContainer: {
photosIconContainer: { padding: theme.spacing(5, 0),
padding: `${theme.spacing.unit * 5}px 0`, textAlign: "center"
textAlign: "center" },
}, uploadText: {
uploadText: { color: theme.typography.body1.color,
color: theme.typography.body2.color, fontSize: 12,
fontSize: 12, fontWeight: 600,
fontWeight: 600, textTransform: "uppercase"
textTransform: "uppercase" }
} }));
});
export const ImageUpload = withStyles(styles, { name: "ImageUpload" })( export const ImageUpload: React.FC<ImageUploadProps> = props => {
({ const {
children, children,
classes,
className, className,
disableClick, disableClick,
isActiveClassName, isActiveClassName,
iconContainerActiveClassName, iconContainerActiveClassName,
iconContainerClassName, iconContainerClassName,
onImageUpload onImageUpload
}: ImageUploadProps & WithStyles<typeof styles>) => ( } = props;
const classes = useStyles(props);
return (
<Dropzone <Dropzone
disableClick={disableClick} disableClick={disableClick}
onDrop={files => onImageUpload(files[0])} onDrop={files => onImageUpload(files[0])}
@ -107,7 +105,7 @@ export const ImageUpload = withStyles(styles, { name: "ImageUpload" })(
</> </>
)} )}
</Dropzone> </Dropzone>
) );
); };
ImageUpload.displayName = "ImageUpload"; ImageUpload.displayName = "ImageUpload";
export default ImageUpload; export default ImageUpload;

View file

@ -5,12 +5,7 @@ import MenuItem from "@material-ui/core/MenuItem";
import Menu from "@material-ui/core/MenuList"; import Menu from "@material-ui/core/MenuList";
import Paper from "@material-ui/core/Paper"; import Paper from "@material-ui/core/Paper";
import Popper from "@material-ui/core/Popper"; import Popper from "@material-ui/core/Popper";
import { import { makeStyles } from "@material-ui/core/styles";
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import Typography from "@material-ui/core/Typography"; import Typography from "@material-ui/core/Typography";
import ArrowDropDown from "@material-ui/icons/ArrowDropDown"; import ArrowDropDown from "@material-ui/icons/ArrowDropDown";
import classNames from "classnames"; import classNames from "classnames";
@ -26,109 +21,104 @@ export interface LanguageSwitchProps {
onLanguageChange: (lang: LanguageCodeEnum) => void; onLanguageChange: (lang: LanguageCodeEnum) => void;
} }
const styles = (theme: Theme) => const useStyles = makeStyles(theme => ({
createStyles({ arrow: {
arrow: { color: theme.palette.primary.main,
color: theme.palette.primary.main, transition: theme.transitions.duration.standard + "ms"
transition: theme.transitions.duration.standard + "ms" },
}, container: {
container: { paddingBottom: theme.spacing(1)
paddingBottom: theme.spacing.unit },
}, menuContainer: {
menuContainer: { cursor: "pointer",
cursor: "pointer", display: "flex",
display: "flex", justifyContent: "space-between",
justifyContent: "space-between", minWidth: 90,
minWidth: 90, padding: theme.spacing(),
padding: theme.spacing.unit, position: "relative"
position: "relative" },
}, menuItem: {
menuItem: { textAlign: "justify"
textAlign: "justify" },
}, menuPaper: {
menuPaper: { maxHeight: `calc(100vh - ${theme.spacing(2)}px)`,
maxHeight: `calc(100vh - ${theme.spacing.unit * 2}px)`, overflow: "scroll"
overflow: "scroll" },
}, popover: {
popover: { zIndex: 1
zIndex: 1 },
}, rotate: {
rotate: { transform: "rotate(180deg)"
transform: "rotate(180deg)"
}
});
const LanguageSwitch = withStyles(styles, { name: "LanguageSwitch" })(
({
classes,
currentLanguage,
languages,
onLanguageChange
}: LanguageSwitchProps & WithStyles<typeof styles>) => {
const [isExpanded, setExpandedState] = React.useState(false);
const anchor = React.useRef();
return (
<div className={classes.container} ref={anchor}>
<Card
className={classes.menuContainer}
onClick={() => setExpandedState(!isExpanded)}
>
<Typography>{currentLanguage}</Typography>
<ArrowDropDown
className={classNames(classes.arrow, {
[classes.rotate]: isExpanded
})}
/>
</Card>
<Popper
className={classes.popover}
open={isExpanded}
anchorEl={anchor.current}
transition
disablePortal
placement="bottom-end"
>
{({ TransitionProps, placement }) => (
<Grow
{...TransitionProps}
style={{
transformOrigin:
placement === "bottom" ? "right top" : "right bottom"
}}
>
<Paper className={classes.menuPaper}>
<ClickAwayListener
onClickAway={() => setExpandedState(false)}
mouseEvent="onClick"
>
{languages.map(lang => (
<Menu>
<MenuItem
className={classes.menuItem}
onClick={() => {
setExpandedState(false);
onLanguageChange(lang.code);
}}
>
<FormattedMessage
defaultMessage="{languageName} - {languageCode}"
description="button"
values={{
languageCode: lang.code,
languageName: lang.language
}}
/>
</MenuItem>
</Menu>
))}
</ClickAwayListener>
</Paper>
</Grow>
)}
</Popper>
</div>
);
} }
); }));
const LanguageSwitch: React.FC<LanguageSwitchProps> = props => {
const { currentLanguage, languages, onLanguageChange } = props;
const classes = useStyles(props);
const [isExpanded, setExpandedState] = React.useState(false);
const anchor = React.useRef();
return (
<div className={classes.container} ref={anchor}>
<Card
className={classes.menuContainer}
onClick={() => setExpandedState(!isExpanded)}
>
<Typography>{currentLanguage}</Typography>
<ArrowDropDown
className={classNames(classes.arrow, {
[classes.rotate]: isExpanded
})}
/>
</Card>
<Popper
className={classes.popover}
open={isExpanded}
anchorEl={anchor.current}
transition
disablePortal
placement="bottom-end"
>
{({ TransitionProps, placement }) => (
<Grow
{...TransitionProps}
style={{
transformOrigin:
placement === "bottom" ? "right top" : "right bottom"
}}
>
<Paper className={classes.menuPaper}>
<ClickAwayListener
onClickAway={() => setExpandedState(false)}
mouseEvent="onClick"
>
{languages.map(lang => (
<Menu>
<MenuItem
className={classes.menuItem}
onClick={() => {
setExpandedState(false);
onLanguageChange(lang.code);
}}
>
<FormattedMessage
defaultMessage="{languageName} - {languageCode}"
description="button"
values={{
languageCode: lang.code,
languageName: lang.language
}}
/>
</MenuItem>
</Menu>
))}
</ClickAwayListener>
</Paper>
</Grow>
)}
</Popper>
</div>
);
};
LanguageSwitch.displayName = "LanguageSwitch"; LanguageSwitch.displayName = "LanguageSwitch";
export default LanguageSwitch; export default LanguageSwitch;

View file

@ -1,2 +1,2 @@
export { default } from './LanguageSwitch'; export { default } from "./LanguageSwitch";
export * from './LanguageSwitch'; export * from "./LanguageSwitch";

View file

@ -1,49 +1,44 @@
import { import { makeStyles } from "@material-ui/core/styles";
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import Typography, { TypographyProps } from "@material-ui/core/Typography"; import Typography, { TypographyProps } from "@material-ui/core/Typography";
import classNames from "classnames"; import classNames from "classnames";
import React from "react"; import React from "react";
const styles = (theme: Theme) => const useStyles = makeStyles(theme => ({
createStyles({ primary: {
primary: { color: theme.palette.primary.main
color: theme.palette.primary.main },
}, root: {
root: { cursor: "pointer",
cursor: "pointer", display: "inline"
display: "inline" },
}, secondary: {
secondary: { color: theme.palette.primary.main
color: theme.palette.primary.main },
}, underline: {
underline: { textDecoration: "underline"
textDecoration: "underline" }
} }));
});
interface LinkProps interface LinkProps extends React.AnchorHTMLAttributes<HTMLAnchorElement> {
extends React.AnchorHTMLAttributes<HTMLAnchorElement>,
WithStyles<typeof styles> {
color?: "primary" | "secondary"; color?: "primary" | "secondary";
underline?: boolean; underline?: boolean;
typographyProps?: TypographyProps; typographyProps?: TypographyProps;
onClick: () => void; onClick: () => void;
} }
const Link = withStyles(styles, { name: "Link" })( const Link: React.FC<LinkProps> = props => {
({ const {
classes,
className, className,
children, children,
color = "primary", color = "primary",
underline = false, underline = false,
onClick, onClick,
...linkProps ...linkProps
}: LinkProps) => ( } = props;
const classes = useStyles(props);
return (
<Typography <Typography
component="a" component="a"
className={classNames({ className={classNames({
@ -59,7 +54,7 @@ const Link = withStyles(styles, { name: "Link" })(
> >
{children} {children}
</Typography> </Typography>
) );
); };
Link.displayName = "Link"; Link.displayName = "Link";
export default Link; export default Link;

View file

@ -1,4 +1,3 @@
import { Omit } from "@material-ui/core";
import Button from "@material-ui/core/Button"; import Button from "@material-ui/core/Button";
import { import {
createStyles, createStyles,
@ -20,10 +19,10 @@ interface ListFieldState {
const styles = (theme: Theme) => const styles = (theme: Theme) =>
createStyles({ createStyles({
chip: { chip: {
marginBottom: theme.spacing.unit marginBottom: theme.spacing(1)
}, },
chipContainer: { chipContainer: {
marginTop: theme.spacing.unit * 2, marginTop: theme.spacing(2),
width: 552 width: 552
} }
}); });

View file

@ -2,15 +2,13 @@ import React from "react";
interface MenuToggleProps { interface MenuToggleProps {
ariaOwns?: string; ariaOwns?: string;
children: (( children: (props: {
props: { actions: {
actions: { open: () => void;
open: () => void; close: () => void;
close: () => void; };
}; open: boolean;
open: boolean; }) => React.ReactElement<any>;
}
) => React.ReactElement<any>);
} }
interface MenuToggleState { interface MenuToggleState {

View file

@ -1,15 +1,15 @@
import Money from "./Money"; import { IMoney } from "./Money";
export { default } from "./Money"; export { default } from "./Money";
export * from "./Money"; export * from "./Money";
export function addMoney(init: Money, ...args: Money[]): Money { export function addMoney(init: IMoney, ...args: IMoney[]): IMoney {
return { return {
amount: args.reduce((acc, curr) => acc + curr.amount, init.amount), amount: args.reduce((acc, curr) => acc + curr.amount, init.amount),
currency: init.currency currency: init.currency
}; };
} }
export function subtractMoney(init: Money, ...args: Money[]): Money { export function subtractMoney(init: IMoney, ...args: IMoney[]): IMoney {
return { return {
amount: args.reduce((acc, curr) => acc - curr.amount, init.amount), amount: args.reduce((acc, curr) => acc - curr.amount, init.amount),
currency: init.currency currency: init.currency

View file

@ -2,7 +2,7 @@ import React from "react";
import { useIntl } from "react-intl"; import { useIntl } from "react-intl";
import { LocaleConsumer } from "../Locale"; import { LocaleConsumer } from "../Locale";
import IMoney from "../Money"; import { IMoney } from "../Money";
export interface MoneyRangeProps { export interface MoneyRangeProps {
from?: IMoney; from?: IMoney;

View file

@ -1,2 +1,2 @@
export { default } from './MoneyRange'; export { default } from "./MoneyRange";
export * from './MoneyRange'; export * from "./MoneyRange";

Some files were not shown because too many files have changed in this diff Show more