@jetshop/template-trend 5.13.0 → 5.13.3-beta.0

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;}
@@ -3,7 +3,7 @@
3
3
  .ProductImageWrapper_p1i58doo{width:5rem;margin-right:1rem;}
4
4
  .ProductCheckoutContainer_pjx0jqi{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;height:100%;width:100%;}.ProductCheckoutContainer_pjx0jqi a{-webkit-text-decoration:none;text-decoration:none;}.ProductCheckoutContainer_pjx0jqi a:hover{opacity:0.8;-webkit-text-decoration:none;text-decoration:none;color:white;}
5
5
  .Product_p3e3eyv{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-items:flex-start;-webkit-box-align:flex-start;-ms-flex-align:flex-start;align-items:flex-start;margin:16px;}
6
- .ProductDetails_p41hym0{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;color:black;}
6
+ .ProductDetails_p41hym0{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;color:black;}.ProductDetails_p41hym0 .price,.ProductDetails_p41hym0 .new-price{margin-top:0.75rem;}.ProductDetails_p41hym0 .old-price{margin-top:0.25rem;}.ProductDetails_p41hym0 .new-price{color:#EB0000;}
7
7
  .Header_hrfqnnj{font-size:16px;margin-bottom:8px;}
8
8
  .ProductName_p1jc6jl9{font-size:12px;}
9
9
  .Error_ednkb9d{color:red;margin-top:8px;font-size:12px;}
@@ -0,0 +1 @@
1
+ .Wrapper_wr5mleq{--innerFontSize:0.85rem;position:relative;}.Wrapper_wr5mleq .label{font-size:0.75rem;cursor:pointer;background:transparent;}.Wrapper_wr5mleq .price-table{position:absolute;padding:0.35rem 0.9rem;background:white;border:1px solid #e5e5e5;max-height:30rem;overflow:scroll;z-index:2;min-width:14rem;max-width:18rem;}.Wrapper_wr5mleq .price-table .label{font-size:var(--innerFontSize);}.Wrapper_wr5mleq .price-table li{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between;}.Wrapper_wr5mleq .price-table li .timestamp{font-size:var(--innerFontSize);}.Wrapper_wr5mleq .price-table li [data-flight-price=''] > .price{font-size:var(--innerFontSize);font-weight:normal;}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jetshop/template-trend",
3
- "version": "5.13.0",
3
+ "version": "5.13.3-beta.0",
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.13.0",
48
+ "@jetshop/core": "^5.13.3-beta.0",
49
49
  "@jetshop/flight-shortcodes": "^2.0.10",
50
- "@jetshop/intl": "^5.13.0",
51
- "@jetshop/react-scripts": "^5.13.0",
52
- "@jetshop/ui": "^5.13.0",
50
+ "@jetshop/intl": "^5.13.2",
51
+ "@jetshop/react-scripts": "^5.13.2",
52
+ "@jetshop/ui": "^5.13.3-beta.0",
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
@@ -625,8 +638,8 @@ input CustomerUpdateDeliveryAddressInput {
625
638
  }
626
639
 
627
640
  input CustomerUpdateExternalAttribute {
628
- name: String
629
- value: String
641
+ name: String!
642
+ value: String!
630
643
  }
631
644
 
632
645
  input CustomerUpdateInput {
@@ -859,6 +872,10 @@ type ListFilterItem {
859
872
  resultCount: Int
860
873
  }
861
874
 
875
+ type ListStringValue {
876
+ value: [String]
877
+ }
878
+
862
879
  input LoginExternalCustomerInput {
863
880
  externalCustomerToken: String!
864
881
  }
@@ -1057,6 +1074,24 @@ type Mutation {
1057
1074
  """
1058
1075
  signUp(input: SignUpInput!): SignUpResponse
1059
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
+
1060
1095
  """
1061
1096
  This mutation's purpose is to update a existing customer's information. An
1062
1097
  authorization token is needed in the request, in order to be able to update the customer.
@@ -1406,6 +1441,11 @@ type Price {
1406
1441
  vat: Decimal!
1407
1442
  }
1408
1443
 
1444
+ type PriceHistory {
1445
+ timestamp: DateTime
1446
+ price: Price
1447
+ }
1448
+
1409
1449
  type PrivateCustomer implements Customer {
1410
1450
  pid: String
1411
1451
  id: ID!
@@ -1616,6 +1656,12 @@ type Product implements Document {
1616
1656
  performance cost, as asking for this will result in a separate API call in the backend.
1617
1657
  """
1618
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
1619
1665
  }
1620
1666
 
1621
1667
  type ProductAutoCompleteResult {
@@ -1704,6 +1750,10 @@ enum ProductCustomFieldType {
1704
1750
  MULTI_LEVEL_LIST
1705
1751
  }
1706
1752
 
1753
+ type ProductHistory {
1754
+ previousPrice: [PriceHistory]
1755
+ }
1756
+
1707
1757
  type ProductImage {
1708
1758
  """
1709
1759
  Alternate text for the image, commonly used for the alt attribute of img-tags.
@@ -1804,6 +1854,16 @@ type ProductVariant {
1804
1854
  warehouseStock(includeInactive: Boolean = false): [Warehouse]
1805
1855
  images: [ProductImage]
1806
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]
1807
1867
  }
1808
1868
 
1809
1869
  type ProductVariantOption {
@@ -2068,8 +2128,8 @@ input SignUpDeliveryAddressInput {
2068
2128
  }
2069
2129
 
2070
2130
  input SignUpExternalAttribute {
2071
- name: String
2072
- value: String
2131
+ name: String!
2132
+ value: String!
2073
2133
  }
2074
2134
 
2075
2135
  input SignUpInput {
@@ -2220,6 +2280,10 @@ type UpdateCartMutation {
2220
2280
  cart: Cart
2221
2281
  }
2222
2282
 
2283
+ type UpdateCustomerGroupResult {
2284
+ success: Boolean!
2285
+ }
2286
+
2223
2287
  type UpdateCustomerPriceListResult {
2224
2288
  success: Boolean!
2225
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
  })}
@@ -21,7 +21,12 @@ export default class HeaderChannelSelector extends Component {
21
21
  render() {
22
22
  return (
23
23
  <ChannelContext.Consumer>
24
- {({ channels, selectedChannel, updateChannel }) => (
24
+ {({
25
+ channels,
26
+ selectedChannel,
27
+ updateChannel,
28
+ selectedChannelGroup
29
+ }) => (
25
30
  <Fragment>
26
31
  <FlyoutTrigger id="channel-selector">
27
32
  {({ showTarget, hideTarget, isOpen }) => (
@@ -44,7 +49,7 @@ export default class HeaderChannelSelector extends Component {
44
49
  {({ isOpen, hideTarget }) => (
45
50
  <Flyout>
46
51
  <Selector
47
- channels={channels}
52
+ channels={selectedChannelGroup || channels}
48
53
  hideTarget={hideTarget}
49
54
  selectedChannel={selectedChannel}
50
55
  updateChannel={updateChannel}
@@ -26,15 +26,14 @@ const modalStyles = css`
26
26
  `;
27
27
 
28
28
  const ChannelSelectorModal = props => {
29
- const { selectedChannel, channels, updateChannel } =
29
+ const { selectedChannel, channels, updateChannel, selectedChannelGroup } =
30
30
  useContext(ChannelContext);
31
-
32
31
  return (
33
32
  <ModalTrigger
34
33
  modalStyles={modalStyles}
35
34
  target={props => (
36
35
  <Selector
37
- channels={channels}
36
+ channels={selectedChannelGroup || channels}
38
37
  selectedChannel={selectedChannel}
39
38
  updateChannel={updateChannel}
40
39
  type={LargeSelector}
@@ -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>
@@ -193,12 +193,8 @@ const Flyout = ({ children }) => (
193
193
  );
194
194
 
195
195
  const ChannelBanner = () => {
196
- const {
197
- channels,
198
- recommendedChannel,
199
- selectedChannel,
200
- updateChannel
201
- } = useContext(ChannelContext);
196
+ const { channels, recommendedChannel, selectedChannel, updateChannel } =
197
+ useContext(ChannelContext);
202
198
 
203
199
  const { bannerIsOpen, hideTheBanner } = useChannelBanner();
204
200
 
@@ -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
 
@@ -27,6 +27,7 @@ import WarehouseStock from '../StockStatus/WarehouseStock';
27
27
 
28
28
  import addToCartMutation from '../../Cart/queries/addToCart.gql';
29
29
  import CartQuery from '../../Cart/queries/cartQuery.gql';
30
+ import { PriceHistoryWrapper } from '../PriceHistory';
30
31
 
31
32
  const StyledForm = styled(Form)`
32
33
  display: flex;
@@ -75,13 +76,12 @@ function AddToCartForm({
75
76
  });
76
77
  const [trigger, dismiss] = useNotification();
77
78
 
78
- const onAddToCartInit = ({ mutationId, quantity, price }) => {
79
+ const onAddToCartInit = ({ mutationId, quantity }) => {
79
80
  trigger(
80
81
  <ProductToastWrapper
81
82
  selectedVariation={variant}
82
83
  product={product}
83
84
  quantity={quantity}
84
- price={price}
85
85
  />,
86
86
  {
87
87
  id: mutationId,
@@ -90,7 +90,7 @@ function AddToCartForm({
90
90
  );
91
91
  };
92
92
  const onAddToCartError = () => {
93
- return ({ mutationId, quantity, price, error }) => {
93
+ return ({ mutationId, quantity, error }) => {
94
94
  dismiss(mutationId);
95
95
 
96
96
  trigger(
@@ -98,7 +98,6 @@ function AddToCartForm({
98
98
  selectedVariation={variant}
99
99
  product={product}
100
100
  quantity={quantity}
101
- price={price}
102
101
  error={error}
103
102
  />,
104
103
  {
@@ -142,6 +141,10 @@ function AddToCartForm({
142
141
  configurationContext && configurationContext.loading ? 0.3 : 1
143
142
  }}
144
143
  />
144
+ <PriceHistoryWrapper
145
+ articleNumber={product.articleNumber}
146
+ variant={variant}
147
+ />
145
148
 
146
149
  <Campaigns
147
150
  campaigns={product.campaigns}
@@ -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';
@@ -66,6 +67,19 @@ const ProductDetails = styled('div')`
66
67
  flex-direction: column;
67
68
  flex-grow: 1;
68
69
  color: black;
70
+
71
+ .price,
72
+ .new-price {
73
+ margin-top: 0.75rem;
74
+ }
75
+
76
+ .old-price {
77
+ margin-top: 0.25rem;
78
+ }
79
+
80
+ .new-price {
81
+ color: ${theme.colors.red};
82
+ }
69
83
  `;
70
84
 
71
85
  const Header = styled('h3')`
@@ -86,14 +100,16 @@ const Error = styled('p')`
86
100
  const ProductToast = ({
87
101
  product,
88
102
  cart,
89
- closeToast,
90
103
  selectedVariation,
91
104
  quantity,
92
- price,
93
105
  error
94
106
  }) => {
107
+ const { price, previousPrice, image } = useProductToast({
108
+ product,
109
+ selectedVariation,
110
+ quantity
111
+ });
95
112
  const track = useTracker();
96
- const image = selectedVariation?.images[0] || product.images[0];
97
113
  return (
98
114
  <Container data-testid="product-toast">
99
115
  <ProductCheckoutContainer>
@@ -120,9 +136,7 @@ const ProductToast = ({
120
136
  </Header>
121
137
  )}
122
138
  <ProductName>{product.name}</ProductName>
123
- {!error && (
124
- <Price price={price.price} previousPrice={price.previousPrice} />
125
- )}
139
+ {!error && <Price price={price} previousPrice={previousPrice} />}
126
140
  {error && (
127
141
  <Error>
128
142
  {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;
@@ -0,0 +1,147 @@
1
+ import t from '@jetshop/intl';
2
+ import React, { useContext } from 'react';
3
+ import { useQuery } from '@apollo/react-hooks';
4
+ import PriceHistoryQuery from './PriceHistoryQuery.gql';
5
+ import { styled } from 'linaria/react';
6
+ import { Price } from '@jetshop/ui/Price';
7
+
8
+ import { FlyoutTrigger } from '@jetshop/ui/Modal/Flyout';
9
+ import { FlyoutTarget } from '@jetshop/ui/Modal/Flyout';
10
+ import ChannelContext from '@jetshop/core/components/ChannelContext/ChannelContext';
11
+
12
+ const Wrapper = styled.div`
13
+ --innerFontSize: 0.85rem;
14
+ position: relative;
15
+
16
+ .label {
17
+ font-size: 0.75rem;
18
+ cursor: pointer;
19
+ background: transparent;
20
+ }
21
+
22
+ .price-table {
23
+ position: absolute;
24
+ padding: 0.35rem 0.9rem;
25
+ background: white;
26
+ border: 1px solid #e5e5e5;
27
+ max-height: 30rem;
28
+ overflow: scroll;
29
+ z-index: 2;
30
+ min-width: 14rem;
31
+ max-width: 18rem;
32
+
33
+ .label {
34
+ font-size: var(--innerFontSize);
35
+ }
36
+
37
+ li {
38
+ display: flex;
39
+ justify-content: space-between;
40
+
41
+ .timestamp {
42
+ font-size: var(--innerFontSize);
43
+ }
44
+
45
+ [data-flight-price=''] {
46
+ > .price {
47
+ font-size: var(--innerFontSize);
48
+ font-weight: normal;
49
+ }
50
+ }
51
+ }
52
+ }
53
+ `;
54
+
55
+ export function PriceHistoryWrapper(props) {
56
+ return (
57
+ <Wrapper>
58
+ <FlyoutTrigger
59
+ id="price-history-flyout"
60
+ coverStyles={{ zIndex: 0, background: 'transparent' }}
61
+ >
62
+ {({ isOpen, hideTarget, showTarget }) => (
63
+ <button
64
+ onClick={() => {
65
+ if (isOpen) {
66
+ hideTarget();
67
+ } else {
68
+ showTarget();
69
+ }
70
+ }}
71
+ className="label"
72
+ >
73
+ {t('View price history')}
74
+ </button>
75
+ )}
76
+ </FlyoutTrigger>
77
+ <FlyoutTarget id="price-history-flyout">
78
+ {() => <PriceHistory {...props} />}
79
+ </FlyoutTarget>
80
+ </Wrapper>
81
+ );
82
+ }
83
+
84
+ const days = 30;
85
+ function PriceHistory({ articleNumber, variant }) {
86
+ const { error, loading, data } = useQuery(PriceHistoryQuery, {
87
+ variables: { articleNumber, days },
88
+ errorPolicy: 'all',
89
+ skip: !articleNumber
90
+ });
91
+
92
+ if (loading || error) {
93
+ return (
94
+ <div className="price-table">
95
+ {loading && (
96
+ <span className="label">
97
+ {t('Getting the last { days } days price changes...', {
98
+ days
99
+ })}
100
+ </span>
101
+ )}
102
+ {error && <span className="label">{t('Something went wrong')}</span>}
103
+ </div>
104
+ );
105
+ }
106
+
107
+ const { product } = data;
108
+
109
+ if (!variant) {
110
+ return <Table history={product.history} days={days} />;
111
+ }
112
+
113
+ const selectedVariant = product.variants.values.find(
114
+ value => value.articleNumber === variant.articleNumber
115
+ );
116
+
117
+ return <Table history={selectedVariant.history} days={days} />;
118
+ }
119
+
120
+ const Table = ({ history, days }) => {
121
+ const { selectedChannel } = useContext(ChannelContext);
122
+
123
+ if (history?.length === 0) {
124
+ return (
125
+ <div className="price-table">
126
+ <span>{t('No recent price changes the last { days }', { days })}</span>
127
+ </div>
128
+ );
129
+ }
130
+
131
+ return (
132
+ <div className="price-table">
133
+ <ul>
134
+ {history.previousPrice.map(({ timestamp, price }) => (
135
+ <li key={timestamp}>
136
+ <span className="timestamp">
137
+ {new Date(timestamp).toLocaleDateString([
138
+ selectedChannel.language.culture
139
+ ])}
140
+ </span>
141
+ <Price price={price} as="span" />
142
+ </li>
143
+ ))}
144
+ </ul>
145
+ </div>
146
+ );
147
+ };
@@ -0,0 +1,32 @@
1
+ query ProductPriceHistory($articleNumber: String!, $days: Int!) {
2
+ product(articleNumber: $articleNumber) {
3
+ id
4
+ articleNumber
5
+ history(days: $days) {
6
+ previousPrice {
7
+ timestamp
8
+ price {
9
+ incVat
10
+ exVat
11
+ vat
12
+ }
13
+ }
14
+ }
15
+
16
+ variants {
17
+ values {
18
+ articleNumber
19
+ history(days: $days) {
20
+ previousPrice {
21
+ timestamp
22
+ price {
23
+ incVat
24
+ vat
25
+ exVat
26
+ }
27
+ }
28
+ }
29
+ }
30
+ }
31
+ }
32
+ }
@@ -14,7 +14,7 @@ import ContentPage from './components/ContentPage/ContentPage.loadable';
14
14
  const config = {
15
15
  theme,
16
16
  apolloConfig: {
17
- shopid: process.env.REACT_APP_SHOP_ID || 'demostore',
17
+ shopid: process.env.REACT_APP_SHOP_ID || 'kalaskungen',
18
18
  graphQLURI:
19
19
  process.env.REACT_APP_GRAPHQL_URI || 'https://storeapi.jetshop.io/',
20
20
  token:
@@ -46,10 +46,7 @@ const config = {
46
46
  },
47
47
  channelOverrides: {},
48
48
  disableGeoRedirect: true,
49
- singleDomainMode:
50
- typeof process.env.REACT_APP_SINGLE_DOMAIN_MODE === 'undefined'
51
- ? true
52
- : process.env.REACT_APP_SINGLE_DOMAIN_MODE, // default to true if this env var is not set
49
+ singleDomainMode: false,
53
50
  schemaExtensions: [],
54
51
  preserveRedirect: true,
55
52
  structuredData: {
@@ -197,6 +197,9 @@
197
197
  "free_shipping_and_return_355b42d1": {
198
198
  "message": "Free shipping and return"
199
199
  },
200
+ "getting_the_last_days_days_price_changes_bedecd5": {
201
+ "message": "Getting the last { days } days price changes..."
202
+ },
200
203
  "go_to_country_517a8515": {
201
204
  "message": "Go to { country }"
202
205
  },
@@ -338,6 +341,9 @@
338
341
  "no_orders_found_ed613bce": {
339
342
  "message": "No orders found"
340
343
  },
344
+ "no_recent_price_changes_the_last_days_61d42dda": {
345
+ "message": "No recent price changes the last { days }"
346
+ },
341
347
  "no_results_for_term_7528ef47": {
342
348
  "message": "No results for <Term />"
343
349
  },
@@ -683,6 +689,9 @@
683
689
  "view_password_ec63cb11": {
684
690
  "message": "View password"
685
691
  },
692
+ "view_price_history_8078c9af": {
693
+ "message": "View price history"
694
+ },
686
695
  "visit_product_page_to_add_54331147": {
687
696
  "message": "Visit product page to add"
688
697
  },
@@ -772,5 +772,14 @@
772
772
  },
773
773
  "email_address_is_required_24d62494": {
774
774
  "message": "E-postadress är obligatoriskt."
775
+ },
776
+ "getting_the_last_days_days_price_changes_bedecd5": {
777
+ "message": "Hämtar de senaste { days } dagarnas prisändringar..."
778
+ },
779
+ "no_recent_price_changes_the_last_days_61d42dda": {
780
+ "message": "Hittade inte några prisförändringar senaste { days } dagarna"
781
+ },
782
+ "view_price_history_8078c9af": {
783
+ "message": "Visa prishistorik"
775
784
  }
776
785
  }