@akinon/projectzero 1.108.0-rc.87 → 1.108.0-snapshot-ZERO-3875-occasion-20251229071759

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 (41) hide show
  1. package/CHANGELOG.md +24 -228
  2. package/app-template/.env.example +1 -1
  3. package/app-template/CHANGELOG.md +556 -4937
  4. package/app-template/README.md +1 -25
  5. package/app-template/package.json +25 -21
  6. package/app-template/public/locales/en/account.json +3 -1
  7. package/app-template/public/locales/en/common.json +1 -42
  8. package/app-template/public/locales/en/product.json +23 -1
  9. package/app-template/public/locales/tr/account.json +3 -1
  10. package/app-template/public/locales/tr/common.json +1 -42
  11. package/app-template/public/locales/tr/product.json +22 -0
  12. package/app-template/src/app/[commerce]/[locale]/[currency]/account/orders/[id]/page.tsx +20 -1
  13. package/app-template/src/app/[commerce]/[locale]/[currency]/basket/page.tsx +82 -9
  14. package/app-template/src/app/[commerce]/[locale]/[currency]/landing-page/[pk]/page.tsx +1 -12
  15. package/app-template/src/app/api/virtual-try-on/limited-categories/route.ts +1 -0
  16. package/app-template/src/app/api/virtual-try-on/route.ts +1 -0
  17. package/app-template/src/assets/fonts/pz-icon.css +0 -3
  18. package/app-template/src/components/input.tsx +1 -2
  19. package/app-template/src/components/modal.tsx +2 -0
  20. package/app-template/src/components/select.tsx +1 -1
  21. package/app-template/src/hooks/index.ts +0 -2
  22. package/app-template/src/plugins.js +8 -2
  23. package/app-template/src/settings.js +1 -6
  24. package/app-template/src/views/account/orders/order-detail-header.tsx +1 -1
  25. package/app-template/src/views/basket/basket-item.tsx +13 -16
  26. package/app-template/src/views/basket/summary.tsx +7 -10
  27. package/app-template/src/views/checkout/steps/shipping/address-box.tsx +30 -17
  28. package/app-template/src/views/checkout/steps/shipping/addresses.tsx +1 -1
  29. package/app-template/src/views/guest-login/index.tsx +1 -6
  30. package/app-template/src/views/header/search/index.tsx +5 -17
  31. package/app-template/src/views/product/layout.tsx +15 -1
  32. package/app-template/src/views/product/product-info.tsx +8 -0
  33. package/app-template/src/views/product/slider.tsx +73 -86
  34. package/commands/plugins.ts +14 -29
  35. package/dist/commands/plugins.js +14 -23
  36. package/package.json +1 -1
  37. package/app-template/src/app/[commerce]/[locale]/[currency]/product/[pk]/loading.tsx +0 -67
  38. package/app-template/src/app/api/image-proxy/route.ts +0 -1
  39. package/app-template/src/app/api/similar-product-list/route.ts +0 -1
  40. package/app-template/src/app/api/similar-products/route.ts +0 -1
  41. package/app-template/src/views/basket/basket-content.tsx +0 -106
@@ -18,7 +18,6 @@ import clsx from 'clsx';
18
18
 
19
19
  interface Props {
20
20
  basket: Basket;
21
- onBasketUpdate?: (basket: Basket) => void;
22
21
  }
23
22
 
24
23
  const voucherCodeFormSchema = (t) =>
@@ -28,7 +27,7 @@ const voucherCodeFormSchema = (t) =>
28
27
 
