@ikas/storefront 4.0.0-alpha.43 → 4.0.0-alpha.44

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.
Files changed (34) hide show
  1. package/package.json +11 -11
  2. package/src/components/checkout/components/address-form/model.ts +1 -0
  3. package/src/components/checkout/components/button/style.module.scss +2 -2
  4. package/src/components/checkout/components/cart-summary/cart-item/index.tsx +11 -26
  5. package/src/components/checkout/components/cart-summary/cart-item/style.module.scss +53 -13
  6. package/src/components/checkout/components/cart-summary/index.tsx +23 -16
  7. package/src/components/checkout/components/cart-summary/style.module.scss +48 -3
  8. package/src/components/checkout/components/customer-addresses/index.tsx +1 -0
  9. package/src/components/checkout/components/customer-addresses/model.ts +16 -8
  10. package/src/components/checkout/components/error/index.tsx +1 -1
  11. package/src/components/checkout/components/error/unknown-error/index.tsx +4 -2
  12. package/src/components/checkout/index.tsx +14 -7
  13. package/src/components/checkout/model.ts +126 -37
  14. package/src/components/checkout/steps/step-info/index.tsx +9 -3
  15. package/src/components/checkout/steps/step-payment/billing-address/index.tsx +1 -1
  16. package/src/components/checkout/steps/step-payment/index.tsx +5 -1
  17. package/src/components/checkout/steps/step-success/index.tsx +5 -3
  18. package/src/components/page-editor/ThemeComponentEditor.tsx +4 -0
  19. package/src/models/data/country/index.ts +4 -0
  20. package/src/models/data/country/location-translations/index.ts +15 -0
  21. package/src/models/data/order/line-item/base-unit/index.ts +22 -0
  22. package/src/models/data/order/line-item/base-unit/unit-type/index.ts +14 -0
  23. package/src/models/data/order/line-item/index.ts +42 -5
  24. package/src/models/data/order/line-item/variant/index.ts +8 -0
  25. package/src/models/data/order/line-item/variant/price/index.ts +2 -0
  26. package/src/models/data/order/line-item/variant/unit/index.ts +17 -0
  27. package/src/models/data/product/attribute-value/index.ts +40 -0
  28. package/src/models/data/product/base-unit/index.ts +19 -0
  29. package/src/models/data/product/index.ts +5 -0
  30. package/src/models/data/product/variant/index.ts +3 -0
  31. package/src/models/data/product/variant/unit/index.ts +17 -0
  32. package/src/models/data/raffle/index.ts +2 -2
  33. package/src/models/data/storefront/routing/index.tsx +4 -0
  34. package/src/models/data/category/init.ts +0 -33
@@ -20,6 +20,7 @@ import {
20
20
  IkasTransactionStatus,
21
21
  IkasCampaignOfferTargetPageType,
22
22
  IkasCampaignOfferProduct,
23
+ IkasOrderShippingMethod,
23
24
  } from "../../models";
24
25
  import { IkasOrderAddress } from "../../models/data/order/address";
