@jetshop/template-trend 5.12.3 → 5.13.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.
@@ -1 +1 @@
1
- .StoreName_sgyktyw{font-size:30px;font-weight:bold;line-height:normal;text-align:center;-webkit-text-decoration:none;text-decoration:none;color:inherit;}.StoreName_sgyktyw a{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-text-decoration:none;text-decoration:none;color:inherit;}
1
+ .StoreName_sgyktyw{font-size:30px;font-weight:bold;line-height:normal;text-align:center;-webkit-text-decoration:none;text-decoration:none;color:inherit;}.StoreName_sgyktyw a{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;-webkit-text-decoration:none;text-decoration:none;color:inherit;}.StoreName_sgyktyw a svg{width:100px;}@media (max-width:49.99rem){.StoreName_sgyktyw a svg{width:85px;}}.StoreName_sgyktyw a span{font-size:12px;text-transform:uppercase;}
@@ -0,0 +1 @@
1
+ .PaginationWrapper_p1arddu{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;width:100%;-webkit-box-pack:justify;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;}
@@ -0,0 +1,11 @@
1
+ {
2
+ "configurations": [
3
+ {
4
+ "type": "node-terminal",
5
+ "name": "Run Script: start",
6
+ "request": "launch",
7
+ "command": "yarn run start",
8
+ "cwd": "${workspaceFolder}"
9
+ }
10
+ ]
11
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jetshop/template-trend",
3
- "version": "5.12.3",
3
+ "version": "5.13.1",
4
4
  "license": "MIT",
5
5
  "scripts": {
6
6
  "build": "react-scripts build",
@@ -45,11 +45,11 @@
45
45
  ]
46
46
  },
