@akinon/projectzero 1.42.0 → 1.43.0-rc.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.
Files changed (40) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/README.md +3 -2
  3. package/app-template/.lintstagedrc.js +5 -4
  4. package/app-template/CHANGELOG.md +403 -7
  5. package/app-template/docs/basic-setup.md +1 -1
  6. package/app-template/docs/plugins.md +7 -7
  7. package/app-template/package-lock.json +29303 -0
  8. package/app-template/package.json +23 -21
  9. package/app-template/public/locales/en/account.json +4 -4
  10. package/app-template/public/locales/tr/account.json +1 -1
  11. package/app-template/src/app/[commerce]/[locale]/[currency]/[...prettyurl]/page.tsx +8 -0
  12. package/app-template/src/app/[commerce]/[locale]/[currency]/account/address/page.tsx +1 -1
  13. package/app-template/src/app/[commerce]/[locale]/[currency]/account/coupons/page.tsx +4 -4
  14. package/app-template/src/app/[commerce]/[locale]/[currency]/account/profile/page.tsx +1 -0
  15. package/app-template/src/app/[commerce]/[locale]/[currency]/basket/page.tsx +1 -1
  16. package/app-template/src/app/[commerce]/[locale]/[currency]/orders/completed/[token]/page.tsx +12 -8
  17. package/app-template/src/components/checkbox.tsx +2 -2
  18. package/app-template/src/components/input.tsx +19 -7
  19. package/app-template/src/components/price.tsx +9 -4
  20. package/app-template/src/redux/reducers/category.ts +7 -1
  21. package/app-template/src/views/account/address-card.tsx +2 -2
  22. package/app-template/src/views/account/address-form.tsx +22 -7
  23. package/app-template/src/views/account/contact-form.tsx +23 -6
  24. package/app-template/src/views/account/favorite-item.tsx +2 -2
  25. package/app-template/src/views/account/favourite-products/favourite-products-list.tsx +5 -1
  26. package/app-template/src/views/category/category-info.tsx +31 -17
  27. package/app-template/src/views/category/filters/filter-item.tsx +131 -0
  28. package/app-template/src/views/category/filters/index.tsx +5 -105
  29. package/app-template/src/views/checkout/steps/payment/options/credit-card/index.tsx +33 -4
  30. package/app-template/src/views/checkout/steps/payment/options/redirection.tsx +43 -37
  31. package/app-template/src/views/checkout/steps/shipping/address-box.tsx +2 -2
  32. package/app-template/src/views/checkout/steps/shipping/addresses.tsx +1 -1
  33. package/app-template/src/views/checkout/steps/shipping/shipping-options.tsx +128 -35
  34. package/app-template/src/views/find-in-store/index.tsx +2 -3
  35. package/app-template/src/views/header/mobile-menu.tsx +25 -8
  36. package/app-template/tsconfig.json +14 -4
  37. package/app-template/yarn.lock +1824 -1953
  38. package/commands/create.ts +29 -5
  39. package/dist/commands/create.js +25 -2
  40. package/package.json +2 -2
@@ -1,20 +1,69 @@
1
1
  import { useAppDispatch, useAppSelector } from '@akinon/next/redux/hooks';
2
2
  import { setCurrentStep } from '@akinon/next/redux/reducers/checkout';
3
3
  import { RootState } from '@theme/redux/store';
4
- import { useSetShippingOptionMutation } from '@akinon/next/data/client/checkout';
4
+ import {
5
+ useSetShippingOptionMutation,
6
+ useSetDataSourceShippingOptionsMutation
7
+ } from '@akinon/next/data/client/checkout';
5
8
  import { Price, Button, Radio } from '@theme/components';
6
9
  import { CheckoutStep } from '@akinon/next/types';
7
10
  import { useLocalization } from '@akinon/next/hooks';
11
+ import { useEffect, useState } from 'react';
8
12
 
