@evershop/evershop 1.2.0 → 1.2.1

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.
@@ -17,6 +17,9 @@ const { error } = require('@evershop/evershop/src/lib/log/logger');
17
17
  const {
18
18
  getEnabledWidgets
19
19
  } = require('@evershop/evershop/src/lib/util/getEnabledWidgets');
20
+ const {
21
+ generateComponentKey
22
+ } = require('@evershop/evershop/src/lib/webpack/util/keyGenerator');
20
23
  /**
21
24
  * Only pass the page routes, not api routes
22
25
  */
@@ -50,9 +53,9 @@ module.exports.buildEntry = async function buildEntry(
50
53
  .replace(/(['"])?([a-zA-Z0-9_]+)(['"])?:/g, '"$2": ');
51
54
  try {
52
55
  const layout = JSON5.parse(check);
53
- const id = Buffer.from(
56
+ const id = generateComponentKey(
54
57
  module.replace(CONSTANTS.ROOTPATH, '')
55
- ).toString('base64');
58
+ );
56
59
  areas[layout.areaId] = areas[layout.areaId] || {};
57
60
  areas[layout.areaId][id] = {
58
61
  id,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@evershop/evershop",
3
- "version": "1.2.0",
3
+ "version": "1.2.1",
4
4
  "description": "The React Ecommerce platform. Built with React and Postgres. Open-source and free. Fast and customizable.",
5
5
  "files": [
6
6
  "bin",
@@ -150,17 +150,19 @@ RenderEditorJS.propTypes = {
150
150
  export default function Editor({ rows }) {
151
151
  return (
152
152
  <div className="editor__html">
153
- {rows.map((row) => {
153
+ {rows.map((row, index) => {
154
154
  const rowClasses = getRowClasses(row.size);
155
155
  return (
156
156
  <div
157
157
  className={`row__container mt-12 grid md:${rowClasses} grid-cols-1 gap-8`}
158
+ key={index}
158
159
  >
159
- {row.columns.map((column) => {
160
+ {row.columns.map((column, index) => {
160
161
  const columnClasses = getColumnClasses(column.size);
161
162
  return (
162
163
  <div
163
164
  className={`column__container md:${columnClasses} col-span-1`}
165
+ key={index}
164
166
  >
165
167
  {column.data?.blocks && (
166
168
  <RenderEditorJS blocks={column.data?.blocks} />
@@ -178,10 +180,10 @@ export default function Editor({ rows }) {
178
180
  Editor.propTypes = {
179
181
  rows: PropTypes.arrayOf(
180
182
  PropTypes.shape({
181
- size: PropTypes.string.isRequired,
183
+ size: PropTypes.number.isRequired,
182
184
  columns: PropTypes.arrayOf(
183
185
  PropTypes.shape({
184
- size: PropTypes.string.isRequired,
186
+ size: PropTypes.number.isRequired,
185
187
  // eslint-disable-next-line react/forbid-prop-types
186
188
  data: PropTypes.object
187
189
  })
@@ -27,3 +27,7 @@ body .codex-editor {
27
27
  #rows .draggable-source--is-dragging>* {
28
28
  visibility: hidden;
29
29
  }
30
+
31
+ .ce-rawtool__textarea {
32
+ z-index: 0;
33
+ }
@@ -63,7 +63,7 @@ export default function Quantity({ qty, api }) {
63
63
  >
64
64
  {isLoading && (
65
65
  <svg
66
- ariaHidden="true"
66
+ aria-hidden="true"
67
67
  focusable="false"
68
68
  role="presentation"
69
69
  className="spinner"
@@ -83,7 +83,7 @@ export default function Quantity({ qty, api }) {
83
83
  {!isLoading && (
84
84
  <svg
85
85
  xmlns="http://www.w3.org/2000/svg"
86
- ariaHidden="true"
86
+ aria-hidden="true"
87
87
  focusable="false"
88
88
  role="presentation"
89
89
  className="icon icon-minus"
@@ -99,7 +99,7 @@ export default function Quantity({ qty, api }) {
99
99
  </svg>
100
100
  )}
101
101
  </button>
102
- <input type="text" value={quantity} />
102
+ <input type="text" value={quantity} readOnly />
103
103
  <button
104
104
  className="flex justify-center items-center"
105
105
  onClick={() => updateQuantity(quantity + 1)}
@@ -108,7 +108,7 @@ export default function Quantity({ qty, api }) {
108
108
  >
109
109
  {isLoading && (
110
110
  <svg
111
- ariaHidden="true"
111
+ aria-hidden="true"
112
112
  focusable="false"
113
113
  role="presentation"
114
114
  className="spinner"
@@ -128,7 +128,7 @@ export default function Quantity({ qty, api }) {
128
128
  {!isLoading && (
129
129
  <svg
130
130
  xmlns="http://www.w3.org/2000/svg"
131
- ariaHidden="true"
131
+ aria-hidden="true"
132
132
  focusable="false"
133
133
  role="presentation"
134
134
  className="icon icon-plus"
@@ -1,5 +1,6 @@
1
1
  const isResolvable = require('is-resolvable');
2
2
  const { getConfig } = require('./getConfig');
3
+ const { generateComponentKey } = require('../webpack/util/keyGenerator');
3
4
 
4
5
  module.exports = exports = {};
5
6
 
@@ -21,7 +22,12 @@ exports.getEnabledWidgets = function getEnabledWidgets() {
21
22
  );
22
23
  }
23
24
  if (configuredWidgets[widget].enabled === true) {
24
- widgets.push({ ...configuredWidgets[widget], type: widget });
25
+ widgets.push({
26
+ ...configuredWidgets[widget],
27
+ type: widget,
28
+ settingComponentKey: generateComponentKey(setting_component),
29
+ componentKey: generateComponentKey(component)
30
+ });
25
31
  }
26
32
  });
27
33
  return widgets;
@@ -4,6 +4,7 @@ const JSON5 = require('json5');
4
4
  const { CONSTANTS } = require('../../helpers');
5
5
  const { error } = require('../../log/logger');
6
6
  const { getEnabledWidgets } = require('../../util/getEnabledWidgets');
7
+ const { generateComponentKey } = require('../util/keyGenerator');
7
8
 
8
9
  /* eslint-disable no-multi-assign */
9
10
  /* eslint-disable global-require */
@@ -29,9 +30,7 @@ module.exports = exports = function AreaLoader(c) {
29
30
  .replace(/(['"])?([a-zA-Z0-9_]+)(['"])?:/g, '"$2": ');
30
31
  try {
31
32
  const layout = JSON5.parse(check);
32
- const id = Buffer.from(module.replace(CONSTANTS.ROOTPATH, '')).toString(
33
- 'base64'
34
- );
33
+ const id = generateComponentKey(module.replace(CONSTANTS.ROOTPATH, ''));
35
34
  areas[layout.areaId] = areas[layout.areaId] || {};
36
35
  areas[layout.areaId][id] = {
37
36
  id,
@@ -0,0 +1,9 @@
1
+ const crypto = require('crypto');
2
+
3
+ function generateComponentKey(text) {
4
+ return crypto.createHash('md5').update(text).digest('hex');
5
+ }
6
+
7
+ module.exports = exports = {
8
+ generateComponentKey
9
+ };
@@ -4,6 +4,7 @@ const JSON5 = require('json5');
4
4
  const isResolvable = require('is-resolvable');
5
5
  const { CONSTANTS } = require('../../helpers');
6
6
  const { parseGraphqlByFile } = require('./parseGraphqlByFile');
7
+ const { generateComponentKey } = require('./keyGenerator');
7
8
 
8
9
  module.exports.parseGraphql = function parseGraphql(modules) {
9
10
  let inUsedFragments = [];
@@ -24,12 +25,12 @@ module.exports.parseGraphql = function parseGraphql(modules) {
24
25
  // If the module is resolvable, get the apsolute path
25
26
  if (!fs.existsSync(module)) {
26
27
  modulePath = require.resolve(module);
27
- moduleKey = Buffer.from(module).toString('base64');
28
+ moduleKey = generateComponentKey(module);
28
29
  } else {
29
30
  modulePath = module;
30
- moduleKey = Buffer.from(
31
+ moduleKey = generateComponentKey(
31
32
  modulePath.replace(CONSTANTS.ROOTPATH, '')
32
- ).toString('base64');
33
+ );
33
34
  }
34
35
  const moduleGraphqlData = parseGraphqlByFile(modulePath);
35
36
  queries[moduleKey] = moduleGraphqlData.query.source;
@@ -41,6 +41,26 @@ module.exports = async (request, response, delegate, next) => {
41
41
  isApi: route.isApi,
42
42
  isAdmin: route.isAdmin
43
43
  };
44
+ let widgetInstances;
45
+ // Check if we are in the test mode
46
+ if (process.env.NODE_ENV === 'test') {
47
+ widgetInstances = [];
48
+ } else {
49
+ widgetInstances = await loadWidgetInstances(request);
50
+ }
51
+ widgetInstances = widgetInstances.map((widget) => {
52
+ const newWidget = {
53
+ sortOrder: widget.sortOrder,
54
+ areaId: widget.areaId,
55
+ type: widget.type
56
+ };
57
+ newWidget.id = `e${widget.uuid.replace(/-/g, '')}`;
58
+ if (route.isAdmin) {
59
+ newWidget.areaId = 'widget_setting_form';
60
+ }
61
+ return newWidget;
62
+ });
63
+ response.locals.widgets = widgetInstances;
44
64
  if (
45
65
  (isDevelopmentMode() &&
46
66
  request.query &&
@@ -51,30 +71,11 @@ module.exports = async (request, response, delegate, next) => {
51
71
  success: true,
52
72
  eContext: {
53
73
  graphqlResponse: get(response, 'locals.graphqlResponse', {}),
54
- propsMap: get(response, 'locals.propsMap', {})
74
+ propsMap: get(response, 'locals.propsMap', {}),
75
+ widgets: widgetInstances
55
76
  }
56
77
  });
57
78
  } else {
58
- let widgetInstances;
59
- // Check if we are in the test mode
60
- if (process.env.NODE_ENV === 'test') {
61
- widgetInstances = [];
62
- } else {
63
- widgetInstances = await loadWidgetInstances(request);
64
- }
65
- widgetInstances = widgetInstances.map((widget) => {
66
- const newWidget = {
67
- sortOrder: widget.sortOrder,
68
- areaId: widget.areaId,
69
- type: widget.type
70
- };
71
- newWidget.id = `e${widget.uuid.replace(/-/g, '')}`;
72
- if (route.isAdmin) {
73
- newWidget.areaId = 'widget_setting_form';
74
- }
75
- return newWidget;
76
- });
77
- response.locals.widgets = widgetInstances;
78
79
  render(request, response);
79
80
  }
80
81
  }
@@ -254,7 +254,7 @@ export const layout = {
254
254
  };
255
255
 
256
256
  export const query = `
257
- query Query {
257
+ query Query ($filters: [FilterInput!]) {
258
258
  product(id: getContextValue("productId", null)) {
259
259
  groupId
260
260
  variantGroupId
@@ -264,7 +264,7 @@ export const query = `
264
264
  optionText
265
265
  }
266
266
  },
267
- groups: attributeGroups {
267
+ groups: attributeGroups(filters: $filters) {
268
268
  items {
269
269
  groupId: attributeGroupId
270
270
  groupName
@@ -285,3 +285,8 @@ export const query = `
285
285
  }
286
286
  }
287
287
  `;
288
+
289
+ export const variables = `
290
+ {
291
+ filters: [{ key: "limit", operation: 'eq', value: 1000 }]
292
+ }`;
@@ -15,7 +15,18 @@ export default function Description({ product: { description } }) {
15
15
 
16
16
  Description.propTypes = {
17
17
  product: PropTypes.shape({
18
- description: PropTypes.string
18
+ description: PropTypes.arrayOf(
19
+ PropTypes.shape({
20
+ size: PropTypes.number.isRequired,
21
+ columns: PropTypes.arrayOf(
22
+ PropTypes.shape({
23
+ size: PropTypes.number.isRequired,
24
+ // eslint-disable-next-line react/forbid-prop-types
25
+ data: PropTypes.object
26
+ })
27
+ ).isRequired
28
+ })
29
+ ).isRequired
19
30
  }).isRequired
20
31
  };
21
32
 
@@ -77,7 +77,11 @@ Options.propTypes = {
77
77
  optionName: PropTypes.string,
78
78
  optionType: PropTypes.string
79
79
  })
80
- ).isRequired
80
+ )
81
+ };
82
+
83
+ Options.defaultProps = {
84
+ options: []
81
85
  };
82
86
 
83
87
  export const layout = {
@@ -157,12 +157,12 @@ export default function Variants({
157
157
  <input
158
158
  name={`variant_options[${i}][attribute_id]`}
159
159
  type="hidden"
160
- value={a.attributeId}
160
+ value={a.attributeId || ''}
161
161
  />
162
162
  <input
163
163
  name={`variant_options[${i}][optionId]`}
164
164
  type="hidden"
165
- value={a.selectedOption}
165
+ value={a.selectedOption || ''}
166
166
  />
167
167
  <div className="mb-2 text-textSubdued uppercase">
168
168
  <span>{a.attribute_name}</span>
@@ -4,7 +4,6 @@ const {
4
4
  OK
5
5
  } = require('@evershop/evershop/src/lib/util/httpStatus');
6
6
  const { getConfig } = require('@evershop/evershop/src/lib/util/getConfig');
7
- const { error } = require('@evershop/evershop/src/lib/log/logger');
8
7
  const {
9
8
  translate
10
9
  } = require('@evershop/evershop/src/lib/locale/translate/translate');
@@ -70,7 +69,7 @@ module.exports = async (request, response, delegate, next) => {
70
69
  groupedItems.map((item) => item.sku)
71
70
  )
72
71
  .and('status', '=', 1)
73
- .load(pool);
72
+ .execute(pool);
74
73
  // Check if all products are available
75
74
  if (products.length !== groupedItems.length) {
76
75
  response.status(INVALID_PAYLOAD);
@@ -107,7 +106,6 @@ module.exports = async (request, response, delegate, next) => {
107
106
  };
108
107
  next();
109
108
  } catch (e) {
110
- error(e);
111
109
  response.status(INTERNAL_SERVER_ERROR);
112
110
  response.json({
113
111
  error: {
@@ -25,7 +25,7 @@ Title.propTypes = {
25
25
  title: PropTypes.string.isRequired
26
26
  };
27
27
 
28
- export default function ShoppingCart({ cart, setting, removeUrl }) {
28
+ export default function ShoppingCart({ cart, setting }) {
29
29
  const { totalQty = 0, items = [] } = cart || {};
30
30
  if (totalQty <= 0) {
31
31
  return <Empty />;
@@ -53,7 +53,7 @@ export default function ShoppingCart({ cart, setting, removeUrl }) {
53
53
  coreComponents={[
54
54
  {
55
55
  component: { default: Items },
56
- props: { items, setting, cartId: cart.uuid, removeUrl },
56
+ props: { items, setting },
57
57
  sortOrder: 10,
58
58
  id: 'shoppingCartTitle'
59
59
  }
@@ -78,8 +78,7 @@ ShoppingCart.propTypes = {
78
78
  }).isRequired,
79
79
  setting: PropTypes.shape({
80
80
  priceIncludingTax: PropTypes.bool
81
- }).isRequired,
82
- removeUrl: PropTypes.string.isRequired
81
+ }).isRequired
83
82
  };
84
83
 
85
84
  export const layout = {
@@ -16,11 +16,17 @@ function Subtotal({ subTotal }) {
16
16
  }
17
17
 
18
18
  Subtotal.propTypes = {
19
- subTotal: PropTypes.number
19
+ subTotal: PropTypes.shape({
20
+ value: PropTypes.number,
21
+ text: PropTypes.string
22
+ })
20
23
  };
21
24
 
22
25
  Subtotal.defaultProps = {
23
- subTotal: 0
26
+ subTotal: {
27
+ value: 0,
28
+ text: ''
29
+ }
24
30
  };
25
31
 
26
32
  function Discount({ discountAmount, coupon }) {
@@ -36,12 +42,18 @@ function Discount({ discountAmount, coupon }) {
36
42
  }
37
43
 
38
44
  Discount.propTypes = {
39
- discountAmount: PropTypes.number,
45
+ discountAmount: PropTypes.shape({
46
+ value: PropTypes.number,
47
+ text: PropTypes.string
48
+ }),
40
49
  coupon: PropTypes.string
41
50
  };
42
51
 
43
52
  Discount.defaultProps = {
44
- discountAmount: 0,
53
+ discountAmount: {
54
+ value: 0,
55
+ text: ''
56
+ },
45
57
  coupon: ''
46
58
  };
47
59
 
@@ -15,7 +15,8 @@ describe('Test line total calculation', () => {
15
15
  const cart = new Cart({
16
16
  status: 1
17
17
  });
18
-
18
+ const priceConfig = config.get('pricing');
19
+ priceConfig.tax.price_including_tax = false;
19
20
  const item = await cart.addItem(1, 1);
20
21
  expect(item.getData('line_total')).toEqual(100);
21
22
  const item2 = await cart.addItem(2, 2);
@@ -26,7 +27,8 @@ describe('Test line total calculation', () => {
26
27
  const cart = new Cart({
27
28
  status: 1
28
29
  });
29
-
30
+ const priceConfig = config.get('pricing');
31
+ priceConfig.tax.price_including_tax = false;
30
32
  const item = await cart.addItem(1, 1);
31
33
  expect(item.getData('line_total_incl_tax')).toEqual(110);
32
34
  const item2 = await cart.addItem(2, 2);
@@ -15,7 +15,8 @@ describe('Test product price calculation', () => {
15
15
  const cart = new Cart({
16
16
  status: 1
17
17
  });
18
-
18
+ const priceConfig = config.get('pricing');
19
+ priceConfig.tax.price_including_tax = false;
19
20
  const item = await cart.addItem(1, 1);
20
21
  expect(item.getData('product_price')).toEqual(100);
21
22
  expect(item.getData('final_price')).toEqual(100);
@@ -28,7 +29,8 @@ describe('Test product price calculation', () => {
28
29
  const cart = new Cart({
29
30
  status: 1
30
31
  });
31
-
32
+ const priceConfig = config.get('pricing');
33
+ priceConfig.tax.price_including_tax = false;
32
34
  const item = await cart.addItem(1, 1);
33
35
  expect(item.getData('product_price_incl_tax')).toEqual(110);
34
36
  expect(item.getData('final_price_incl_tax')).toEqual(110);
@@ -15,7 +15,8 @@ describe('Test tax amount calculation', () => {
15
15
  const cart = new Cart({
16
16
  status: 1
17
17
  });
18
-
18
+ const priceConfig = config.get('pricing');
19
+ priceConfig.tax.price_including_tax = false;
19
20
  const item = await cart.addItem(1, 1);
20
21
  expect(item.getData('tax_amount')).toEqual(10);
21
22
  const item2 = await cart.addItem(2, 2);
@@ -15,7 +15,6 @@ const {
15
15
  getEnabledWidgets
16
16
  } = require('@evershop/evershop/src/lib/util/getEnabledWidgets');
17
17
  const { get } = require('@evershop/evershop/src/lib/util/get');
18
- const isResolvable = require('is-resolvable');
19
18
  const {
20
19
  loadWidgetInstances
21
20
  } = require('../../../cms/services/widget/loadWidgetInstances');
@@ -98,41 +97,21 @@ module.exports = async (request, response, delegate, next) => {
98
97
  const widgetSpecs = enabledWidgets.find(
99
98
  (enabledWidget) => enabledWidget.type === widget.type
100
99
  );
100
+ const componentPath = currentRoute?.isAdmin
101
+ ? widgetSpecs.setting_component
102
+ : widgetSpecs.component;
103
+ const componentKey = currentRoute?.isAdmin
104
+ ? widgetSpecs.settingComponentKey
105
+ : widgetSpecs.componentKey;
101
106
  return {
102
107
  uuid: widget.uuid,
108
+ type: widget.type,
103
109
  settings: widget.settings,
104
- component: currentRoute?.isAdmin
105
- ? widgetSpecs.setting_component
106
- : widgetSpecs.component
110
+ component: componentPath,
111
+ componentKey
107
112
  };
108
113
  });
109
114
  }
110
- json.queries = Object.keys(json.queries).reduce((acc, key) => {
111
- const componentPath = Buffer.from(key, 'base64').toString('ascii');
112
- if (
113
- applicableWidgets.find(
114
- (widget) => widget.component === componentPath
115
- ) ||
116
- !isResolvable(componentPath)
117
- ) {
118
- acc[key] = json.queries[key];
119
- }
120
- return acc;
121
- }, {});
122
-
123
- // Remove all variables from widgets that are not used
124
- json.variables = Object.keys(json.variables).reduce((acc, key) => {
125
- const componentPath = Buffer.from(key, 'base64').toString('ascii');
126
- if (
127
- applicableWidgets.find(
128
- (widget) => widget.component === componentPath
129
- ) ||
130
- !isResolvable(componentPath)
131
- ) {
132
- acc[key] = json.variables[key];
133
- }
134
- return acc;
135
- }, {});
136
115
 
137
116
  let operation = 'query Query';
138
117
  const { fragments } = json;
@@ -142,7 +121,7 @@ module.exports = async (request, response, delegate, next) => {
142
121
 
143
122
  if (applicableWidgets.length > 0) {
144
123
  applicableWidgets.forEach((widget) => {
145
- const widgetKey = Buffer.from(widget.component).toString('base64');
124
+ const widgetKey = widget.componentKey;
146
125
  let widgetQuery = json.queries[widgetKey];
147
126
  // Deep clone the widget variables
148
127
  let widgetVariables = JSON.parse(
@@ -265,7 +244,13 @@ module.exports = async (request, response, delegate, next) => {
265
244
  json.variables[widgetUUID] = widgetVariables;
266
245
  // Now we merge the queries to the query as the string,
267
246
  queryStr = Object.keys(json.queries).reduce((acc, key) => {
268
- if (!isResolvable(Buffer.from(key, 'base64').toString('ascii'))) {
247
+ if (
248
+ !enabledWidgets.find(
249
+ (widget) =>
250
+ widget.componentKey === key ||
251
+ widget.settingComponentKey === key
252
+ )
253
+ ) {
269
254
  // eslint-disable-next-line no-param-reassign
270
255
  acc += `\n${json.queries[key]} `;
271
256
  }
@@ -275,7 +260,13 @@ module.exports = async (request, response, delegate, next) => {
275
260
  // Now we merge the variables
276
261
  variables = Object.keys(json.variables).reduce(
277
262
  (acc, key) => {
278
- if (!isResolvable(Buffer.from(key, 'base64').toString('ascii'))) {
263
+ if (
264
+ !enabledWidgets.find(
265
+ (widget) =>
266
+ widget.componentKey === key ||
267
+ widget.settingComponentKey === key
268
+ )
269
+ ) {
279
270
  acc.values = { ...acc.values, ...json.variables[key].values };
280
271
  acc.defs = [...acc.defs, ...json.variables[key].defs];
281
272
  }
@@ -287,7 +278,13 @@ module.exports = async (request, response, delegate, next) => {
287
278
  } else {
288
279
  // Just delete resolvable queries and variables
289
280
  queryStr = Object.keys(json.queries).reduce((acc, key) => {
290
- if (isResolvable(Buffer.from(key, 'base64').toString('ascii'))) {
281
+ if (
282
+ enabledWidgets.find(
283
+ (widget) =>
284
+ widget.componentKey === key ||
285
+ widget.settingComponentKey === key
286
+ )
287
+ ) {
291
288
  delete json.queries[key];
292
289
  } else {
293
290
  // eslint-disable-next-line no-param-reassign
@@ -298,7 +295,13 @@ module.exports = async (request, response, delegate, next) => {
298
295
 
299
296
  variables = Object.keys(json.variables).reduce(
300
297
  (acc, key) => {
301
- if (isResolvable(Buffer.from(key, 'base64').toString('ascii'))) {
298
+ if (
299
+ enabledWidgets.find(
300
+ (widget) =>
301
+ widget.componentKey === key ||
302
+ widget.settingComponentKey === key
303
+ )
304
+ ) {
302
305
  delete json.variables[key];
303
306
  } else {
304
307
  acc.values = { ...acc.values, ...json.variables[key].values };