47
47
  "dependencies": {
48
- "@jetshop/core": "^5.12.3",
48
+ "@jetshop/core": "^5.13.1",
49
49
  "@jetshop/flight-shortcodes": "^2.0.10",
50
- "@jetshop/intl": "^5.12.3",
51
- "@jetshop/react-scripts": "^5.12.3",
52
- "@jetshop/ui": "^5.12.3",
50
+ "@jetshop/intl": "^5.13.1",
51
+ "@jetshop/react-scripts": "^5.13.1",
52
+ "@jetshop/ui": "^5.13.1",
53
53
  "@react-google-maps/api": "~1.7.0",
54
54
  "prop-types": "^15.6.2",
55
55
  "react": "^16.9.0",
package/schema.graphql CHANGED
@@ -213,6 +213,12 @@ type Category implements Document {
213
213
  """
214
214
  isDynamic: Boolean!
215
215
 
216
+ """
217
+ The category's dynamic filtersNB: Carries a performance cost, as asking for
218
+ this will result in a separate API call in the backend.
219
+ """
220
+ dynamicFiltering: [CategoryDynamicFilter]
221
+
216
222
  """
217
223
  Get content data set via the Content Editor.NB: Carries a performance cost, as
218
224
  asking for this will result in a separate API call in the backend.
@@ -229,6 +235,13 @@ type CategoryAutoCompleteResult {
229
235
  result: [Category]
230
236
  }
231
237
 
238
+ type CategoryDynamicFilter {
239
+ type: String
240
+ value: CategoryDynamicFilterValue
241
+ }
242
+
243
+ union CategoryDynamicFilterValue = StringValue | ListStringValue | BoolValue
244
+
232
245
  type CategoryImage {
233
246
  width: Int
234
247
  height: Int
@@ -624,6 +637,11 @@ input CustomerUpdateDeliveryAddressInput {
624
637
  addressName: String
625
638
  }
626
639
 
640
+ input CustomerUpdateExternalAttribute {
641
+ name: String!
642
+ value: String!
643
+ }
644
+
627
645
  input CustomerUpdateInput {
628
646
  pid: String
629
647
  organizationNumber: String
@@ -631,6 +649,7 @@ input CustomerUpdateInput {
631
649
  deliveryAddresses: [CustomerUpdateDeliveryAddressInput]
632
650
  preferences: CustomerUpdatePreferenceInput
633
651
  consents: [CustomerUpdateConsentInput]
652
+ externalAttributes: [CustomerUpdateExternalAttribute]
634
653
  dynamicContent: String
635
654
  }
636
655
 
@@ -853,6 +872,10 @@ type ListFilterItem {
853
872
  resultCount: Int
854
873
  }
855
874
 
875
+ type ListStringValue {
876
+ value: [String]
877
+ }
878
+
856
879
  input LoginExternalCustomerInput {
857
880
  externalCustomerToken: String!
858
881
  }
@@ -1051,6 +1074,24 @@ type Mutation {
1051
1074
  """
1052
1075
  signUp(input: SignUpInput!): SignUpResponse
1053
1076
 
1077
+ """
1078
+ ## Description
1079
+ This mutation's purpose is to update a existing customer's group using an
1080
+ access code. An authorization token is needed in the request, in order to be
1081
+ able to update the customer.
1082
+ ## Error Codes
1083
+ ### Unauthorized
1084
+ Unauthorized
1085
+ ### UnableToUpdateCustomer
1086
+ Error in underlying API call, more info may be contained in the error message.
1087
+ ### CustomerAlreadyUpdated
1088
+ Customer already in the customer group
1089
+ ### CustomerNotFound
1090
+ No match on customer with access code
1091
+
1092
+ """
1093
+ updateCustomerGroup(customerGroupAccessCode: String!): UpdateCustomerGroupResult
1094
+
1054
1095
  """
1055
1096
  This mutation's purpose is to update a existing customer's information. An
1056
1097
  authorization token is needed in the request, in order to be able to update the customer.
@@ -1400,6 +1441,11 @@ type Price {
1400
1441
  vat: Decimal!
1401
1442
  }
1402
1443
 
1444
+ type PriceHistory {
1445
+ timestamp: DateTime
1446
+ price: Price
1447
+ }
1448
+
1403
1449
  type PrivateCustomer implements Customer {
1404
1450
  pid: String
1405
1451
  id: ID!
@@ -1610,6 +1656,12 @@ type Product implements Document {
1610
1656
  performance cost, as asking for this will result in a separate API call in the backend.
1611
1657
  """
1612
1658
  familyMembers: [Product!]
1659
+
1660
+ """Get Product History within the set number of days"""
1661
+ history(
1662
+ """number of days, default is 30"""
1663
+ days: Int = 30
1664
+ ): ProductHistory
1613
1665
  }
1614
1666
 
1615
1667
  type ProductAutoCompleteResult {
@@ -1698,6 +1750,10 @@ enum ProductCustomFieldType {
1698
1750
  MULTI_LEVEL_LIST
1699
1751
  }
1700
1752
 
1753
+ type ProductHistory {
1754
+ previousPrice: [PriceHistory]
1755
+ }
1756
+
1701
1757
  type ProductImage {
1702
1758
  """
1703
1759
  Alternate text for the image, commonly used for the alt attribute of img-tags.
@@ -1798,6 +1854,16 @@ type ProductVariant {
1798
1854
  warehouseStock(includeInactive: Boolean = false): [Warehouse]
1799
1855
  images: [ProductImage]
1800
1856
  barcode: String
1857
+
1858
+ """Get Product History within the set number of days"""
1859
+ history(
1860
+ """number of days, default is 30"""
1861
+ days: Int = 30
1862
+ ): ProductVariantHistory
1863
+ }
1864
+
1865
+ type ProductVariantHistory {
1866
+ previousPrice: [PriceHistory]
1801
1867
  }
1802
1868
 
1803
1869
  type ProductVariantOption {
@@ -2061,6 +2127,11 @@ input SignUpDeliveryAddressInput {
2061
2127
  addressName: String
2062
2128
  }
2063
2129
 
2130
+ input SignUpExternalAttribute {
2131
+ name: String!
2132
+ value: String!
2133
+ }
2134
+
2064
2135
  input SignUpInput {
2065
2136
  type: CustomerType!
2066
2137
  pid: String
@@ -2074,6 +2145,7 @@ input SignUpInput {
2074
2145
  deliveryAddresses: [SignUpDeliveryAddressInput]
2075
2146
  preferences: SignUpPreferencesInput
2076
2147
  consents: [SignUpConsentInput]
2148
+ externalAttributes: [SignUpExternalAttribute]
2077
2149
  dynamicContent: String
2078
2150
  priceListAccessCode: String
2079
2151
  }
@@ -2208,6 +2280,10 @@ type UpdateCartMutation {
2208
2280
  cart: Cart
2209
2281
  }
2210
2282
 
2283
+ type UpdateCustomerGroupResult {
2284
+ success: Boolean!
2285
+ }
2286
+
2211
2287
  type UpdateCustomerPriceListResult {
2212
2288
  success: Boolean!
2213
2289
  }
@@ -198,7 +198,11 @@ const CartFlyoutView = ({ result, modal, ...rest }) => {
198
198
  return (
199
199
  <Flex key={discount.name} style={{ marginTop: '1em' }}>
200
200
  <label>{discount.name}</label>
201
- <Price price={discount.value} style={{ display: 'inline' }} />
201
+ <Price
202
+ price={discount.value}
203
+ style={{ display: 'inline' }}
204
+ negative
205
+ />
202
206
  </Flex>
203
207
  );
204
208
  })}
@@ -61,6 +61,7 @@ export function ProductGrid({
61
61
  category = '',
62
62
  loading,
63
63
  className,
64
+ categoryPath,
64
65
  ...rest
65
66
  }) {
66
67
  const track = useTracker();
@@ -86,6 +87,7 @@ export function ProductGrid({
86
87
  product={product}
87
88
  style={{ opacity: loading ? 0.5 : 1 }}
88
89
  list={listName}
90
+ categoryPath={categoryPath}
89
91
  loadImageEagerly={isAboveFold(index)}
90
92
  {...rest}
91
93
  >
@@ -4,7 +4,7 @@ import React from 'react';
4
4
  export function Success({ children, className }) {
5
5
  return (
6
6
  <div className={cx(success, className)}>
7
- <div>{children}</div>
7
+ <div data-testid="success-message">{children}</div>
8
8
  </div>
9
9
  );
10
10
  }
@@ -2,7 +2,8 @@ import React from 'react';
2
2
  import { Link } from 'react-router-dom';
3
3
  import { Below } from '@jetshop/ui/Breakpoints';
4
4
  import { styled } from 'linaria/react';
5
- import TrendLogo from './trend-logo.svg';
5
+ import { ReactComponent as NorceLogo } from './NorceLogo.svg';
6
+ import { theme } from '../../Theme';
6
7
 
7
8
  const StoreName = styled('h2')`
8
9
  font-size: 30px;
@@ -14,8 +15,19 @@ const StoreName = styled('h2')`
14
15
  a {
15
16
  display: flex;
16
17
  align-items: center;
18
+ flex-direction: column;
17
19
  text-decoration: none;
18
20
  color: inherit;
21
+ svg {
22
+ width: 100px;
23
+ ${theme.below.md} {
24
+ width: 85px;
25
+ }
26
+ }
27
+ span {
28
+ font-size: 12px;
29
+ text-transform: uppercase;
30
+ }
19
31
  }
20
32
  `;
21
33
 
@@ -27,7 +39,8 @@ const Logo = ({ searchOpen }) => (
27
39
  {!searchOpen && (
28
40
  <StoreName>
29
41
  <Link to="/">
30
- <img alt="Trend" src={TrendLogo} />
42
+ <NorceLogo />
43
+ <span>Storefront</span>
31
44
  </Link>
32
45
  </StoreName>
33
46
  )}
@@ -35,7 +48,8 @@ const Logo = ({ searchOpen }) => (
35
48
  ) : (
36
49
  <StoreName>
37
50
  <Link to="/">
38
- <img alt="Trend" src={TrendLogo} />
51
+ <NorceLogo />
52
+ <span>Storefront</span>
39
53
  </Link>
40
54
  </StoreName>
41
55
  )
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 515.3 102.8"><defs><style>.a{fill:#10141d;}</style></defs><path class="a" d="M466.13,100.83a28.63,28.63,0,0,0,28.3,22.9c10.2,0,18.4-3.2,22.7-9.6h26.3c-6.8,18.2-26.3,30.5-48.9,30.5A50.94,50.94,0,0,1,443,93.33c0-28.4,22.3-51.4,50.8-51.4s50.9,22.9,50.9,51.3a46.8,46.8,0,0,1-.6,7.6Zm1-19.6h53.3c-3.2-10.4-14-18.8-26.7-18.8S470.33,70.73,467.13,81.23Z" transform="translate(-29.43 -41.83)"/><path class="a" d="M126.43,140.63h-22V90.33a26.5,26.5,0,1,0-53,0v50.3h-22V90.33a48.5,48.5,0,1,1,97,0Z" transform="translate(-29.43 -41.83)"/><path class="a" d="M286.63,140.53h-22V91.63a48.61,48.61,0,0,1,48.5-48.5v22a26.55,26.55,0,0,0-26.5,26.5Z" transform="translate(-29.43 -41.83)"/><path class="a" d="M409,100.83c-2.9,13.8-13.8,22.8-28.3,22.8-17.2,0-28.8-12.4-28.8-30.5s11.6-30.5,28.8-30.5a26.77,26.77,0,0,1,20.4,9L417.33,57c-9.2-9.4-21-15.2-36.7-15.2-29.5,0-51.3,21.8-51.3,51.3s21.8,51.3,51.3,51.3c26.5,0,47.1-18.3,50.6-43.6Z" transform="translate(-29.43 -41.83)"/><path class="a" d="M242.43,140.63h-94.2v-95h94.2Zm-73.2-21h52.2v-53h-52.2v53Z" transform="translate(-29.43 -41.83)"/></svg>
@@ -54,6 +54,7 @@ function ChangePassword() {
54
54
  <PrimaryButton
55
55
  type="submit"
56
56
  disabled={isSubmitting || !isValid}
57
+ data-testid="save-password-button"
57
58
  >
58
59
  {t('Save')}
59
60
  </PrimaryButton>
@@ -10,7 +10,11 @@ import { useProductList } from '@jetshop/core/hooks/ProductList';
10
10
  export function Product({ product, loading, children, listId }) {
11
11
  // Use the variant's image for display
12
12
  const productForDisplay = { ...product };
13
- if (product.isVariant && product.variant.images) {
13
+ if (
14
+ product.isVariant &&
15
+ product.variant.images &&
16
+ product.variant.images.length > 0
17
+ ) {
14
18
  productForDisplay.images = product.variant.images;
15
19
  }
16
20
 
@@ -75,13 +75,12 @@ function AddToCartForm({
75
75
  });
76
76
  const [trigger, dismiss] = useNotification();
77
77
 
78
- const onAddToCartInit = ({ mutationId, quantity, price }) => {
78
+ const onAddToCartInit = ({ mutationId, quantity }) => {
79
79
  trigger(
80
80
  <ProductToastWrapper
81
81
  selectedVariation={variant}
82
82
  product={product}
83
83
  quantity={quantity}
84
- price={price}
85
84
  />,
86
85
  {
87
86
  id: mutationId,
@@ -90,7 +89,7 @@ function AddToCartForm({
90
89
  );
91
90
  };
92
91
  const onAddToCartError = () => {
93
- return ({ mutationId, quantity, price, error }) => {
92
+ return ({ mutationId, quantity, error }) => {
94
93
  dismiss(mutationId);
95
94
 
96
95
  trigger(
@@ -98,7 +97,6 @@ function AddToCartForm({
98
97
  selectedVariation={variant}
99
98
  product={product}
100
99
  quantity={quantity}
101
- price={price}
102
100
  error={error}
103
101
  />,
104
102
  {
@@ -8,6 +8,7 @@ import CartProvider from '@jetshop/core/components/Query/CartProvider';
8
8
  import t from '@jetshop/intl';
9
9
  import Image from '@jetshop/ui/Image/Image';
10
10
  import { Price } from '@jetshop/ui/Price';
11
+ import useProductToast from './useProductToast';
11
12
 
12
13
  import { baseStyles } from '../../ui/Button';
13
14
  import { theme } from '../../Theme';
@@ -86,14 +87,16 @@ const Error = styled('p')`
86
87
  const ProductToast = ({
87
88
  product,
88
89
  cart,
89
- closeToast,
90
90
  selectedVariation,
91
91
  quantity,
92
- price,
93
92
  error
94
93
  }) => {
94
+ const { price, previousPrice, image } = useProductToast({
95
+ product,
96
+ selectedVariation,
97
+ quantity
98
+ });
95
99
  const track = useTracker();
96
- const image = selectedVariation?.images[0] || product.images[0];
97
100
  return (
98
101
  <Container data-testid="product-toast">
99
102
  <ProductCheckoutContainer>
@@ -120,9 +123,7 @@ const ProductToast = ({
120
123
  </Header>
121
124
  )}
122
125
  <ProductName>{product.name}</ProductName>
123
- {!error && (
124
- <Price price={price.price} previousPrice={price.previousPrice} />
125
- )}
126
+ {!error && <Price price={price} previousPrice={previousPrice} />}
126
127
  {error && (
127
128
  <Error>
128
129
  {t('An error occurred. Details:')}
@@ -0,0 +1,26 @@
1
+ function useProductToast({ product, selectedVariation, quantity }) {
2
+ let image, price, previousPrice;
3
+
4
+ const toastProduct = selectedVariation || product;
5
+
6
+ // Calculating the price by mutliplying with quantity
7
+ price = calculatePrice(toastProduct.price, quantity);
8
+ previousPrice = calculatePrice(toastProduct.previousPrice, quantity);
9
+
10
+ image = selectedVariation?.images[0] || product.images[0];
11
+
12
+ return {
13
+ price,
14
+ previousPrice,
15
+ image
16
+ };
17
+ }
18
+
19
+ function calculatePrice(price, quantity) {
20
+ const incVat = price.incVat * quantity;
21
+ const exVat = price.exVat * quantity;
22
+ const vat = price.vat * quantity;
23
+ return { incVat, exVat, vat };
24
+ }
25
+
26
+ export default useProductToast;
@@ -120,7 +120,7 @@ const ProductContainer = styled('div')`
120
120
  }
121
121
  `;
122
122
 
123
- const Product = ({ result: { data, loading }, product }) => {
123
+ const Product = ({ result: { data, loading }, product, partialProduct }) => {
124
124
  const initialVariant = useVariantFromUrl();
125
125
  const t = useIntl();
126
126
 
@@ -132,13 +132,17 @@ const Product = ({ result: { data, loading }, product }) => {
132
132
  const { selectedVariant: selectedVariation, getMissingOptions } =
133
133
  variantHandler;
134
134
 
135
+ if (!product) {
136
+ product = partialProduct;
137
+ }
135
138
  // Return early if there is no product
136
- if (!product)
139
+ if (!product) {
137
140
  return (
138
141
  <ProductContainer>
139
142
  <ProductPageLoadingState />
140
143
  </ProductContainer>
141
144
  );
145
+ }
142
146
 
143
147
  const images = product.images ?? [];
144
148
  const parents = getParentOrCanonicalRoute(data?.route?.parents, product);
@@ -75,6 +75,7 @@ const config = {
75
75
  Category: [LoadableStandardCategoryPage, LoadableWindowedCategoryPage],
76
76
  Page: [ContentPage]
77
77
  }
78
- }
78
+ },
79
+ usePrimaryRouteForProducts: false
79
80
  };
80
81
  export default config;