9
13
  const ShippingOptions = () => {
10
14
  const { t } = useLocalization();
11
- const { steps, shippingOptions, preOrder, addressList } = useAppSelector(
12
- (state: RootState) => state.checkout
13
- );
14
- const { shipping_option, shipping_address } = preOrder ?? {};
15
+ const {
16
+ steps,
17
+ shippingOptions,
18
+ dataSourceShippingOptions,
19
+ preOrder,
20
+ addressList
21
+ } = useAppSelector((state: RootState) => state.checkout);
22
+ const { shipping_option, shipping_address, data_source_shipping_options } =
23
+ preOrder ?? {};
24
+
25
+ const [selectedPks, setSelectedPks] = useState<
26
+ { dataSourcePk: number; optionPk: number }[] | null
27
+ >(null);
28
+
15
29
  const [setShippingOption] = useSetShippingOptionMutation();
30
+ const [setDataSourceShippingOption] =
31
+ useSetDataSourceShippingOptionsMutation();
32
+
16
33
  const dispatch = useAppDispatch();
17
34
 
35
+ useEffect(() => {
36
+ if (!data_source_shipping_options) return;
37
+
38
+ const initialSelectedPks = data_source_shipping_options.map((option) => ({
39
+ dataSourcePk: option.data_source.pk,
40
+ optionPk: option.pk
41
+ }));
42
+
43
+ setSelectedPks(initialSelectedPks);
44
+ }, [data_source_shipping_options]);
45
+
46
+ const updateData = (dataSourcePk: number, newPk: number) => {
47
+ const updatedSelectedPks = selectedPks?.map((item) =>
48
+ item.dataSourcePk === dataSourcePk ? { ...item, optionPk: newPk } : item
49
+ );
50
+
51
+ if (!updatedSelectedPks) return;
52
+
53
+ setSelectedPks(updatedSelectedPks);
54
+
55
+ const pks = updatedSelectedPks.map((item) => item.optionPk);
56
+ setDataSourceShippingOption(pks);
57
+ };
58
+
59
+ const handleRadioChange = (
60
+ e: React.ChangeEvent<HTMLInputElement>,
61
+ dataSourcePk: number
62
+ ) => {
63
+ const newPk = parseInt(e.currentTarget.value);
64
+ updateData(dataSourcePk, newPk);
65
+ };
66
+
18
67
  return (
19
68
  <div className="w-full lg:w-2/5">
20
69
  <div className="border-b border-gray-400 px-8 py-4">
@@ -32,37 +81,81 @@ const ShippingOptions = () => {
32
81
  {t('checkout.address.shipping.chosen_address')}:{' '}
33
82
  {shipping_address?.city.name}
34
83
  </p>
35
- {shippingOptions.map((option) => (
36
- <div
37
- key={option.pk}
38
- className="py-4 border-t border-gray-400 flex justify-between"
39
- >
40
- <Radio
41
- name="shipping"
42
- checked={option.pk === shipping_option?.pk}
43
- onChange={() => {
44
- setShippingOption(option.pk);
45
- }}
46
- onClick={() => {
47
- setShippingOption(option?.pk);
48
- }}
49
- data-testid={`checkout-shipping-option-${option.pk}`}
84
+ {}
85
+ {shippingOptions && shippingOptions.length > 0 && (
86
+ <>
87
+ {shippingOptions.map((option) => (
88
+ <div
89
+ key={option.pk}
90
+ className="py-4 border-t border-gray-400 flex justify-between"
91
+ >
92
+ <Radio
93
+ name="shipping"
94
+ checked={option.pk === shipping_option?.pk}
95
+ onChange={() => {
96
+ setShippingOption(option.pk);
97
+ }}
98
+ data-testid={`checkout-shipping-option-${option.pk}`}
99
+ >
100
+ {option.name}
101
+ </Radio>
102
+ <span className="text-xs">
103
+ <Price value={option.shipping_amount} />
104
+ </span>
105
+ </div>
106
+ ))}
107
+ <Button
108
+ className="mt-2 w-full"
109
+ disabled={!steps.shipping.completed}
110
+ onClick={() => dispatch(setCurrentStep(CheckoutStep.Payment))}
111
+ data-testid="checkout-shipping-save"
112
+ >
113
+ {t('checkout.address.shipping.button')}
114
+ </Button>
115
+ </>
116
+ )}
117
+ {dataSourceShippingOptions && dataSourceShippingOptions.length > 0 && (
118
+ <>
119
+ {dataSourceShippingOptions.map((option) => (
120
+ <div key={option.pk}>
121
+ <h3 className="text-lg font-bold">{option?.name}</h3>
122
+ {option.data_source_shipping_options.map((opt) => (
123
+ <div
124
+ key={opt.pk}
125
+ className="py-4 border-t border-gray-400 flex justify-between"
126
+ >
127
+ <Radio
128
+ name={`data-source-shipping-${option.pk}`}
129
+ checked={
130
+ selectedPks?.some(
131
+ (item) => item.optionPk === opt.pk
132
+ ) || false
133
+ }
134
+ onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
135
+ handleRadioChange(e, option.pk)
136
+ }
137
+ value={opt.pk}
138
+ data-testid={`checkout-data-source-shipping-${opt.pk}`}
139
+ >
140
+ {opt?.shipping_option_name}
141
+ </Radio>
142
+ <span className="text-xs">
143
+ <Price value={opt?.shipping_amount} />
144
+ </span>
145
+ </div>
146
+ ))}
147
+ </div>
148
+ ))}
149
+ <Button
150
+ className="mt-2 w-full"
151
+ disabled={!steps.shipping.completed}
152
+ onClick={() => dispatch(setCurrentStep(CheckoutStep.Payment))}
153
+ data-testid="checkout-shipping-save"
50
154
  >
51
- {option.name}
52
- </Radio>
53
- <span className="text-xs">
54
- <Price value={option.shipping_amount} />
55
- </span>
56
- </div>
57
- ))}
58
- <Button
59
- className="mt-2 w-full"
60
- disabled={!steps.shipping.completed}
61
- onClick={() => dispatch(setCurrentStep(CheckoutStep.Payment))}
62
- data-testid="checkout-shipping-save"
63
- >
64
- {t('checkout.address.shipping.button')}
65
- </Button>
155
+ {t('checkout.address.shipping.button')}
156
+ </Button>
157
+ </>
158
+ )}
66
159
  </div>
67
160
  )}