29
28
  export const Summary = (props: Props) => {
30
29
  const { t } = useLocalization();
31
- const { basket, onBasketUpdate } = props;
30
+ const { basket } = props;
32
31
  const router = useRouter();
33
32
  const {
34
33
  register,
@@ -54,7 +53,7 @@ export const Summary = (props: Props) => {
54
53
  const removeVoucherCode = () => {
55
54
  removeVoucherCodeMutation()
56
55
  .unwrap()
57
- .then((basket) => {
56
+ .then((basket) =>
58
57
  dispatch(
59
58
  basketApi.util.updateQueryData(
60
59
  'getBasket',
@@ -63,9 +62,8 @@ export const Summary = (props: Props) => {
63
62
  Object.assign(draftBasket, basket);
64
63
  }
65
64
  )
66
- );
67
- onBasketUpdate?.(basket);
68
- })
65
+ )
66
+ )
69
67
  .catch((error: Error) => {
70
68
  setError('voucherCode', { message: error.data.non_field_errors });
71
69
  });
@@ -76,7 +74,7 @@ export const Summary = (props: Props) => {
76
74
  voucher_code: data.voucherCode
77
75
  })
78
76
  .unwrap()
79
- .then((basket) => {
77
+ .then((basket) =>
80
78
  dispatch(
81
79
  basketApi.util.updateQueryData(
82
80
  'getBasket',
@@ -85,9 +83,8 @@ export const Summary = (props: Props) => {
85
83
  Object.assign(draftBasket, basket);
86
84
  }
87
85
  )
88
- );
89
- onBasketUpdate?.(basket);
90
- })
86
+ )
87
+ )
91
88
  .catch((error: Error) => {
92
89
  setError('voucherCode', { message: error.data.non_field_errors });
93
90
  });
@@ -85,7 +85,7 @@ const AddressBox = ({
85
85
  };
86
86
 
87
87
  const onSubmit = (data) => {
88
- editAddress({ ...data, invalidateTag: 'Addresses' })
88
+ editAddress({ ...data, invalidateTag: 'Checkout' })
89
89
  .unwrap()
90
90
  .then((editAddressResponse) => {
91
91
  handleAddressClick(addressType, editAddressResponse);
@@ -96,7 +96,7 @@ const AddressBox = ({
96
96
  };
97
97
 
98
98
  const handleRemoveAddress = async (addressPk: number) => {
99
- await removeAddress({ id: addressPk, invalidateTag: 'Addresses' });
99
+ await removeAddress({ id: addressPk, invalidateTag: 'Checkout' });
100
100
  setRemoveAddressModalOpen(false);
101
101
  dispatch(resetCheckoutState());
102
102
 
@@ -168,7 +168,10 @@ const AddressBox = ({
168
168
  <Button
169
169
  appearance="ghost"
170
170
  className="italic underline hover:text-secondary-500 hover:!bg-white hover:!border-white p-0 h-auto"
171
- onClick={() => setIsEditAddressModalOpen(true)}
171
+ onClick={(e) => {
172
+ e.stopPropagation();
173
+ setIsEditAddressModalOpen(true);
174
+ }}
172
175
  data-testid="checkout-address-edit"
173
176
  >
174
177
  {t('checkout.address.box.edit')}
@@ -180,21 +183,26 @@ const AddressBox = ({
180
183
  setOpen={setIsEditAddressModalOpen}
181
184
  className="w-full sm:w-[28rem] max-h-[90vh] overflow-y-auto"
182
185
  >
183
- <AddressForm
184
- data={{
185
- ...address,
186
- country: address.country?.pk,
187
- city: address.city?.pk,
188
- township: address.township?.pk,
189
- district: address.district?.pk
190
- }}
191
- onSubmit={onSubmit}
192
- />
186
+ <div onClick={(e) => e.stopPropagation()}>
187
+ <AddressForm
188
+ data={{
189
+ ...address,
190
+ country: address.country?.pk,
191
+ city: address.city?.pk,
192
+ township: address.township?.pk,
193
+ district: address.district?.pk
194
+ }}
195
+ onSubmit={onSubmit}
196
+ />
197
+ </div>
193
198
  </Modal>
194
199
  <Button
195
200
  appearance="ghost"
196
201
  className="italic underline hover:text-secondary-500 hover:!bg-white hover:!border-white p-0 h-auto"
197
- onClick={() => setRemoveAddressModalOpen(true)}
202
+ onClick={(e) => {
203
+ e.stopPropagation();
204
+ setRemoveAddressModalOpen(true);
205
+ }}
198
206
  data-testid="checkout-address-remove"
199
207
  >
200
208
  {t('checkout.address.box.remove')}
@@ -207,14 +215,18 @@ const AddressBox = ({
207
215
  setOpen={setRemoveAddressModalOpen}
208
216
  showCloseButton={false}
209
217
  >
210
- <div className="text-center px-6 py-10">
218
+ <div
219
+ className="text-center px-6 py-10"
220
+ onClick={(e) => e.stopPropagation()}
221
+ >
211
222
  <p className="mb-4">
212
223
  {t('account.address_book.modal.delete_description')}
213
224
  </p>
214
225
  <div className="space-x-3 flex justify-center">
215
226
  <Button
216
227
  appearance="outlined"
217
- onClick={() => {
228
+ onClick={(e) => {
229
+ e.stopPropagation();
218
230
  setRemoveAddressModalOpen(false);
219
231
  }}
220
232
  data-testid="remove-address-modal-cancel"
@@ -224,7 +236,8 @@ const AddressBox = ({
224
236
  <Button
225
237
  appearance="filled"
226
238
  disabled={removeAddressLoading}
227
- onClick={() => {
239
+ onClick={(e) => {
240
+ e.stopPropagation();
228
241
  handleRemoveAddress(address.pk);
229
242
  }}
230
243
  className={
@@ -77,7 +77,7 @@ const Addresses = () => {
77
77
  }, [billing_and_shipping_same]);
78
78
 
79
79
  const onSubmit = (data) => {
80
- addAddress({ ...data, invalidateTag: 'Addresses' })
80
+ addAddress({ ...data, invalidateTag: 'Checkout' })
81
81
  .unwrap()
82
82
  .then((addAddressResponse) => {
83
83
  if (addressList.length === 0) {
@@ -51,14 +51,9 @@ const GuestLogin = () => {
51
51
  ).unwrap();
52
52
 
53
53
  Object.keys(response?.errors || {}).forEach((key) => {
54
- const errorValue = response?.errors[key];
55
- const message = Array.isArray(errorValue)
56
- ? errorValue.join(', ')
57
- : errorValue || '';
58
-
59
54
  setError(key as keyof GuestLoginFormParams, {
60
55
  type: 'custom',
61
- message
56
+ message: response?.errors[key]?.join(', ')
62
57
  });
63
58
  });
64
59
  } catch (error) {
@@ -4,11 +4,11 @@ import { useEffect, useRef, useState } from 'react';
4
4
  import { useAppDispatch, useAppSelector } from '@akinon/next/redux/hooks';
5
5
  import { closeSearch } from '@akinon/next/redux/reducers/header';
6
6
  import clsx from 'clsx';
7
- import { Icon, Input } from '@theme/components';
7
+
8
+ import { Icon } from '@theme/components';
8
9
  import Results from './results';
9
10
  import { ROUTES } from '@theme/routes';
10
11
  import { useLocalization, useRouter } from '@akinon/next/hooks';
11
- import PluginModule, { Component } from '@akinon/next/components/plugin-module';
12
12
 
13
13
  export default function Search() {
14
14
  const { t } = useLocalization();
@@ -41,14 +41,6 @@ export default function Search() {
41
41
  };
42
42
  }, [isSearchOpen, dispatch]);
43
43
 
44
- const handleSearchTextChange = (e: React.ChangeEvent<HTMLInputElement>) => {
45
- setSearchText(e.target.value);
46
- };
47
-
48
- const handleCloseSearch = () => {
49
- dispatch(closeSearch());
50
- };
51
-
52
44
  return (
53
45
  <>
54
46
  <div
@@ -74,9 +66,9 @@ export default function Search() {
74
66
  {t('common.search.results_for')}
75
67
  </span>
76
68
  <div className="flex items-center">
77
- <Input
69
+ <input
78
70
  value={searchText}
79
- onChange={handleSearchTextChange}
71
+ onChange={(e) => setSearchText(e.target.value)}
80
72
  onKeyDown={(e) => {
81
73
  if (e.key === 'Enter' && searchText.trim() !== '') {
82
74
  router.push(`${ROUTES.LIST}/?search_text=${searchText}`);
@@ -86,18 +78,14 @@ export default function Search() {
86
78
  placeholder={t('common.search.placeholder')}
87
79
  ref={inputRef}
88
80
  />
89
-
90
- <PluginModule component={Component.HeaderImageSearchFeature} />
91
-
92
81
  <Icon
93
82
  name="close"
94
83
  size={14}
95
- onClick={handleCloseSearch}
84
+ onClick={() => dispatch(closeSearch())}
96
85
  className="cursor-pointer"
97
86
  />
98
87
  </div>
99
88
  </div>
100
-
101
89
  <Results searchText={searchText} />
102
90
  </div>
103
91
  </div>
@@ -22,6 +22,16 @@ export default async function ProductLayout({
22
22
  breadcrumbData,
23
23
  children
24
24
  }: ProductPageProps) {
25
+ const categoryIds = breadcrumbData
26
+ ?.map((item) => item.extra_context?.attributes?.category_id)
27
+ .filter(Boolean)
28
+ .join(',');
29
+
30
+ const categoryPaths = breadcrumbData
31
+ ?.map((item) => item.path)
32
+ .filter(Boolean)
33
+ .join(',');
34
+
25
35
  return (
26
36
  <div className="container mx-auto">
27
37
  <div className="max-w-5xl mx-auto my-5 px-7">
@@ -31,7 +41,11 @@ export default async function ProductLayout({
31
41
  <div className="col-span-5 lg:col-span-3">
32
42
  <ProductInfoSlider product={data.product} />
33
43
  </div>
34
- <div className="flex flex-col items-center col-span-5 lg:col-span-2">
44
+ <div
45
+ className="flex flex-col items-center col-span-5 lg:col-span-2"
46
+ data-category-ids={categoryIds}
47
+ data-category-paths={categoryPaths}
48
+ >
35
49
  <div className="w-full">{children}</div>
36
50
  </div>
37
51
  </div>
@@ -13,6 +13,7 @@ import { useStockAlert } from '../../hooks/use-stock-alert';
13
13
  import { ProductVariants } from './product-variants';
14
14
  import { ProductActions } from './product-actions';
15
15
  import { ProductShare } from './product-share';
16
+ import PluginModule, { Component } from '@akinon/next/components/plugin-module';
16
17
 
17
18
  export default function ProductInfo({ data }: ProductPageProps) {
18
19
  const { data: session } = useSession();
@@ -105,6 +106,13 @@ export default function ProductInfo({ data }: ProductPageProps) {
105
106
  onCloseModal={closeModal}
106
107
  />
107
108
 
109
+ <PluginModule
110
+ component={Component.VirtualTryOnPlugin}
111
+ props={{
112
+ product: data.product
113
+ }}
114
+ />
115
+
108
116
  <MiscButtons
109
117
  productName={data.product.name}
110
118
  productPk={data.product.pk}
@@ -7,7 +7,6 @@ import { Product } from '@akinon/next/types';
7
7
  import { Image } from '@akinon/next/components/image';
8
8
  import useFavButton from '../../hooks/use-fav-button';
9
9
  import { twMerge } from 'tailwind-merge';
10
- import PluginModule, { Component } from '@akinon/next/components/plugin-module';
11
10
 
12
11
  type ProductSliderItem = {
13
12
  product: Product;
@@ -36,102 +35,90 @@ export default function ProductInfoSlider({ product }: ProductSliderItem) {
36
35
  carouselRef.current?.next();
37
36
  };
38
37
 
39
- const handleThumbnailClick = (index: number) => {
38
+ const handleThumbnailClick = (index) => {
40
39
  setActiveIndex(index);
41
40
  carouselRef.current?.goToSlide(index);
42
41
  };
43
42
 
44
43
  return (
45
- <>
46
- <div className="lg:grid lg:grid-cols-6">
47
- <div className="lg:col-span-1">
48
- <div className="flex flex-col items-center justify-center md:mr-[6px]">
49
- <button
50
- onClick={goToPrev}
51
- className={twMerge(
52
- 'hidden justify-center p-2 mb-3 border border-gray-100 rounded-full cursor-pointer lg:block',
53
- [activeIndex === 0 && 'cursor-not-allowed opacity-45']
54
- )}
55
- disabled={activeIndex === 0}
56
- >
57
- <Icon name="chevron-up" size={15} className="fill-[#000000]" />
58
- </button>
59
- <div className="hidden flex-col items-center overflow-scroll w-[80px] max-h-[620px] lg:block">
60
- {product?.productimage_set?.map((item, index) => (
61
- <Image
62
- key={index}
63
- src={item.image}
64
- alt={`Thumbnail ${index}`}
65
- width={80}
66
- height={128}
67
- aspectRatio={80 / 128}
68
- className={twMerge('cursor-pointer', [
69
- activeIndex === index && 'border-2 border-primary'
70
- ])}
71
- onClick={() => handleThumbnailClick(index)}
72
- />
73
- ))}
74
- </div>
75
- <button
76
- onClick={goToNext}
77
- className={twMerge(
78
- 'hidden justify-center p-2 mt-3 border border-gray-100 rounded-full cursor-pointer lg:block',
79
- [
80
- activeIndex === product.productimage_set.length - 1 &&
81
- 'cursor-not-allowed opacity-45'
82
- ]
83
- )}
84
- disabled={activeIndex === product.productimage_set.length - 1}
85
- >
86
- <Icon name="chevron-down" size={15} className="fill-[#000000]" />
87
- </button>
88
- </div>
89
- </div>
90
-
91
- <div className="relative lg:col-span-5">
92
- <FavButton className="absolute right-8 top-6 z-[20] sm:hidden" />
93
-
94
- <PluginModule
95
- component={Component.ProductImageSearchFeature}
96
- props={{
97
- product,
98
- activeIndex,
99
- showResetButton: true
100
- }}
101
- />
102
-
103
- <CarouselCore
104
- responsive={{
105
- all: {
106
- breakpoint: { max: 5000, min: 0 },
107
- items: 1
108
- }
109
- }}
110
- arrows={false}
111
- swipeable={true}
112
- ref={carouselRef}
113
- afterChange={(previousSlide, { currentSlide }) => {
114
- setActiveIndex(currentSlide);
115
- }}
116
- containerAspectRatio={{ mobile: 520 / 798, desktop: 484 / 726 }}
44
+ <div className="lg:grid lg:grid-cols-6">
45
+ <div className="lg:col-span-1">
46
+ <div className="flex flex-col items-center justify-center md:mr-[6px]">
47
+ <button
48
+ onClick={goToPrev}
49
+ className={twMerge(
50
+ 'hidden justify-center p-2 mb-3 border border-gray-100 rounded-full cursor-pointer lg:block',
51
+ [activeIndex === 0 && 'cursor-not-allowed opacity-45']
52
+ )}
53
+ disabled={activeIndex === 0}
117
54
  >
118
- {product?.productimage_set?.map((item, i) => (
55
+ <Icon name="chevron-up" size={15} className="fill-[#000000]" />
56
+ </button>
57
+ <div className="hidden flex-col items-center overflow-scroll w-[80px] max-h-[620px] lg:block">
58
+ {product?.productimage_set?.map((item, index) => (
119
59
  <Image
120
- key={i}
60
+ key={index}
121
61
  src={item.image}
122
- alt={product?.name || 'Product image'}
123
- draggable={false}
124
- aspectRatio={484 / 726}
125
- sizes="(min-width: 425px) 512px,
126
- (min-width: 601px) 576px,
127
- (min-width: 768px) 336px,
128
- (min-width: 1024px) 484px, 368px"
129
- fill
62
+ alt={`Thumbnail ${index}`}
63
+ width={80}
64
+ height={128}
65
+ className={twMerge('cursor-pointer', [
66
+ activeIndex === index && 'border-2 border-primary'
67
+ ])}
68
+ onClick={() => handleThumbnailClick(index)}
130
69
  />
131
70
  ))}
132
- </CarouselCore>
71
+ </div>
72
+ <button
73
+ onClick={goToNext}
74
+ className={twMerge(
75
+ 'hidden justify-center p-2 mt-3 border border-gray-100 rounded-full cursor-pointer lg:block',
76
+ [
77
+ activeIndex === product.productimage_set.length - 1 &&
78
+ 'cursor-not-allowed opacity-45'
79
+ ]
80
+ )}
81
+ disabled={activeIndex === product.productimage_set.length - 1}
82
+ >
83
+ <Icon name="chevron-down" size={15} className="fill-[#000000]" />
84
+ </button>
133
85
  </div>
134
86
  </div>
135
- </>
87
+
88
+ <div className="relative lg:col-span-5">
89
+ <FavButton className="absolute right-8 top-6 z-[20] sm:hidden" />
90
+
91
+ <CarouselCore
92
+ responsive={{
93
+ all: {
94
+ breakpoint: { max: 5000, min: 0 },
95
+ items: 1
96
+ }
97
+ }}
98
+ arrows={false}
99
+ swipeable={true}
100
+ ref={carouselRef}
101
+ afterChange={(previousSlide, { currentSlide }) => {
102
+ setActiveIndex(currentSlide);
103
+ }}
104
+ containerAspectRatio={{ mobile: 520 / 798, desktop: 484 / 726 }}
105
+ >
106
+ {product?.productimage_set?.map((item, i) => (
107
+ <Image
108
+ key={i}
109
+ src={item.image}
110
+ alt={product.name}
111
+ draggable={false}
112
+ aspectRatio={484 / 726}
113
+ sizes="(min-width: 425px) 512px,
114
+ (min-width: 601px) 576px,
115
+ (min-width: 768px) 336px,
116
+ (min-width: 1024px) 484px, 368px"
117
+ fill
118
+ />
119
+ ))}
120
+ </CarouselCore>
121
+ </div>
122
+ </div>
136
123
  );
137
124
  }
@@ -29,14 +29,7 @@ async function checkVersion(pkg: PackageJson) {
29
29
 
30
30
  if (!semver.satisfies(pkg.dependencies['@akinon/next'], latestVersion)) {
31
31
  console.warn(
32
- `\x1b[43m Warning: The "${packageName}" package is currently at`,
33
- `\x1b[41m version ${pkg.dependencies['@akinon/next']}`,
34
- `\x1b[43m Please upgrade it to the latest version (${latestVersion}) to ensure plugin compatibility.`,
35
- '\x1b[0m\n'
36
- );
37
- } else {
38
- console.log(
39
- `\x1b[42m Info: The package "${packageName}" is currently in the current version (${latestVersion}).`,
32
+ `\x1b[43mWarning: The "${packageName}" package is currently at version ${pkg.dependencies['@akinon/next']}. Please upgrade it to the latest version (${latestVersion}) to ensure plugin compatibility.`,
40
33
  '\x1b[0m\n'
41
34
  );
42
35
  }
@@ -61,27 +54,7 @@ export default async () => {
61
54
  }
62
55
  }
63
56
 
64
- function findPackageJson(): PackageJson {
65
- const packageJsonPaths = [
66
- path.resolve(rootDir, './package.json'),
67
- path.resolve(rootDir, './apps/projectzeronext/package.json')
68
- ];
69
-
70
- for (const packageJsonPath of packageJsonPaths) {
71
- try {
72
- const pkg = require(packageJsonPath);
73
- if (pkg.dependencies['@akinon/next']) {
74
- return pkg;
75
- }
76
- } catch (error) {
77
- continue;
78
- }
79
- }
80
-
81
- throw new Error('Could not find package.json with @akinon/next dependency');
82
- }
83
-
84
- const pkg = findPackageJson();
57
+ const pkg: PackageJson = require(path.resolve(rootDir, './package.json'));
85
58
  await checkVersion(pkg);
86
59
 
87
60
  const pluginsFilePath = findPluginsFilePath();
@@ -164,6 +137,10 @@ export default async () => {
164
137
  name: 'Tamara Payment Extension',
165
138
  value: 'pz-tamara-extension'
166
139
  },
140
+ {
141
+ name: 'Similar Products',
142
+ value: 'pz-similar-products'
143
+ },
167
144
  {
168
145
  name: 'Hepsipay',
169
146
  value: 'pz-hepsipay'
@@ -171,6 +148,14 @@ export default async () => {
171
148
  {
172
149
  name: 'Flow Payment',
173
150
  value: 'pz-flow-payment'
151
+ },
152
+ {
153
+ name: 'Virtual Try-On',
154
+ value: 'pz-virtual-try-on'
155
+ },
156
+ {
157
+ name: 'CyberSource UC',
158
+ value: 'pz-cybersource-uc'
174
159
  }
175
160
  ];
176
161
 
@@ -50,10 +50,7 @@ function checkVersion(pkg) {
50
50
  const pkgInfo = (yield response.json());
51
51
  const latestVersion = pkgInfo['dist-tags'].latest;
52
52
  if (!semver_1.default.satisfies(pkg.dependencies['@akinon/next'], latestVersion)) {
53
- console.warn(`\x1b[43m Warning: The "${packageName}" package is currently at`, `\x1b[41m version ${pkg.dependencies['@akinon/next']}`, `\x1b[43m Please upgrade it to the latest version (${latestVersion}) to ensure plugin compatibility.`, '\x1b[0m\n');
54
- }
55
- else {
56
- console.log(`\x1b[42m Info: The package "${packageName}" is currently in the current version (${latestVersion}).`, '\x1b[0m\n');
53
+ console.warn(`\x1b[43mWarning: The "${packageName}" package is currently at version ${pkg.dependencies['@akinon/next']}. Please upgrade it to the latest version (${latestVersion}) to ensure plugin compatibility.`, '\x1b[0m\n');
57
54
  }
58
55
  }
59
56
  catch (error) {
@@ -75,25 +72,7 @@ exports.default = () => __awaiter(void 0, void 0, void 0, function* () {
75
72
  throw new Error('plugins.js was not found in either of the expected locations.');
76
73
  }
77
74
  }
78
- function findPackageJson() {
79
- const packageJsonPaths = [
80
- path_1.default.resolve(rootDir, './package.json'),
81
- path_1.default.resolve(rootDir, './apps/projectzeronext/package.json')
82
- ];
83
- for (const packageJsonPath of packageJsonPaths) {
84
- try {
85
- const pkg = require(packageJsonPath);
86
- if (pkg.dependencies['@akinon/next']) {
87
- return pkg;
88
- }
89
- }
90
- catch (error) {
91
- continue;
92
- }
93
- }
94
- throw new Error('Could not find package.json with @akinon/next dependency');
95
- }
96
- const pkg = findPackageJson();
75
+ const pkg = require(path_1.default.resolve(rootDir, './package.json'));
97
76
  yield checkVersion(pkg);
98
77
  const pluginsFilePath = findPluginsFilePath();
99
78
  let installedPlugins = [];
@@ -173,6 +152,10 @@ exports.default = () => __awaiter(void 0, void 0, void 0, function* () {
173
152
  name: 'Tamara Payment Extension',
174
153
  value: 'pz-tamara-extension'
175
154
  },
155
+ {
156
+ name: 'Similar Products',
157
+ value: 'pz-similar-products'
158
+ },
176
159
  {
177
160
  name: 'Hepsipay',
178
161
  value: 'pz-hepsipay'
@@ -180,6 +163,14 @@ exports.default = () => __awaiter(void 0, void 0, void 0, function* () {
180
163
  {
181
164
  name: 'Flow Payment',
182
165
  value: 'pz-flow-payment'
166
+ },
167
+ {
168
+ name: 'Virtual Try-On',
169
+ value: 'pz-virtual-try-on'
170
+ },
171
+ {
172
+ name: 'CyberSource UC',
173
+ value: 'pz-cybersource-uc'
183
174
  }
184
175
  ];
185
176
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@akinon/projectzero",
3
- "version": "1.108.0-rc.87",
3
+ "version": "1.108.0-snapshot-ZERO-3875-occasion-20251229071759",
4
4
  "private": false,
5
5
  "description": "CLI tool to manage your Project Zero Next project",
6
6
  "bin": {