25
26
  import {
@@ -174,6 +175,11 @@ export default class CheckoutViewModel {
174
175
  } else {
175
176
  return this.changeStep(CheckoutStep.INFO);
176
177
  }
178
+ } else if (
179
+ this.step === CheckoutStep.SUCCESS &&
180
+ !this.canProceedToPayment
181
+ ) {
182
+ return this.changeStep(CheckoutStep.INFO);
177
183
  } else if (
178
184
  ![
179
185
  CheckoutStep.INFO,
@@ -250,15 +256,6 @@ export default class CheckoutViewModel {
250
256
  }
251
257
  }
252
258
 
253
- if (this.step === CheckoutStep.PAYMENT) {
254
- if (this.isInStoreDelivery) {
255
- this.checkout.billingAddress = new IkasOrderAddress();
256
- if (this.checkoutSettings) {
257
- this.checkout.billingAddress.checkoutSettings = this.checkoutSettings;
258
- }
259
- }
260
- }
261
-
262
259
  if (this.step !== CheckoutStep.SUCCESS) {
263
260
  if (this.checkout.isComplete) {
264
261
  return this.changeStep(CheckoutStep.SUCCESS);
@@ -369,7 +366,9 @@ export default class CheckoutViewModel {
369
366
 
370
367
  get canProceedToShipping() {
371
368
  return (
372
- this.checkout.shippingAddress?.isValid &&
369
+ (this.isDigitalOnly
370
+ ? this.checkout.billingAddress?.isValid
371
+ : this.checkout.shippingAddress?.isValid) &&
373
372
  this.checkout.hasValidCustomerEmail &&
374
373
  this.error?.type !== ErrorType.NO_SHIPPING_ERROR
375
374
  );
@@ -435,6 +434,12 @@ export default class CheckoutViewModel {
435
434
  );
436
435
  }
437
436
 
437
+ get isDigitalOnly() {
438
+ return (
439
+ this.checkout.shippingMethod === IkasOrderShippingMethod.DIGITAL_DELIVERY
440
+ );
441
+ }
442
+
438
443
  // VALIDATIONS END
439
444
 
440
445
  saveCart = async () => {
@@ -445,12 +450,17 @@ export default class CheckoutViewModel {
445
450
  }
446
451
 
447
452
  if (
448
- this.step === CheckoutStep.INFO ||
449
- this.step === CheckoutStep.SHIPPING
453
+ (this.step === CheckoutStep.INFO ||
454
+ this.step === CheckoutStep.SHIPPING) &&
455
+ !this.isDigitalOnly
450
456
  ) {
451
457
  input.billingAddress = null;
452
458
  }
453
459
 
460
+ if (this.isDigitalOnly) {
461
+ input.shippingAddress = null;
462
+ }
463
+
454
464
  const response = await CartStoreAPI.saveCart({ input });
455
465
 
456
466
  if (response?.graphQLErrors && response.graphQLErrors.length) {
@@ -463,6 +473,7 @@ export default class CheckoutViewModel {
463
473
  } else {
464
474
  throw {
465
475
  type: ErrorType.API_ERROR,
476
+ data: response.firstErrorMessage,
466
477
  };
467
478
  }
468
479
  }
@@ -517,6 +528,7 @@ export default class CheckoutViewModel {
517
528
  if (!checkStocksResponse.isSuccess) {
518
529
  throw {
519
530
  type: ErrorType.API_ERROR,
531
+ data: checkStocksResponse.firstErrorMessage,
520
532
  };
521
533
  }
522
534
 
@@ -562,6 +574,7 @@ export default class CheckoutViewModel {
562
574
  if (!response.isSuccess || !response.data?.length) {
563
575
  this.error = {
564
576
  type: ErrorType.API_ERROR,
577
+ data: response.firstErrorMessage,
565
578
  };
566
579
  return;
567
580
  }
@@ -615,7 +628,7 @@ export default class CheckoutViewModel {
615
628
  try {
616
629
  await this.checkStocks();
617
630
  } catch (err) {
618
- if (err.type) {
631
+ if (typeof err.type !== undefined) {
619
632
  this.error = err;
620
633
  } else {
621
634
  console.log(err);
@@ -639,6 +652,7 @@ export default class CheckoutViewModel {
639
652
  ) {
640
653
  this.error = {
641
654
  type: ErrorType.API_ERROR,
655
+ data: paymentGatewaysResponse.firstErrorMessage,
642
656
  };
643
657
  return;
644
658
  }
@@ -711,18 +725,29 @@ export default class CheckoutViewModel {
711
725
  this.checkout.customer = new IkasOrderCustomer(
712
726
  this.store.customerStore.customer as any
713
727
  );
714
- } else if (!this.checkout.customer)
715
- this.checkout.customer = new IkasOrderCustomer({});
728
+ } else {
729
+ this.checkout.customer = new IkasOrderCustomer(
730
+ this.checkout.customer || {}
731
+ );
732
+ }
716
733
  };
717
734
 
718
735
  createShippingAddress = () => {
736
+ if (this.isDigitalOnly) return;
737
+
719
738
  if (!this.checkout.shippingAddress) {
720
- const customerAddresses = this.store.customerStore.customer?.addresses;
721
- this.onSelectedShippingAddressIdChange(
722
- customerAddresses?.length ? customerAddresses[0].id! : "-1"
723
- );
739
+ if (!!this.store.customerStore.customer) {
740
+ const customerAddresses = this.store.customerStore.customer.addresses;
741
+ this.onSelectedShippingAddressIdChange(
742
+ customerAddresses?.length ? customerAddresses[0].id! : "-1"
743
+ );
744
+ } else {
745
+ this.onSelectedShippingAddressIdChange("-1");
746
+ }
724
747
  } else {
725
- this.selectedShippingAddressId = this.checkout.shippingAddress.id || "-1";
748
+ this.checkout.shippingAddress = new IkasOrderAddress(
749
+ _cloneDeep(this.checkout.shippingAddress) || {}
750
+ );
726
751
  this.checkout.shippingAddress.checkoutSettings = this.checkoutSettings;
727
752
  }
728
753
  };
@@ -733,26 +758,21 @@ export default class CheckoutViewModel {
733
758
  USE_DIFFERENT_ADDRESS_KEY
734
759
  );
735
760
 
736
- if (this.useDifferentAddress) {
737
- if (this.checkout.billingAddress) {
738
- this.selectedBillingAddressId =
739
- this.checkout.billingAddress.id || "-1";
740
- }
741
- this.checkout.billingAddress =
742
- this.checkout.billingAddress || new IkasOrderAddress();
743
- } else {
744
- if (this.isInStoreDelivery || this.checkout.billingAddress) {
745
- this.checkout.billingAddress = new IkasOrderAddress(
746
- _cloneDeep(this.checkout.billingAddress) || {}
761
+ if (!this.checkout.billingAddress) {
762
+ if (!!this.store.customerStore.customer) {
763
+ const customerAddresses = this.store.customerStore.customer.addresses;
764
+ this.onSelectedBillingAddressIdChange(
765
+ customerAddresses?.length ? customerAddresses[0].id! : "-1"
747
766
  );
748
767
  } else {
749
- this.checkout.billingAddress = new IkasOrderAddress(
750
- _cloneDeep(this.checkout.shippingAddress) || {}
751
- );
768
+ this.onSelectedBillingAddressIdChange("-1");
752
769
  }
770
+ } else {
771
+ this.checkout.billingAddress = new IkasOrderAddress(
772
+ _cloneDeep(this.checkout.billingAddress) || {}
773
+ );
774
+ this.checkout.billingAddress.checkoutSettings = this.checkoutSettings;
753
775
  }
754
-
755
- this.checkout.billingAddress.checkoutSettings = this.checkoutSettings;
756
776
  }
757
777
  };
758
778
 
@@ -1048,6 +1068,34 @@ export default class CheckoutViewModel {
1048
1068
  } else {
1049
1069
  this.changeStep(CheckoutStep.PAYMENT);
1050
1070
  }
1071
+ } catch (err) {
1072
+ if (typeof err.type !== undefined) {
1073
+ this.error = err;
1074
+ } else {
1075
+ console.log(err);
1076
+ this.error = {
1077
+ type: ErrorType.UNKNOWN,
1078
+ };
1079
+ }
1080
+ this.isStepLoading = false;
1081
+ }
1082
+ };
1083
+
1084
+ onProceedToDigitalOnlyPaymentClick = async () => {
1085
+ if (!this.canProceedToPayment) {
1086
+ this.isErrorsVisible = true;
1087
+ return;
1088
+ }
1089
+
1090
+ this.isErrorsVisible = false;
1091
+
1092
+ try {
1093
+ this.isStepLoading = true;
1094
+
1095
+ await this.checkStocks();
1096
+ await this.saveCart();
1097
+
1098
+ this.changeStep(CheckoutStep.PAYMENT);
1051
1099
  } catch (err) {
1052
1100
  if (err.type) {
1053
1101
  this.error = err;
@@ -1076,7 +1124,7 @@ export default class CheckoutViewModel {
1076
1124
  this.error = undefined;
1077
1125
  this.changeStep(CheckoutStep.PAYMENT);
1078
1126
  } catch (err) {
1079
- if (err.type) {
1127
+ if (typeof err.type !== undefined) {
1080
1128
  this.error = err;
1081
1129
  } else {
1082
1130
  console.log(err);
@@ -1118,6 +1166,46 @@ export default class CheckoutViewModel {
1118
1166
  return;
1119
1167
  }
1120
1168
 
1169
+ await this.createSaleTransaction();
1170
+ } catch (err) {
1171
+ if (typeof err.type !== undefined) {
1172
+ this.error = err;
1173
+ } else {
1174
+ this.error = {
1175
+ type: ErrorType.UNKNOWN,
1176
+ };
1177
+ }
1178
+ this.isStepLoading = false;
1179
+ }
1180
+ };
1181
+
1182
+ onCompleteDigitalOnlyPaymentClick = async () => {
1183
+ if (
1184
+ !this.canProceedToPayment ||
1185
+ (this.checkoutSettings.showTermsAndConditionsCheckbox &&
1186
+ !this.isTermsAndConditionsChecked)
1187
+ ) {
1188
+ this.isErrorsVisible = true;
1189
+ return;
1190
+ }
1191
+
1192
+ try {
1193
+ this.isErrorsVisible = false;
1194
+ this.isStepLoading = true;
1195
+
1196
+ await this.checkStocks();
1197
+ await this.saveCart();
1198
+
1199
+ if (this.isCustomFlowStripe) {
1200
+ const stripeFromBtn = document.querySelector("#stripe-form-btn");
1201
+ if (stripeFromBtn) {
1202
+ //@ts-ignore
1203
+ stripeFromBtn.click();
1204
+ }
1205
+
1206
+ return;
1207
+ }
1208
+
1121
1209
  await this.createSaleTransaction();
1122
1210
  } catch (err) {
1123
1211
  if (err.type) {
@@ -1207,6 +1295,7 @@ export default class CheckoutViewModel {
1207
1295
  process.env.NEXT_PUBLIC_BASE_URL + response.data.returnSlug;
1208
1296
  } else {
1209
1297
  throw {
1298
+ data: response.firstErrorMessage,
1210
1299
  type: ErrorType.UNKNOWN,
1211
1300
  };
1212
1301
  }
@@ -31,7 +31,9 @@ const CheckoutStepInfo: React.FC<Props> = ({ vm }) => {
31
31
  );
32
32
 
33
33
  const customerAddressesViewModel = React.useMemo(() => {
34
- return new CustomerAddressesViewModel(vm, "shipping");
34
+ return vm.isDigitalOnly
35
+ ? new CustomerAddressesViewModel(vm, "billing")
36
+ : new CustomerAddressesViewModel(vm, "shipping");
35
37
  }, [vm]);
36
38
 
37
39
  return (
@@ -70,12 +72,16 @@ const CheckoutStepInfo: React.FC<Props> = ({ vm }) => {
70
72
  marginTop: vm.store.customerStore.customer ? "0px" : "32px",
71
73
  }}
72
74
  text={
73
- vm.deliveryMethod === "address"
75
+ vm.deliveryMethod === "address" && !vm.isDigitalOnly
74
76
  ? t("checkout-page:actions.continueWithShipping")
75
77
  : t("checkout-page:actions.continueWithPayment")
76
78
  }
77
79
  isLoading={vm.isStepLoading}
78
- onClick={vm.onProceedToShippingClick}
80
+ onClick={
81
+ vm.isDigitalOnly
82
+ ? vm.onProceedToDigitalOnlyPaymentClick
83
+ : vm.onProceedToShippingClick
84
+ }
79
85
  />
80
86
  )}
81
87
  </div>
@@ -31,7 +31,7 @@ export const BillingAddress: React.FC<Props> = observer(({ vm }) => {
31
31
  marginBottom: vm.useDifferentAddress ? "24px" : "0px",
32
32
  }}
33
33
  >
34
- {vm.deliveryMethod === "address" && (
34
+ {vm.deliveryMethod === "address" && !vm.isDigitalOnly && (
35
35
  <Checkbox
36
36
  value={!vm.useDifferentAddress}
37
37
  hasError={vm.isErrorsVisible && !vm.isTermsAndConditionsChecked}
@@ -93,7 +93,11 @@ export const CheckoutStepPayment: React.FC<Props> = observer(({ vm }) => {
93
93
  }}
94
94
  text={t("checkout-page:actions.completeOrder")}
95
95
  isLoading={vm.isStepLoading}
96
- onClick={vm.onCompletePaymentClick}
96
+ onClick={
97
+ vm.isDigitalOnly
98
+ ? vm.onCompleteDigitalOnlyPaymentClick
99
+ : vm.onCompletePaymentClick
100
+ }
97
101
  />
98
102
 
99
103
  {!!t("checkout-page:securePaymentTooltip") && (
@@ -246,9 +246,11 @@ export const StepSuccess: React.FC<Props> = observer(({ vm }) => {
246
246
  <ExpandableSection title={t("checkout-page:paymentSummary")}>
247
247
  {paymentInfoGrid}
248
248
  </ExpandableSection>
249
- <ExpandableSection title={t("checkout-page:shippingSummary")}>
250
- {contactInfoGrid}
251
- </ExpandableSection>
249
+ {!vm.isDigitalOnly && (
250
+ <ExpandableSection title={t("checkout-page:shippingSummary")}>
251
+ {contactInfoGrid}
252
+ </ExpandableSection>
253
+ )}
252
254
 
253
255
  <div className={styles.Actions}>
254
256
  <div className={styles.HelpText}>
@@ -96,6 +96,8 @@ export class ThemeEditorComponent extends React.Component<Props> {
96
96
  statusUpdatedAt: null,
97
97
  stockLocationId: null,
98
98
  taxValue: null,
99
+ unitPrice: null,
100
+ finalUnitPrice: null,
99
101
  variant: {
100
102
  barcodeList: null,
101
103
  brand: null,
@@ -112,6 +114,8 @@ export class ThemeEditorComponent extends React.Component<Props> {
112
114
  type: null,
113
115
  weight: null,
114
116
  variantValues: [],
117
+ baseUnit: null,
118
+ unit: null,
115
119
  },
116
120
  orderedAt: 0,
117
121
  }),
@@ -1,4 +1,5 @@
1
1
  import { IkasBaseModel } from "../base";
2
+ import { IkasLocationTranslations } from "./location-translations";
2
3
  import { IkasCountry as ICountry } from "@ikas/storefront-models";
3
4
  import { makeObservable, observable } from "mobx";
4
5
 
@@ -9,6 +10,7 @@ export class IkasCountry extends IkasBaseModel implements ICountry {
9
10
  emojiString: string | null = null;
10
11
  iso2: string | null = null;
11
12
  iso3: string | null = null;
13
+ locationTranslations?: IkasLocationTranslations | null = null;
12
14
  name: string;
13
15
  native: string | null = null;
14
16
  phoneCode: string | null = null;
@@ -23,6 +25,7 @@ export class IkasCountry extends IkasBaseModel implements ICountry {
23
25
  this.emojiString = data.emojiString || null;
24
26
  this.iso2 = data.iso2 || null;
25
27
  this.iso3 = data.iso3 || null;
28
+ this.locationTranslations = data.locationTranslations || null;
26
29
  this.name = data.name || "";
27
30
  this.native = data.native || null;
28
31
  this.phoneCode = data.phoneCode || null;
@@ -36,6 +39,7 @@ export class IkasCountry extends IkasBaseModel implements ICountry {
36
39
  emojiString: observable,
37
40
  iso2: observable,
38
41
  iso3: observable,
42
+ locationTranslations: observable,
39
43
  name: observable,
40
44
  native: observable,
41
45
  phoneCode: observable,
@@ -0,0 +1,15 @@
1
+ import { IkasLocationTranslations as ILocationTranslations } from "@ikas/storefront-models";
2
+ import { makeAutoObservable } from "mobx";
3
+
4
+ export class IkasLocationTranslations implements ILocationTranslations {
5
+ de: string | null;
6
+ en: string;
7
+ tr: string;
8
+
9
+ constructor(data: ILocationTranslations) {
10
+ this.de = data.de || null;
11
+ this.en = data.en || "";
12
+ this.tr = data.tr || "";
13
+ makeAutoObservable(this);
14
+ }
15
+ }
@@ -0,0 +1,22 @@
1
+ import {
2
+ IkasProductUnitType,
3
+ IkasOrderLineBaseUnit as IOrderLineBaseUnit,
4
+ } from "@ikas/storefront-models";
5
+ import { makeAutoObservable } from "mobx";
6
+ import { IkasOrderLineVariantUnitType } from "./unit-type";
7
+
8
+ export class IkasOrderLineBaseUnit implements IOrderLineBaseUnit {
9
+ baseAmount: number;
10
+ type: IkasProductUnitType;
11
+ unit: IkasOrderLineVariantUnitType | null;
12
+
13
+ constructor(data: IOrderLineBaseUnit) {
14
+ this.baseAmount = data.baseAmount;
15
+ this.type = data.type;
16
+ this.unit = data.unit ? new IkasOrderLineVariantUnitType(data.unit) : null;
17
+
18
+ makeAutoObservable(this);
19
+ }
20
+ }
21
+
22
+ export { IkasProductUnitType };
@@ -0,0 +1,14 @@
1
+ import { IkasOrderLineVariantUnitType as IOrderLineVariantUnitType } from "@ikas/storefront-models";
2
+ import { makeAutoObservable } from "mobx";
3
+
4
+ export class IkasOrderLineVariantUnitType implements IOrderLineVariantUnitType {
5
+ id: string;
6
+ name: string;
7
+
8
+ constructor(data: IOrderLineVariantUnitType) {
9
+ this.id = data.id;
10
+ this.name = data.name;
11
+
12
+ makeAutoObservable(this);
13
+ }
14
+ }
@@ -20,6 +20,7 @@ export class IkasOrderLineItem extends IkasBaseModel implements IOrderLineItem {
20
20
  discount: IkasOrderLineDiscount | null = null;
21
21
  discountPrice: number | null = null;
22
22
  finalPrice: number | null = null;
23
+ finalUnitPrice: number | null;
23
24
  options: IkasOrderLineItemOption[] | null = null;
24
25
  originalOrderLineItemId: string | null = null;
25
26
  price: number;
@@ -28,6 +29,7 @@ export class IkasOrderLineItem extends IkasBaseModel implements IOrderLineItem {
28
29
  statusUpdatedAt: number | null = null;
29
30
  stockLocationId: string | null = null;
30
31
  taxValue: number | null = null;
32
+ unitPrice: number | null;
31
33
  variant: IkasOrderLineVariant;
32
34
  orderedAt: number;
33
35
 
@@ -42,14 +44,19 @@ export class IkasOrderLineItem extends IkasBaseModel implements IOrderLineItem {
42
44
  this.discount = data.discount
43
45
  ? new IkasOrderLineDiscount(data.discount)
44
46
  : null;
45
- this.discountPrice = data.discountPrice || null;
46
- this.finalPrice = data.finalPrice || null;
47
- (this.options =
48
- data.options?.map((o) => new IkasOrderLineItemOption(o)) || null),
49
- (this.originalOrderLineItemId = data.originalOrderLineItemId || null);
47
+ this.discountPrice = data.discountPrice ?? null;
48
+ this.finalPrice = data.finalPrice ?? null;
49
+ this.finalUnitPrice = data.finalUnitPrice ?? null;
50
+ this.options =
51
+ data.options?.map((o) => new IkasOrderLineItemOption(o)) || null;
52
+ this.originalOrderLineItemId = data.originalOrderLineItemId || null;
50
53
  this.price = data.price;
51
54
  this.quantity = data.quantity;
52
55
  this.status = data.status;
56
+ this.statusUpdatedAt = data.statusUpdatedAt;
57
+ this.stockLocationId = data.stockLocationId;
58
+ this.taxValue = data.taxValue;
59
+ this.unitPrice = data.unitPrice ?? null;
53
60
  this.variant = new IkasOrderLineVariant(data.variant);
54
61
  this.orderedAt = data.orderedAt;
55
62
 
@@ -61,6 +68,7 @@ export class IkasOrderLineItem extends IkasBaseModel implements IOrderLineItem {
61
68
  discount: observable,
62
69
  discountPrice: observable,
63
70
  finalPrice: observable,
71
+ finalUnitPrice: observable,
64
72
  options: observable,
65
73
  originalOrderLineItemId: observable,
66
74
  price: observable,
@@ -69,6 +77,7 @@ export class IkasOrderLineItem extends IkasBaseModel implements IOrderLineItem {
69
77
  statusUpdatedAt: observable,
70
78
  stockLocationId: observable,
71
79
  taxValue: observable,
80
+ unitPrice: observable,
72
81
  variant: observable,
73
82
  orderedAt: observable,
74
83
  //@ts-ignore
@@ -79,6 +88,8 @@ export class IkasOrderLineItem extends IkasBaseModel implements IOrderLineItem {
79
88
  overridenPriceWithQuantity: computed,
80
89
  formattedOverridenPriceWithQuantity: computed,
81
90
  formattedFinalPrice: computed,
91
+ formattedUnitPrice: computed,
92
+ formattedFinalUnitPrice: computed,
82
93
  formattedDiscountPrice: computed,
83
94
  finalPriceWithQuantity: computed,
84
95
  formattedFinalPriceWithQuantity: computed,
@@ -120,6 +131,32 @@ export class IkasOrderLineItem extends IkasBaseModel implements IOrderLineItem {
120
131
  );
121
132
  }
122
133
 
134
+ get formattedUnitPrice() {
135
+ return formatCurrency(
136
+ this.unitPrice || 0,
137
+ this.currencyCode || "",
138
+ this.currencySymbol || ""
139
+ );
140
+ }
141
+
142
+ get formattedFinalUnitPrice() {
143
+ return formatCurrency(
144
+ this.finalUnitPrice || 0,
145
+ this.currencyCode || "",
146
+ this.currencySymbol || ""
147
+ );
148
+ }
149
+
150
+ get unitPriceText() {
151
+ if (this.finalUnitPrice === null) return;
152
+
153
+ return `${formatCurrency(
154
+ this.finalUnitPrice,
155
+ this.currencyCode || "",
156
+ this.currencySymbol || ""
157
+ )} / ${this.variant.baseUnit?.unit?.name || this.variant.baseUnit?.type}`;
158
+ }
159
+
123
160
  get formattedDiscountPrice() {
124
161
  return formatCurrency(
125
162
  this.discountPrice || 0,
@@ -6,9 +6,12 @@ import { IkasOrderLineVariantBrand } from "./brand";
6
6
  import { IkasOrderLineVariantCategory } from "./category";
7
7
  import { IkasOrderLineVariantPrice } from "./price";
8
8
  import { makeAutoObservable } from "mobx";
9
+ import { IkasOrderLineVariantUnit } from "./unit";
10
+ import { IkasOrderLineBaseUnit } from "../base-unit";
9
11
 
10
12
  export class IkasOrderLineVariant implements IOrderLineVariant {
11
13
  barcodeList: string[] | null = null;
14
+ baseUnit: IkasOrderLineBaseUnit | null;
12
15
  brand: IkasOrderLineVariantBrand | null = null;
13
16
  categories: IkasOrderLineVariantCategory[] | null = null;
14
17
  id: string | null = null;
@@ -21,6 +24,7 @@ export class IkasOrderLineVariant implements IOrderLineVariant {
21
24
  tagIds: string[] | null = null;
22
25
  taxValue: number | null = null;
23
26
  type: number | null = null;
27
+ unit: IkasOrderLineVariantUnit | null;
24
28
  weight: number | null = null;
25
29
  variantValues: IkasOrderLineVariantVariantValue[] | null = null;
26
30
 
@@ -29,6 +33,9 @@ export class IkasOrderLineVariant implements IOrderLineVariant {
29
33
 
30
34
  constructor(data: IOrderLineVariant) {
31
35
  this.barcodeList = data.barcodeList || null;
36
+ this.baseUnit = data.baseUnit
37
+ ? new IkasOrderLineBaseUnit(data.baseUnit)
38
+ : null;
32
39
  this.brand = data.brand ? new IkasOrderLineVariantBrand(data.brand) : null;
33
40
  this.categories =
34
41
  data.categories?.map((c) => new IkasOrderLineVariantCategory(c)) || null;
@@ -43,6 +50,7 @@ export class IkasOrderLineVariant implements IOrderLineVariant {
43
50
  this.tagIds = data.tagIds || null;
44
51
  this.taxValue = data.taxValue || null;
45
52
  this.type = data.type || null;
53
+ this.unit = data.unit ? new IkasOrderLineVariantUnit(data.unit) : null;
46
54
  this.weight = data.weight || null;
47
55
  this.variantValues =
48
56
  data.variantValues?.map(
@@ -7,6 +7,7 @@ export class IkasOrderLineVariantPrice implements IOrderLineVariantPrice {
7
7
  discountPrice: number | null = null;
8
8
  priceListId: string | null = null;
9
9
  sellPrice: number;
10
+ unitPrice: number | null;
10
11
 
11
12
  constructor(data: IOrderLineVariantPrice) {
12
13
  this.buyPrice = data.buyPrice || null;
@@ -14,6 +15,7 @@ export class IkasOrderLineVariantPrice implements IOrderLineVariantPrice {
14
15
  this.discountPrice = data.discountPrice || null;
15
16
  this.priceListId = data.priceListId || null;
16
17
  this.sellPrice = data.sellPrice;
18
+ this.unitPrice = data.unitPrice;
17
19
 
18
20
  makeAutoObservable(this);
19
21
  }
@@ -0,0 +1,17 @@
1
+ import {
2
+ IkasProductUnitType,
3
+ IkasOrderLineVariantUnit as IOrderLineVariantUnit,
4
+ } from "@ikas/storefront-models";
5
+ import { makeAutoObservable } from "mobx";
6
+
7
+ export class IkasOrderLineVariantUnit implements IOrderLineVariantUnit {
8
+ amount: number;
9
+ type: IkasProductUnitType;
10
+
11
+ constructor(data: IOrderLineVariantUnit) {
12
+ this.amount = data.amount;
13
+ this.type = data.type;
14
+
15
+ makeAutoObservable(this);
16
+ }
17
+ }
@@ -5,9 +5,11 @@ import {
5
5
  IkasProductAttributeValue as IProductAttributeValue,
6
6
  IkasAttributeTableCellValue as IAttributeTableCellValue,
7
7
  IkasProductAttributeMap as IProductAttributeMap,
8
+ IkasProductAttributeType,
8
9
  } from "@ikas/storefront-models";
9
10
  import { makeAutoObservable } from "mobx";
10
11
  import { IkasProductAttributeValueFunctions } from "@ikas/storefront-model-functions";
12
+ import ProductStore from "../../../../store/product";
11
13
 
12
14
  export class IkasProductAttributeValue implements IProductAttributeValue {
13
15
  imageIds: string[] | null = null;
@@ -40,6 +42,44 @@ export class IkasProductAttributeValue implements IProductAttributeValue {
40
42
  get tableValue() {
41
43
  return IkasProductAttributeValueFunctions.getTableValue(this.value);
42
44
  }
45
+
46
+ get productIds() {
47
+ if (
48
+ this.productAttribute?.type !== IkasProductAttributeType.PRODUCT ||
49
+ !this.value
50
+ ) {
51
+ return [];
52
+ }
53
+
54
+ try {
55
+ return JSON.parse(this.value) as string[];
56
+ } catch (err) {
57
+ console.error(err);
58
+ return [];
59
+ }
60
+ }
61
+
62
+ async getProducts() {
63
+ if (
64
+ this.productAttribute?.type !== IkasProductAttributeType.PRODUCT ||
65
+ !this.value
66
+ ) {
67
+ return [];
68
+ }
69
+
70
+ try {
71
+ const response = await ProductStore.searchProducts({
72
+ input: {
73
+ productIdList: this.productIds,
74
+ },
75
+ });
76
+
77
+ return response.data?.data || [];
78
+ } catch (err) {
79
+ console.error(err);
80
+ return [];
81
+ }
82
+ }
43
83
  }
44
84
 
45
85
  export class IkasAttributeTableCellValue implements IAttributeTableCellValue {