68
161
  </div>
@@ -162,10 +162,9 @@ export const FindInStore = ({ productPk, productName, variants }) => {
162
162
  </div>
163
163
  <Link
164
164
  href={`https://maps.google.com/?q=${store.latitude},${store.longitude}`}
165
+ target="_blank"
165
166
  >
166
- <a target="_blank">
167
- <Button>{t('product.find_in_store.directions')}</Button>
168
- </a>
167
+ <Button>{t('product.find_in_store.directions')}</Button>
169
168
  </Link>
170
169
  </div>
171
170
  </Accordion>
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
 
3
- import { useState } from 'react';
3
+ import { useState, useEffect, useRef } from 'react';
4
4
  import { MenuItemType } from '@akinon/next/types';
5
5
  import { useAppDispatch, useAppSelector } from '@akinon/next/redux/hooks';
6
6
  import { closeMobileMenu } from '@akinon/next/redux/reducers/header';
@@ -32,9 +32,30 @@ export default function MobileMenu(props: MobileMenuProps) {
32
32
  (state) => state.header.isMobileMenuOpen
33
33
  );
34
34
 
35
+ const menuRef = useRef<HTMLDivElement>(null);
36
+
37
+ useEffect(() => {
38
+ function handleClickOutside(event: MouseEvent) {
39
+ if (
40
+ isMobileMenuOpen &&
41
+ menuRef.current &&
42
+ !menuRef.current.contains(event.target as Node)
43
+ ) {
44
+ dispatch(closeMobileMenu());
45
+ setSelectedSubMenu(null);
46
+ }
47
+ }
48
+
49
+ document.addEventListener('mousedown', handleClickOutside);
50
+
51
+ return () => {
52
+ document.removeEventListener('mousedown', handleClickOutside);
53
+ };
54
+ // eslint-disable-next-line react-hooks/exhaustive-deps
55
+ }, [isMobileMenuOpen]);
56
+
35
57
  return (
36
58
  <>
37
- {/* MENU OVERLAY */}
38
59
  <div
39
60
  className={clsx(
40
61
  'fixed top-0 left-0 z-30 w-screen h-screen invisible opacity-0 bg-black bg-opacity-80 transition duration-500',
@@ -42,14 +63,10 @@ export default function MobileMenu(props: MobileMenuProps) {
42
63
  '!visible !opacity-100 scroll-lock': isMobileMenuOpen
43
64
  }
44
65
  )}
45
- // TODO: Remove this after we have a better solution for clicking outside of the menu
46
- onClick={() => {
47
- dispatch(closeMobileMenu());
48
- setSelectedSubMenu(null);
49
- }}
50
66
  />
51
- {/* TODO: Add a way to close the menu when clicking outside of it */}
67
+
52
68
  <div
69
+ ref={menuRef}
53
70
  className={clsx(
54
71
  'fixed top-0 left-0 z-50 flex flex-col bg-white w-72 pt-4 h-screen invisible opacity-0 transition duration-500 transform -translate-x-72',
55
72
  {
@@ -3,7 +3,19 @@
3
3
  "display": "Default",
4
4
  "compilerOptions": {
5
5
  "baseUrl": "./src",
6
- "paths": { "@theme/*": ["./*"] },
6
+ "paths": {
7
+ "@theme/*": ["./*"],
8
+ "@root/*": ["./app/[commerce]/[locale]/[currency]/*"],
9
+ "@product/*": ["./app/[commerce]/[locale]/[currency]/product/*"],
10
+ "@group-product/*": [
11
+ "./app/[commerce]/[locale]/[currency]/group-product/*"
12
+ ],
13
+ "@category/*": ["./app/[commerce]/[locale]/[currency]/category/*"],
14
+ "@special-page/*": [
15
+ "./app/[commerce]/[locale]/[currency]/special-page/*"
16
+ ],
17
+ "@flat-page/*": ["./app/[commerce]/[locale]/[currency]/flat-page/*"]
18
+ },
7
19
  "allowSyntheticDefaultImports": true,
8
20
  "composite": false,
9
21
  "declaration": true,
@@ -40,7 +52,5 @@
40
52
  ".next/types/**/*.ts",
41
53
  "../../packages/**/*"
42
54
  ],
43
- "exclude": ["node_modules",
44
- "../../packages/projectzero/app-template"
45
- ]
55
+ "exclude": ["node_modules", "../../packages/projectzero/app-template"]
46
56
  }