@evershop/evershop 1.0.0-beta.2 → 1.0.0-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +34 -51
- package/package.json +1 -1
- package/src/lib/components/Area.js +3 -3
- package/src/lib/components/form/Form.js +19 -5
- package/src/lib/components/form/fields/Hidden.js +13 -9
- package/src/lib/components/form/fields/Radio.js +1 -1
- package/src/modules/base/graphql/types/Country/Country.graphql +2 -0
- package/src/modules/base/graphql/types/Country/Country.resolvers.js +11 -1
- package/src/modules/catalog/components/product/list/List.js +18 -2
- package/src/modules/catalog/pages/admin/attributeEdit/index.js +2 -2
- package/src/modules/catalog/pages/admin/attributeEdit+attributeNew/General.js +1 -1
- package/src/modules/catalog/pages/admin/attributeGrid/rows/GroupRow.js +2 -1
- package/src/modules/catalog/pages/frontStore/categoryView/CategoryView.js +22 -0
- package/src/modules/catalog/pages/frontStore/categoryView/Filter.js +51 -48
- package/src/modules/catalog/pages/frontStore/categoryView/Filter.scss +43 -8
- package/src/modules/catalog/pages/frontStore/categoryView/General.js +12 -40
- package/src/modules/catalog/pages/frontStore/categoryView/General.scss +5 -0
- package/src/modules/catalog/pages/frontStore/categoryView/Pagination.js +2 -2
- package/src/modules/catalog/pages/frontStore/categoryView/Products.js +5 -5
- package/src/modules/catalog/{components/product/list → pages/frontStore/categoryView}/Sorting.js +31 -17
- package/src/modules/catalog/pages/frontStore/categoryView/[index]filters.js +0 -1
- package/src/modules/catalog/pages/frontStore/homepage/FeaturedProducts.js +1 -1
- package/src/modules/checkout/api/frontStore/addToCart/{addToCart.js → [detectCurrentCart]addToCart.js} +1 -1
- package/src/modules/checkout/api/frontStore/addToCart/[tokenVerify]detectCurrentCart[auth].js +3 -0
- package/src/modules/checkout/api/frontStore/checkoutPlaceOrder/route +1 -1
- package/src/modules/checkout/api/frontStore/checkoutSetContactInfo/saveContactInfo.js +4 -4
- package/src/modules/checkout/api/frontStore/checkoutSetPaymentInfo/savePaymentInfo.js +26 -4
- package/src/modules/checkout/api/frontStore/checkoutSetShipmentInfo/saveShipmentInfo.js +4 -4
- package/src/modules/checkout/components/frontStore/checkout/payment/paymentStep/StepContent.js +43 -83
- package/src/modules/checkout/components/frontStore/checkout/shipment/StepContent.js +1 -2
- package/src/modules/checkout/pages/admin/all/CheckoutMenuGroup.js +1 -1
- package/src/modules/checkout/pages/admin/orderEdit/Payment.js +8 -1
- package/src/modules/checkout/pages/admin/orderEdit/payment/Total.js +1 -0
- package/src/modules/checkout/pages/frontStore/all/[tokenVerify]detectCurrentCart[auth].js +7 -1
- package/src/modules/checkout/pages/frontStore/cart/ShoppingCart.js +1 -0
- package/src/modules/checkout/pages/frontStore/checkout/Checkout.js +1 -1
- package/src/modules/checkout/pages/frontStore/checkout/PaymentStep.js +1 -2
- package/src/modules/checkout/pages/frontStore/checkoutSuccess/CustomerInfo.js +1 -1
- package/src/modules/checkout/services/cart/Cart.js +130 -106
- package/src/modules/checkout/services/cart/DataObject.js +37 -11
- package/src/modules/checkout/services/cart/Item.js +153 -115
- package/src/modules/checkout/services/orderCreator.js +2 -0
- package/src/modules/checkout/services/toPrice.js +1 -0
- package/src/modules/cms/api/admin/imageUpload/[context]multerFile[auth].js +1 -1
- package/src/modules/cms/pages/admin/all/CmsMenuGroup.js +1 -1
- package/src/modules/cms/pages/frontStore/all/Meta.js +1 -0
- package/src/modules/cms/pages/frontStore/all/MobileMenu.js +2 -2
- package/src/modules/cod/api/frontStore/codCapturePayment/[bodyParser]capture.js +51 -0
- package/src/modules/cod/api/frontStore/codCapturePayment/bodyParser.js +5 -0
- package/src/modules/cod/api/frontStore/codCapturePayment/route +2 -0
- package/src/modules/cod/api/frontStore/paymentMethods/[validateCart]registerCod[sendMethods].js +14 -0
- package/src/modules/cod/bootstrap.js +20 -0
- package/src/modules/cod/components/CODLogo.js +5 -0
- package/src/modules/cod/graphql/types/CODSetting/CODSetting.graphql +5 -0
- package/src/modules/cod/graphql/types/CODSetting/CODSetting.resolvers.js +20 -0
- package/src/modules/cod/pages/admin/orderEdit/CaptureButton.js +54 -0
- package/src/modules/cod/pages/admin/paymentSetting/CODSetting.js +59 -0
- package/src/modules/cod/pages/frontStore/checkout/CashOnDelivery.js +70 -0
- package/src/modules/customer/components/Address/AddressForm/AddressForm.js +106 -0
- package/src/modules/customer/components/Address/AddressForm/AddressFormLoadingSkeleton.js +18 -0
- package/src/modules/customer/components/Address/AddressForm/AddressFormLoadingSkeleton.scss +27 -0
- package/src/modules/customer/components/Address/AddressForm/Country.js +36 -0
- package/src/modules/customer/components/Address/AddressForm/Index.js +35 -0
- package/src/modules/customer/components/Address/AddressForm/NameAndTelephone.js +43 -0
- package/src/modules/customer/components/Address/AddressForm/Province.js +42 -0
- package/src/modules/customer/components/Address/AddressForm/ProvinceAndPostcode.js +52 -0
- package/src/modules/customer/{pages/frontStore/address → components/Address}/AddressSummary.js +1 -1
- package/src/modules/customer/pages/admin/all/CustomerMenuGroup.js +1 -1
- package/src/modules/customer/pages/frontStore/all/UserIcon.js +1 -1
- package/src/modules/customer/pages/frontStore/checkout/CustomerInfoStep.js +7 -2
- package/src/modules/graphql/api/frontStore/graphql/[bodyParser]graphql.js +8 -0
- package/src/modules/paypal/api/frontStore/paymentMethods/[validateCart]registerPaypal[sendMethods].js +21 -0
- package/src/modules/paypal/api/frontStore/paypalAuthorizePayment/[bodyParser]authorize.js +76 -0
- package/src/modules/paypal/api/frontStore/paypalAuthorizePayment/bodyParser.js +5 -0
- package/src/modules/paypal/api/frontStore/paypalAuthorizePayment/route +2 -0
- package/src/modules/paypal/api/frontStore/paypalCapturePayment/[bodyParser]capture.js +74 -0
- package/src/modules/paypal/api/frontStore/paypalCapturePayment/bodyParser.js +5 -0
- package/src/modules/paypal/api/frontStore/paypalCapturePayment/route +2 -0
- package/src/modules/paypal/api/frontStore/paypalCreateOrder/[bodyParser]createOrder.js +168 -0
- package/src/modules/paypal/api/frontStore/paypalCreateOrder/bodyParser.js +5 -0
- package/src/modules/paypal/api/frontStore/paypalCreateOrder/route +2 -0
- package/src/modules/paypal/api/frontStore/paypalGetAccessToken/[bodyParser]getAccessToken.js +66 -0
- package/src/modules/paypal/api/frontStore/paypalGetAccessToken/bodyParser.js +5 -0
- package/src/modules/paypal/api/frontStore/paypalGetAccessToken/route +2 -0
- package/src/modules/paypal/bootstrap.js +20 -0
- package/src/modules/paypal/components/PaypalLogo.js +5 -0
- package/src/modules/paypal/graphql/types/PaypalSetting/PaypalSetting.graphql +9 -0
- package/src/modules/paypal/graphql/types/PaypalSetting/PaypalSetting.resolvers.js +90 -0
- package/src/modules/paypal/migration/Version-1.0.0.js +7 -0
- package/src/modules/paypal/pages/admin/paymentSetting/PaypalSetting.js +119 -0
- package/src/modules/paypal/pages/frontStore/checkout/Paypal.js +137 -0
- package/src/modules/paypal/pages/frontStore/paypalCancel/index.js +29 -0
- package/src/modules/paypal/pages/frontStore/paypalCancel/route +2 -0
- package/src/modules/paypal/pages/frontStore/paypalReturn/Error.js +13 -0
- package/src/modules/paypal/pages/frontStore/paypalReturn/index.js +51 -0
- package/src/modules/paypal/pages/frontStore/paypalReturn/route +2 -0
- package/src/modules/paypal/services/getApiBaseUrl.js +5 -0
- package/src/modules/promotion/bootstrap.js +67 -66
- package/src/modules/promotion/pages/admin/all/CouponMenuGroup.js +1 -1
- package/src/modules/promotion/services/{couponValidator.js → CouponValidator.js} +0 -0
- package/src/modules/promotion/services/{discountCalculator.js → DiscountCalculator.js} +18 -17
- package/src/modules/setting/graphql/types/ShippingSetting/ShippingSetting.graphql +1 -1
- package/src/modules/setting/graphql/types/ShippingSetting/ShippingSetting.resolvers.js +5 -5
- package/src/modules/setting/pages/admin/paymentSetting/PaymentSetting.js +1 -1
- package/src/modules/setting/pages/admin/shippingSetting/ShippingSetting.js +4 -4
- package/src/modules/setting/pages/admin/storeSetting/StoreSetting.js +6 -6
- package/src/modules/stripe/bootstrap.js +20 -0
- package/src/modules/stripe/components/StripeLogo.js +5 -0
- package/src/modules/stripe/pages/frontStore/checkout/CheckoutForm.js +20 -26
- package/src/modules/stripe/pages/frontStore/checkout/Stripe.js +87 -0
- package/src/modules/checkout/components/frontStore/checkout/address/AddressBook.js +0 -82
- package/src/modules/checkout/components/frontStore/checkout/address/NewBillingAddressForm.js +0 -36
- package/src/modules/checkout/components/frontStore/checkout/address/NewShippingAddressForm.js +0 -38
- package/src/modules/checkout/components/frontStore/checkout/address/UseShippingAddress.js +0 -64
- package/src/modules/customer/pages/admin/customerGrid/NewCustomertButton.js +0 -17
- package/src/modules/customer/pages/admin/customerNew/index.js +0 -8
- package/src/modules/customer/pages/admin/customerNew/route +0 -2
- package/src/modules/customer/pages/frontStore/address/AddressForm.js +0 -238
- package/src/modules/stripe/index.js +0 -1
- package/src/modules/stripe/pages/frontStore/checkout/PaymentFormContext.js +0 -40
- package/src/modules/stripe/pages/frontStore/checkout/PaymentFormCustom.js +0 -71
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<p> </p>
|
|
2
2
|
<p align="center">
|
|
3
|
-
<h1 align="center">Lightweight
|
|
3
|
+
<h1 align="center">Lightweight And Extendable React E-commerce Platform</h1>
|
|
4
4
|
</p>
|
|
5
5
|
<p align="center">
|
|
6
6
|
<a href="https://evershop.io/docs/development/getting-started/introduction">Documentation</a>
|
|
@@ -15,49 +15,36 @@
|
|
|
15
15
|
</a>
|
|
16
16
|
</p>
|
|
17
17
|
|
|
18
|
-
##
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
url
|
|
40
|
-
}
|
|
41
|
-
url
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
`
|
|
45
|
-
```
|
|
18
|
+
## Introduction
|
|
19
|
+
|
|
20
|
+
EverShop is a GraphQL Based and React ecommerce platform with essential commerce features. Built with React, modular and fully customizable.
|
|
21
|
+
|
|
22
|
+
## Features
|
|
23
|
+
- Catalog management
|
|
24
|
+
- Product management
|
|
25
|
+
- Category management
|
|
26
|
+
- Attribute and attribute group
|
|
27
|
+
- Variant management
|
|
28
|
+
- Custom options
|
|
29
|
+
- Product layered navigation
|
|
30
|
+
- Order management
|
|
31
|
+
- Customer management
|
|
32
|
+
- Customer group
|
|
33
|
+
- Customer address
|
|
34
|
+
- Login, register and my account
|
|
35
|
+
- Advanced coupon management
|
|
36
|
+
- Online payment methods
|
|
37
|
+
- Stripe
|
|
38
|
+
- Paypal
|
|
46
39
|
|
|
47
40
|
## Demo
|
|
48
41
|
|
|
49
42
|
Explore our demo store.
|
|
50
43
|
|
|
51
44
|
<p align="center">
|
|
52
|
-
|
|
53
|
-
</p-->
|
|
54
|
-
<p align="left">
|
|
55
|
-
<a href="https://demo.evershop.io/" target="_blank">
|
|
56
|
-
<img alt="evershop-store-demo" height="35" alt="EverShop Store Demo" src="https://raw.githubusercontent.com/evershopcommerce/evershop/dev/.github/images/evershop-store-front-demo.png"/>
|
|
57
|
-
</a>
|
|
45
|
+
<img alt="EverShop Admin Demo" width="950" src="https://raw.githubusercontent.com/evershopcommerce/evershop/dev/.github/images/evershop-backend-demo.png"/>
|
|
58
46
|
</p>
|
|
59
|
-
|
|
60
|
-
<p align="left">
|
|
47
|
+
<p align="center">
|
|
61
48
|
<a href="https://demo.evershop.io/admin" target="_blank">
|
|
62
49
|
<img alt="evershop-backend-demo" height="35" alt="EverShop Admin Demo" src="https://raw.githubusercontent.com/evershopcommerce/evershop/dev/.github/images/evershop-admin-demo.png"/>
|
|
63
50
|
</a>
|
|
@@ -66,10 +53,14 @@ Explore our demo store.
|
|
|
66
53
|
|
|
67
54
|
Email: demo@gmail.com<br/>
|
|
68
55
|
Password: 123456
|
|
69
|
-
|
|
56
|
+
<p align="center">
|
|
70
57
|
<img alt="EverShop Store Demo" width="950" src="https://raw.githubusercontent.com/evershopcommerce/evershop/dev/.github/images/evershop-product-detail.png"/>
|
|
71
|
-
</p
|
|
72
|
-
|
|
58
|
+
</p>
|
|
59
|
+
<p align="center">
|
|
60
|
+
<a href="https://demo.evershop.io/" target="_blank">
|
|
61
|
+
<img alt="evershop-store-demo" height="35" alt="EverShop Store Demo" src="https://raw.githubusercontent.com/evershopcommerce/evershop/dev/.github/images/evershop-store-front-demo.png"/>
|
|
62
|
+
</a>
|
|
63
|
+
</p>
|
|
73
64
|
|
|
74
65
|
## Quick Start
|
|
75
66
|
|
|
@@ -85,22 +76,14 @@ npx create-evershop-app my-app --playAround
|
|
|
85
76
|
|
|
86
77
|
- [Theme development](https://evershop.io/docs/development/theme/theme-overview).
|
|
87
78
|
|
|
88
|
-
|
|
89
|
-
- Catalog management(with product attribute, custom option and variants)
|
|
90
|
-
- Order management
|
|
91
|
-
- Customer management
|
|
92
|
-
- Coupon management
|
|
93
|
-
- Tax
|
|
94
|
-
- Online payment (For now using Stripe)
|
|
95
|
-
- Basic CMS pages management
|
|
96
|
-
- Easy to customize by developing extensions
|
|
79
|
+
|
|
97
80
|
|
|
98
81
|
## Support
|
|
99
82
|
|
|
100
83
|
If you like my work, feel free to:
|
|
101
84
|
|
|
102
|
-
- ⭐ this repository. It
|
|
103
|
-
- [][tweet] about EverShop
|
|
85
|
+
- ⭐ this repository. It helps.
|
|
86
|
+
- [][tweet] about EverShop. Please accept my gratitude.
|
|
104
87
|
|
|
105
88
|
[tweet]: https://twitter.com/intent/tweet?url=https%3A%2F%2Fgithub.com%2Fevershopcommerce%2Fevershop&text=Awesome%20React%20Ecommerce%20Project&hashtags=react,ecommerce,expressjs,graphql
|
|
106
89
|
### Ask a question about EverShop
|
package/package.json
CHANGED
|
@@ -34,7 +34,7 @@ function Area(props) {
|
|
|
34
34
|
|
|
35
35
|
return (
|
|
36
36
|
<WrapperComponent {...areaWrapperProps}>
|
|
37
|
-
{areaComponents.map((w) => {
|
|
37
|
+
{areaComponents.map((w, index) => {
|
|
38
38
|
const C = w.component.default;
|
|
39
39
|
const id = w.id;
|
|
40
40
|
const propsMap = context.propsMap;
|
|
@@ -48,8 +48,8 @@ function Area(props) {
|
|
|
48
48
|
if (w.props) {
|
|
49
49
|
Object.assign(componentProps, w.props);
|
|
50
50
|
}
|
|
51
|
-
if (typeof C === 'string') return <C key={
|
|
52
|
-
return <C key={
|
|
51
|
+
if (typeof C === 'string') return <C key={index} {...componentProps} />;
|
|
52
|
+
return <C key={index} areaProps={props} {...componentProps} />;
|
|
53
53
|
})}
|
|
54
54
|
</WrapperComponent>
|
|
55
55
|
);
|
|
@@ -50,10 +50,22 @@ export function Form(props) {
|
|
|
50
50
|
const errors = {};
|
|
51
51
|
fields.forEach((f) => {
|
|
52
52
|
f.validationRules.forEach((r) => {
|
|
53
|
-
|
|
54
|
-
if
|
|
55
|
-
if (
|
|
56
|
-
|
|
53
|
+
let rule;
|
|
54
|
+
// Check if r is a string or an object
|
|
55
|
+
if (typeof r === 'string') {
|
|
56
|
+
rule = r;
|
|
57
|
+
} else {
|
|
58
|
+
rule = r.rule;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const ruleValidator = validator.getRule(rule);
|
|
62
|
+
if (ruleValidator === undefined) return;
|
|
63
|
+
if (!ruleValidator.handler.call(fields, f.value)) {
|
|
64
|
+
if (r.message) {
|
|
65
|
+
errors[f.name] = r.message;
|
|
66
|
+
} else {
|
|
67
|
+
errors[f.name] = ruleValidator.errorMessage;
|
|
68
|
+
}
|
|
57
69
|
}
|
|
58
70
|
});
|
|
59
71
|
});
|
|
@@ -119,7 +131,9 @@ export function Form(props) {
|
|
|
119
131
|
// Get the first element with the name of the field with error
|
|
120
132
|
const firstElementWithError = document.getElementsByName(firstFieldWithError)[0];
|
|
121
133
|
// Focus on the first element with error
|
|
122
|
-
firstElementWithError
|
|
134
|
+
if (firstElementWithError) {
|
|
135
|
+
firstElementWithError.focus();
|
|
136
|
+
}
|
|
123
137
|
}
|
|
124
138
|
} catch (error) {
|
|
125
139
|
if (onError) {
|
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
import PropTypes from 'prop-types';
|
|
2
2
|
import React from 'react';
|
|
3
|
+
import Error from './Error';
|
|
3
4
|
|
|
4
|
-
export function Hidden({ name, value }) {
|
|
5
|
+
export function Hidden({ name, value, error }) {
|
|
5
6
|
return (
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
7
|
+
<>
|
|
8
|
+
{error && <Error error={error} />}
|
|
9
|
+
<input
|
|
10
|
+
type="text"
|
|
11
|
+
id={name}
|
|
12
|
+
name={name}
|
|
13
|
+
value={value}
|
|
14
|
+
readOnly
|
|
15
|
+
style={{ display: 'none' }}
|
|
16
|
+
/>
|
|
17
|
+
</>
|
|
14
18
|
);
|
|
15
19
|
}
|
|
16
20
|
|
|
@@ -66,7 +66,7 @@ Radio.propTypes = {
|
|
|
66
66
|
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
|
67
67
|
text: PropTypes.string
|
|
68
68
|
})).isRequired,
|
|
69
|
-
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number])
|
|
69
|
+
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number])
|
|
70
70
|
};
|
|
71
71
|
|
|
72
72
|
Radio.defaultProps = {
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
const { contries } = require("../../../../../lib/locale/countries")
|
|
1
|
+
const { contries } = require("../../../../../lib/locale/countries");
|
|
2
|
+
const { getSetting } = require("../../../../setting/services/setting");
|
|
3
|
+
const { provinces } = require("../../../../../lib/locale/provinces");
|
|
2
4
|
|
|
3
5
|
module.exports = {
|
|
4
6
|
Query: {
|
|
@@ -9,6 +11,11 @@ module.exports = {
|
|
|
9
11
|
} else {
|
|
10
12
|
return contries.filter((c) => list.includes(c.code));
|
|
11
13
|
}
|
|
14
|
+
},
|
|
15
|
+
allowedCountries: async () => {
|
|
16
|
+
const allowedCountries = await getSetting("allowedCountries", '["US"]');
|
|
17
|
+
let list = JSON.parse(allowedCountries);
|
|
18
|
+
return contries.filter((c) => list.includes(c.code));
|
|
12
19
|
}
|
|
13
20
|
},
|
|
14
21
|
Country: {
|
|
@@ -26,6 +33,9 @@ module.exports = {
|
|
|
26
33
|
} else {
|
|
27
34
|
return country;
|
|
28
35
|
}
|
|
36
|
+
},
|
|
37
|
+
provinces: (country) => {
|
|
38
|
+
return provinces.filter((p) => p.countryCode === country.code);
|
|
29
39
|
}
|
|
30
40
|
}
|
|
31
41
|
}
|
|
@@ -6,7 +6,7 @@ import { Price } from './item/Price';
|
|
|
6
6
|
import Area from '../../../../../lib/components/Area';
|
|
7
7
|
import { get } from '../../../../../lib/util/get';
|
|
8
8
|
|
|
9
|
-
export default function ProductList({ products = [] }) {
|
|
9
|
+
export default function ProductList({ products = [], countPerRow = 3 }) {
|
|
10
10
|
if (products.length === 0) {
|
|
11
11
|
return (
|
|
12
12
|
<div className="product-list">
|
|
@@ -14,8 +14,24 @@ export default function ProductList({ products = [] }) {
|
|
|
14
14
|
</div>
|
|
15
15
|
);
|
|
16
16
|
}
|
|
17
|
+
|
|
18
|
+
let className;
|
|
19
|
+
switch (countPerRow) {
|
|
20
|
+
case 3:
|
|
21
|
+
className = 'grid grid-cols-2 md:grid-cols-3 gap-2';
|
|
22
|
+
break;
|
|
23
|
+
case 4:
|
|
24
|
+
className = 'grid grid-cols-2 md:grid-cols-4 gap-2';
|
|
25
|
+
break;
|
|
26
|
+
case 5:
|
|
27
|
+
className = 'grid grid-cols-2 md:grid-cols-5 gap-2';
|
|
28
|
+
break;
|
|
29
|
+
default:
|
|
30
|
+
className = 'grid grid-cols-2 md:grid-cols-3 gap-2';
|
|
31
|
+
}
|
|
32
|
+
|
|
17
33
|
return (
|
|
18
|
-
<div className=
|
|
34
|
+
<div className={className}>
|
|
19
35
|
{
|
|
20
36
|
products.map((p) => (
|
|
21
37
|
<Area
|
|
@@ -15,8 +15,8 @@ module.exports = async (request, response, delegate, next) => {
|
|
|
15
15
|
} else {
|
|
16
16
|
setContextValue(request, 'attributeId', attribute.attribute_id);
|
|
17
17
|
setContextValue(request, 'pageInfo', {
|
|
18
|
-
title: attribute.
|
|
19
|
-
description: attribute.
|
|
18
|
+
title: attribute.attribute_name,
|
|
19
|
+
description: attribute.attribute_name
|
|
20
20
|
});
|
|
21
21
|
next();
|
|
22
22
|
}
|
|
@@ -21,11 +21,12 @@ export default function GroupRow({ groups, saveAttributeGroupUrl }) {
|
|
|
21
21
|
onSuccess={() => {
|
|
22
22
|
location.reload();
|
|
23
23
|
}}
|
|
24
|
+
isJSON={true}
|
|
24
25
|
>
|
|
25
26
|
<Field
|
|
26
27
|
formId="group-edit"
|
|
27
28
|
type="text"
|
|
28
|
-
name="
|
|
29
|
+
name="group_name"
|
|
29
30
|
value={group.groupName}
|
|
30
31
|
/>
|
|
31
32
|
<Field
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import Area from '../../../../../lib/components/Area';
|
|
3
|
+
|
|
4
|
+
export default function CategoryView() {
|
|
5
|
+
return (
|
|
6
|
+
<div className="page-width grid grid-cols-1 md:grid-cols-4 gap-2">
|
|
7
|
+
<Area
|
|
8
|
+
id="leftColumn"
|
|
9
|
+
className="md:col-span-1"
|
|
10
|
+
/>
|
|
11
|
+
<Area
|
|
12
|
+
id="rightColumn"
|
|
13
|
+
className="md:col-span-3"
|
|
14
|
+
/>
|
|
15
|
+
</div>
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const layout = {
|
|
20
|
+
areaId: 'content',
|
|
21
|
+
sortOrder: 10
|
|
22
|
+
}
|
|
@@ -2,7 +2,6 @@ import PropTypes from 'prop-types';
|
|
|
2
2
|
import React, { useState } from 'react';
|
|
3
3
|
import Area from '../../../../../lib/components/Area';
|
|
4
4
|
import { get } from '../../../../../lib/util/get';
|
|
5
|
-
import Sorting from '../../../components/product/list/Sorting';
|
|
6
5
|
import './Filter.scss';
|
|
7
6
|
|
|
8
7
|
function Price({
|
|
@@ -109,10 +108,16 @@ function Attributes({ currentFilters, attributes, updateFilter }) {
|
|
|
109
108
|
e.preventDefault();
|
|
110
109
|
if (isChecked === true) {
|
|
111
110
|
updateFilter(
|
|
112
|
-
currentFilters.
|
|
113
|
-
(f) =>
|
|
114
|
-
|
|
115
|
-
|
|
111
|
+
currentFilters.map(
|
|
112
|
+
(f) => {
|
|
113
|
+
if (f.key !== attributeCode) {
|
|
114
|
+
return f
|
|
115
|
+
} else {
|
|
116
|
+
const value = f.value.split(',').filter((v) => parseInt(v) !== parseInt(optionId));
|
|
117
|
+
return { key: attributeCode, value: value.join(',') };
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
).filter((f) => f.value !== '')
|
|
116
121
|
);
|
|
117
122
|
} else {
|
|
118
123
|
updateFilter(currentFilters.concat({ key: attributeCode, value: optionId }));
|
|
@@ -124,21 +129,31 @@ function Attributes({ currentFilters, attributes, updateFilter }) {
|
|
|
124
129
|
{attributes.map((a) => (
|
|
125
130
|
<div key={a.attributeCode}>
|
|
126
131
|
<div className="filter-item-title"><span className="font-medium">{a.attributeName}</span></div>
|
|
127
|
-
<ul className="
|
|
132
|
+
<ul className="filter-option-list">
|
|
128
133
|
{a.options.map((o) => {
|
|
129
134
|
const isChecked = currentFilters.find(
|
|
130
135
|
(f) => f.key === a.attributeCode
|
|
131
|
-
&&
|
|
136
|
+
&& f.value.split(',').includes(o.optionId.toString())
|
|
132
137
|
);
|
|
133
138
|
return (
|
|
134
139
|
<li key={o.optionId} className="mt-05 mr-05">
|
|
135
|
-
<
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
140
|
+
<a href="#" className='flex justify-start items-center' onClick={(e) => onChange(e, a.attributeCode, o.optionId, !!isChecked)}>
|
|
141
|
+
{isChecked && <svg width="24px" height="24px" viewBox="0 0 24 24" >
|
|
142
|
+
<g stroke="none" strokeWidth="1" fill="none" fillRule="evenodd">
|
|
143
|
+
<g fill="#212121" fillRule="nonzero">
|
|
144
|
+
<path d="M18,3 C19.6568542,3 21,4.34314575 21,6 L21,18 C21,19.6568542 19.6568542,21 18,21 L6,21 C4.34314575,21 3,19.6568542 3,18 L3,6 C3,4.34314575 4.34314575,3 6,3 L18,3 Z M16.4696699,7.96966991 L10,14.4393398 L7.53033009,11.9696699 C7.23743687,11.6767767 6.76256313,11.6767767 6.46966991,11.9696699 C6.1767767,12.2625631 6.1767767,12.7374369 6.46966991,13.0303301 L9.46966991,16.0303301 C9.76256313,16.3232233 10.2374369,16.3232233 10.5303301,16.0303301 L17.5303301,9.03033009 C17.8232233,8.73743687 17.8232233,8.26256313 17.5303301,7.96966991 C17.2374369,7.6767767 16.7625631,7.6767767 16.4696699,7.96966991 Z" ></path>
|
|
145
|
+
</g>
|
|
146
|
+
</g>
|
|
147
|
+
</svg>}
|
|
148
|
+
{!isChecked && <svg width="24px" height="24px" viewBox="0 0 24 24">
|
|
149
|
+
<g stroke="none" strokeWidth="1" fill="none" fillRule="evenodd">
|
|
150
|
+
<g fill="#212121" fillRule="nonzero">
|
|
151
|
+
<path d="M5.75,3 L18.25,3 C19.7687831,3 21,4.23121694 21,5.75 L21,18.25 C21,19.7687831 19.7687831,21 18.25,21 L5.75,21 C4.23121694,21 3,19.7687831 3,18.25 L3,5.75 C3,4.23121694 4.23121694,3 5.75,3 Z M5.75,4.5 C5.05964406,4.5 4.5,5.05964406 4.5,5.75 L4.5,18.25 C4.5,18.9403559 5.05964406,19.5 5.75,19.5 L18.25,19.5 C18.9403559,19.5 19.5,18.9403559 19.5,18.25 L19.5,5.75 C19.5,5.05964406 18.9403559,4.5 18.25,4.5 L5.75,4.5 Z"></path>
|
|
152
|
+
</g>
|
|
153
|
+
</g>
|
|
154
|
+
</svg>}
|
|
155
|
+
<span className='filter-option'>{o.optionText}</span>
|
|
156
|
+
</a>
|
|
142
157
|
</li>
|
|
143
158
|
);
|
|
144
159
|
})}
|
|
@@ -162,8 +177,7 @@ Attributes.propTypes = {
|
|
|
162
177
|
};
|
|
163
178
|
|
|
164
179
|
export default function Filter({ category: { availableFilters, products: { currentFilters } } }) {
|
|
165
|
-
|
|
166
|
-
const [filtering, setFiltering] = useState(false);
|
|
180
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
167
181
|
|
|
168
182
|
const updateFilter = (newFilters) => {
|
|
169
183
|
const currentUrl = window.location.href;
|
|
@@ -189,30 +203,14 @@ export default function Filter({ category: { availableFilters, products: { curre
|
|
|
189
203
|
};
|
|
190
204
|
|
|
191
205
|
return (
|
|
192
|
-
|
|
193
|
-
<div className=
|
|
194
|
-
<div className="
|
|
195
|
-
<div className="
|
|
196
|
-
|
|
197
|
-
<
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
</svg>
|
|
201
|
-
<span className="font-light">FILTER BY</span>
|
|
202
|
-
</button>
|
|
203
|
-
)}
|
|
204
|
-
{filtering === true && (
|
|
205
|
-
<div className="close-filter mb-1">
|
|
206
|
-
<button type="button" onClick={(e) => { e.preventDefault(); setFiltering(false); }} className="link-button">
|
|
207
|
-
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
|
|
208
|
-
<path fillRule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clipRule="evenodd" />
|
|
209
|
-
</svg>
|
|
210
|
-
</button>
|
|
211
|
-
</div>
|
|
212
|
-
)}
|
|
213
|
-
</div>
|
|
214
|
-
{filtering === true && (
|
|
215
|
-
<div className="filter-table md:grid md:grid-cols-4 gap-2">
|
|
206
|
+
<>
|
|
207
|
+
<div className={`product-filter-tool hidden md:block ${isOpen ? 'opening' : 'closed'}`}>
|
|
208
|
+
<div className="">
|
|
209
|
+
<div className="self-center">
|
|
210
|
+
<div className="filter-heading">
|
|
211
|
+
<span className="font-bold ">SHOP BY</span>
|
|
212
|
+
</div>
|
|
213
|
+
<div className='mt-1 grid grid-cols-1 gap-2'>
|
|
216
214
|
<Area
|
|
217
215
|
id="productFilter"
|
|
218
216
|
updateFilter={updateFilter}
|
|
@@ -229,20 +227,25 @@ export default function Filter({ category: { availableFilters, products: { curre
|
|
|
229
227
|
]}
|
|
230
228
|
/>
|
|
231
229
|
</div>
|
|
232
|
-
)}
|
|
233
|
-
</div>
|
|
234
|
-
{filtering === false && (
|
|
235
|
-
<div>
|
|
236
|
-
<Sorting currentFilters={currentFilters} />
|
|
237
230
|
</div>
|
|
238
|
-
|
|
231
|
+
</div>
|
|
232
|
+
<a className='filter-closer flex md:hidden' href="#" onClick={(e) => { e.preventDefault(); setIsOpen(!isOpen) }}>
|
|
233
|
+
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="w-6 h-6">
|
|
234
|
+
<path strokeLinecap="round" strokeLinejoin="round" d="M10.5 6h9.75M10.5 6a1.5 1.5 0 11-3 0m3 0a1.5 1.5 0 10-3 0M3.75 6H7.5m3 12h9.75m-9.75 0a1.5 1.5 0 01-3 0m3 0a1.5 1.5 0 00-3 0m-3.75 0H7.5m9-6h3.75m-3.75 0a1.5 1.5 0 01-3 0m3 0a1.5 1.5 0 00-3 0m-9.75 0h9.75" />
|
|
235
|
+
</svg>
|
|
236
|
+
</a>
|
|
239
237
|
</div>
|
|
240
|
-
|
|
238
|
+
<a className='filter-opener flex md:hidden' href="#" onClick={(e) => { e.preventDefault(); setIsOpen(!isOpen) }}>
|
|
239
|
+
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="w-6 h-6">
|
|
240
|
+
<path strokeLinecap="round" strokeLinejoin="round" d="M10.5 6h9.75M10.5 6a1.5 1.5 0 11-3 0m3 0a1.5 1.5 0 10-3 0M3.75 6H7.5m3 12h9.75m-9.75 0a1.5 1.5 0 01-3 0m3 0a1.5 1.5 0 00-3 0m-3.75 0H7.5m9-6h3.75m-3.75 0a1.5 1.5 0 01-3 0m3 0a1.5 1.5 0 00-3 0m-9.75 0h9.75" />
|
|
241
|
+
</svg>
|
|
242
|
+
</a>
|
|
243
|
+
</>
|
|
241
244
|
);
|
|
242
245
|
}
|
|
243
246
|
|
|
244
247
|
export const layout = {
|
|
245
|
-
areaId: "
|
|
248
|
+
areaId: "leftColumn",
|
|
246
249
|
sortOrder: 1
|
|
247
250
|
}
|
|
248
251
|
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
.product-filter-tool {
|
|
2
2
|
padding-top: 1rem;
|
|
3
3
|
padding-bottom: 1rem;
|
|
4
|
-
border-top: 1px solid var(--divider);
|
|
5
|
-
border-bottom: 1px solid var(--divider);
|
|
6
4
|
margin-bottom: 1.5rem;
|
|
7
5
|
.filter-item-title {
|
|
8
6
|
margin-bottom: 0.5rem;
|
|
@@ -16,13 +14,8 @@
|
|
|
16
14
|
}
|
|
17
15
|
}
|
|
18
16
|
.filter-option {
|
|
19
|
-
|
|
20
|
-
display: block;
|
|
21
|
-
padding: 0.5rem 1.5rem;
|
|
17
|
+
padding: 0rem 0.8rem;
|
|
22
18
|
border-radius: 2px;
|
|
23
|
-
&.checked {
|
|
24
|
-
border: 2px solid var(--text);
|
|
25
|
-
}
|
|
26
19
|
}
|
|
27
20
|
|
|
28
21
|
.filter-heading {
|
|
@@ -97,3 +90,45 @@ input[type="range"]:nth-child(1)::-webkit-slider-thumb {
|
|
|
97
90
|
float: right;
|
|
98
91
|
margin-right: -5px;
|
|
99
92
|
}
|
|
93
|
+
|
|
94
|
+
.filter-opener, .filter-closer {
|
|
95
|
+
position: fixed;
|
|
96
|
+
bottom: 20px;
|
|
97
|
+
left: 20px;
|
|
98
|
+
width: 35px;
|
|
99
|
+
height: 35px;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.filter-opener, .filter-closer {
|
|
103
|
+
z-index: 998;
|
|
104
|
+
background: #fff;
|
|
105
|
+
border-radius: 50%;
|
|
106
|
+
box-shadow: 0 0 10px rgba(0,0,0,0.2);
|
|
107
|
+
justify-content: center;
|
|
108
|
+
align-items: center;
|
|
109
|
+
svg {
|
|
110
|
+
width: 20px;
|
|
111
|
+
height: 20px;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
@media (max-width: 639px) {
|
|
116
|
+
.product-filter-tool.opening {
|
|
117
|
+
display: block;
|
|
118
|
+
position: fixed;
|
|
119
|
+
// Make full screen
|
|
120
|
+
top: 0;
|
|
121
|
+
left: 0;
|
|
122
|
+
right: 0;
|
|
123
|
+
bottom: 0;
|
|
124
|
+
z-index: 999;
|
|
125
|
+
background-color: #fff;
|
|
126
|
+
padding: 20px;
|
|
127
|
+
box-sizing: border-box;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.filter-opener,
|
|
131
|
+
.filter-closer {
|
|
132
|
+
display: flex;
|
|
133
|
+
}
|
|
134
|
+
}
|