@akinon/projectzero 2.0.15-rc.0 → 2.0.15
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.
- package/CHANGELOG.md +2 -4
- package/app-template/.env.example +0 -1
- package/app-template/CHANGELOG.md +31 -70
- package/app-template/README.md +1 -25
- package/app-template/next.config.mjs +1 -4
- package/app-template/package.json +41 -41
- package/app-template/src/hooks/index.ts +0 -2
- package/app-template/src/plugins.js +0 -1
- package/app-template/src/proxy.ts +1 -2
- package/app-template/src/views/header/search/index.tsx +5 -13
- package/app-template/src/views/product/slider.tsx +38 -85
- package/codemods/migrate-page-types/index.js +75 -0
- package/codemods/migrate-page-types/transform.js +169 -0
- package/codemods/upgrade-to-2/index.js +100 -43
- package/commands/plugins.ts +0 -4
- package/dist/commands/plugins.js +0 -4
- package/package.json +1 -1
- package/app-template/src/app/global-error.tsx +0 -22
package/CHANGELOG.md
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
# @akinon/projectzero
|
|
2
2
|
|
|
3
|
-
## 2.0.15
|
|
3
|
+
## 2.0.15
|
|
4
4
|
|
|
5
5
|
### Patch Changes
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
- d99a6a7d5: ZERO-3457_1: Fixed the settings prop and made sure everything is customizable.
|
|
9
|
-
- e18836b2: ZERO-4160: Restore scope in Sentry addon configuration in akinon.json
|
|
7
|
+
- 5df7a236: ZERO-4479: Add migrate-page-types codemod (PageProps -> AsyncPageProps/ResolvedPageProps) and integrate into upgrade-to-2
|
|
10
8
|
|
|
11
9
|
## 2.0.14
|
|
12
10
|
|
|
@@ -7,7 +7,6 @@ NEXT_PUBLIC_URL=http://localhost:3000
|
|
|
7
7
|
SERVICE_BACKEND_URL=https://02fde10fee4440269e695aa10707dfaf.lb.akinoncloud.com
|
|
8
8
|
SITEMAP_S3_BUCKET_NAME=0fb534
|
|
9
9
|
NEXT_PUBLIC_VIRTUAL_TRY_ON_API_URL=https://d2a26507c7094f359aba349b96a96881.lb.akinoncloud.com
|
|
10
|
-
NEXT_PUBLIC_ENABLE_IMAGE_SEARCH=true
|
|
11
10
|
|
|
12
11
|
# LOG_LEVEL_DEV=debug # For more details, please refer to the Logging documentation.
|
|
13
12
|
|
|
@@ -1,75 +1,36 @@
|
|
|
1
1
|
# projectzeronext
|
|
2
2
|
|
|
3
|
-
## 2.0.15
|
|
4
|
-
|
|
5
|
-
### Patch Changes
|
|
6
|
-
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
-
|
|
21
|
-
-
|
|
22
|
-
-
|
|
23
|
-
-
|
|
24
|
-
-
|
|
25
|
-
-
|
|
26
|
-
-
|
|
27
|
-
-
|
|
28
|
-
-
|
|
29
|
-
-
|
|
30
|
-
-
|
|
31
|
-
-
|
|
32
|
-
-
|
|
33
|
-
-
|
|
34
|
-
- Updated dependencies [9db81a71]
|
|
35
|
-
- Updated dependencies [591e345e]
|
|
36
|
-
- Updated dependencies [0df6bc1f]
|
|
37
|
-
- Updated dependencies [4de5303c5]
|
|
38
|
-
- Updated dependencies [63a72000]
|
|
39
|
-
- Updated dependencies [95b139dc]
|
|
40
|
-
- Updated dependencies [1d00f2d0]
|
|
41
|
-
- Updated dependencies [4ac7b2a1]
|
|
42
|
-
- Updated dependencies [4998a963]
|
|
43
|
-
- Updated dependencies [c0228aff]
|
|
44
|
-
- Updated dependencies [3909d322]
|
|
45
|
-
- Updated dependencies [e18836b2]
|
|
46
|
-
- @akinon/next@2.0.15-rc.0
|
|
47
|
-
- @akinon/pz-checkout-gift-pack@2.0.15-rc.0
|
|
48
|
-
- @akinon/pz-one-click-checkout@2.0.15-rc.0
|
|
49
|
-
- @akinon/pz-basket-gift-pack@2.0.15-rc.0
|
|
50
|
-
- @akinon/pz-masterpass-rest@2.0.15-rc.0
|
|
51
|
-
- @akinon/pz-pay-on-delivery@2.0.15-rc.0
|
|
52
|
-
- @akinon/pz-credit-payment@2.0.15-rc.0
|
|
53
|
-
- @akinon/pz-click-collect@2.0.15-rc.0
|
|
54
|
-
- @akinon/pz-multi-basket@2.0.15-rc.0
|
|
55
|
-
- @akinon/pz-masterpass@2.0.15-rc.0
|
|
56
|
-
- @akinon/pz-gpay@2.0.15-rc.0
|
|
57
|
-
- @akinon/pz-b2b@2.0.15-rc.0
|
|
58
|
-
- @akinon/pz-bkm@2.0.15-rc.0
|
|
59
|
-
- @akinon/pz-otp@2.0.15-rc.0
|
|
60
|
-
- @akinon/pz-similar-products@2.0.15-rc.0
|
|
61
|
-
- @akinon/pz-virtual-try-on@2.0.15-rc.0
|
|
62
|
-
- @akinon/pz-theme@2.0.15-rc.0
|
|
63
|
-
- @akinon/pz-akifast@2.0.15-rc.0
|
|
64
|
-
- @akinon/pz-apple-pay@2.0.15-rc.0
|
|
65
|
-
- @akinon/pz-cybersource-uc@2.0.15-rc.0
|
|
66
|
-
- @akinon/pz-flow-payment@2.0.15-rc.0
|
|
67
|
-
- @akinon/pz-google-pay@2.0.15-rc.0
|
|
68
|
-
- @akinon/pz-haso@2.0.15-rc.0
|
|
69
|
-
- @akinon/pz-hepsipay@2.0.15-rc.0
|
|
70
|
-
- @akinon/pz-saved-card@2.0.15-rc.0
|
|
71
|
-
- @akinon/pz-tabby-extension@2.0.15-rc.0
|
|
72
|
-
- @akinon/pz-tamara-extension@2.0.15-rc.0
|
|
3
|
+
## 2.0.15
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- @akinon/next@2.0.15
|
|
8
|
+
- @akinon/pz-akifast@2.0.15
|
|
9
|
+
- @akinon/pz-apple-pay@2.0.15
|
|
10
|
+
- @akinon/pz-b2b@2.0.15
|
|
11
|
+
- @akinon/pz-basket-gift-pack@2.0.15
|
|
12
|
+
- @akinon/pz-bkm@2.0.15
|
|
13
|
+
- @akinon/pz-checkout-gift-pack@2.0.15
|
|
14
|
+
- @akinon/pz-click-collect@2.0.15
|
|
15
|
+
- @akinon/pz-credit-payment@2.0.15
|
|
16
|
+
- @akinon/pz-cybersource-uc@2.0.15
|
|
17
|
+
- @akinon/pz-flow-payment@2.0.15
|
|
18
|
+
- @akinon/pz-google-pay@2.0.15
|
|
19
|
+
- @akinon/pz-gpay@2.0.15
|
|
20
|
+
- @akinon/pz-haso@2.0.15
|
|
21
|
+
- @akinon/pz-hepsipay@2.0.15
|
|
22
|
+
- @akinon/pz-masterpass@2.0.15
|
|
23
|
+
- @akinon/pz-masterpass-rest@2.0.15
|
|
24
|
+
- @akinon/pz-multi-basket@2.0.15
|
|
25
|
+
- @akinon/pz-one-click-checkout@2.0.15
|
|
26
|
+
- @akinon/pz-otp@2.0.15
|
|
27
|
+
- @akinon/pz-pay-on-delivery@2.0.15
|
|
28
|
+
- @akinon/pz-saved-card@2.0.15
|
|
29
|
+
- @akinon/pz-similar-products@2.0.15
|
|
30
|
+
- @akinon/pz-tabby-extension@2.0.15
|
|
31
|
+
- @akinon/pz-tamara-extension@2.0.15
|
|
32
|
+
- @akinon/pz-theme@2.0.15
|
|
33
|
+
- @akinon/pz-virtual-try-on@2.0.15
|
|
73
34
|
|
|
74
35
|
## 2.0.14
|
|
75
36
|
|
package/app-template/README.md
CHANGED
|
@@ -12,30 +12,6 @@ Run `cp .env.example .env && yarn` command at project root and all dependencies
|
|
|
12
12
|
|
|
13
13
|
- `SITEMAP_S3_BUCKET_NAME`: S3 bucket name for XML sitemaps (e.g., "0fb534"). This is required for the sitemap route to function correctly.
|
|
14
14
|
|
|
15
|
-
### Optional Environment Variables
|
|
16
|
-
|
|
17
|
-
- `NEXT_PUBLIC_ENABLE_IMAGE_SEARCH`: Set to `true` to enable image search feature for all users. If not set or `false`, the feature will only be visible to users who have enabled it via localStorage.
|
|
18
|
-
|
|
19
|
-
## Image Search Feature
|
|
20
|
-
|
|
21
|
-
The image search functionality allows users to search for similar products by uploading images or cropping existing product images.
|
|
22
|
-
|
|
23
|
-
### Feature Visibility Control
|
|
24
|
-
|
|
25
|
-
The image search feature can be controlled in two ways:
|
|
26
|
-
|
|
27
|
-
1. **Environment Variable (Global)**: Set `NEXT_PUBLIC_ENABLE_IMAGE_SEARCH=true` to enable for all users
|
|
28
|
-
2. **localStorage (Individual Users)**: Users can enable it locally using browser developer tools
|
|
29
|
-
|
|
30
|
-
````
|
|
31
|
-
|
|
32
|
-
### Feature Locations
|
|
33
|
-
|
|
34
|
-
When enabled, the image search feature appears in:
|
|
35
|
-
|
|
36
|
-
- **Header Search**: Camera icon next to the search input
|
|
37
|
-
- **Product Detail Page**: "View Similar Styles" button on product images
|
|
38
|
-
|
|
39
15
|
### Build
|
|
40
16
|
|
|
41
17
|
To build the app, run the following command:
|
|
@@ -43,7 +19,7 @@ To build the app, run the following command:
|
|
|
43
19
|
```bash
|
|
44
20
|
cd projectzeronext # Project root
|
|
45
21
|
yarn build
|
|
46
|
-
|
|
22
|
+
```
|
|
47
23
|
|
|
48
24
|
### Develop
|
|
49
25
|
|
|
@@ -48,12 +48,9 @@ const withSerwist = withSerwistInit({
|
|
|
48
48
|
const sentryConfig = {
|
|
49
49
|
silent: true,
|
|
50
50
|
dryRun: !process.env.SENTRY_DSN,
|
|
51
|
-
org: 'akinon'
|
|
51
|
+
org: 'akinon'
|
|
52
52
|
// project: 'enter_your_project_name_here',
|
|
53
53
|
// authToken: 'enter_your_auth_token_here'
|
|
54
|
-
sourcemaps: {
|
|
55
|
-
deleteSourcemapsAfterUpload: true
|
|
56
|
-
}
|
|
57
54
|
};
|
|
58
55
|
|
|
59
56
|
const enhancedConfig = withPzConfig(nextConfig);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "projectzeronext",
|
|
3
|
-
"version": "2.0.15
|
|
3
|
+
"version": "2.0.15",
|
|
4
4
|
"private": true,
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"scripts": {
|
|
@@ -24,33 +24,33 @@
|
|
|
24
24
|
"test:middleware": "jest middleware-matcher.test.ts --bail"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@akinon/next": "2.0.15
|
|
28
|
-
"@akinon/pz-akifast": "2.0.15
|
|
29
|
-
"@akinon/pz-apple-pay": "2.0.15
|
|
30
|
-
"@akinon/pz-b2b": "2.0.15
|
|
31
|
-
"@akinon/pz-basket-gift-pack": "2.0.15
|
|
32
|
-
"@akinon/pz-bkm": "2.0.15
|
|
33
|
-
"@akinon/pz-checkout-gift-pack": "2.0.15
|
|
34
|
-
"@akinon/pz-click-collect": "2.0.15
|
|
35
|
-
"@akinon/pz-credit-payment": "2.0.15
|
|
36
|
-
"@akinon/pz-cybersource-uc": "2.0.15
|
|
37
|
-
"@akinon/pz-flow-payment": "2.0.15
|
|
38
|
-
"@akinon/pz-google-pay": "2.0.15
|
|
39
|
-
"@akinon/pz-gpay": "2.0.15
|
|
40
|
-
"@akinon/pz-haso": "2.0.15
|
|
41
|
-
"@akinon/pz-hepsipay": "2.0.15
|
|
42
|
-
"@akinon/pz-masterpass": "2.0.15
|
|
43
|
-
"@akinon/pz-masterpass-rest": "2.0.15
|
|
44
|
-
"@akinon/pz-multi-basket": "2.0.15
|
|
45
|
-
"@akinon/pz-one-click-checkout": "2.0.15
|
|
46
|
-
"@akinon/pz-otp": "2.0.15
|
|
47
|
-
"@akinon/pz-pay-on-delivery": "2.0.15
|
|
48
|
-
"@akinon/pz-saved-card": "2.0.15
|
|
49
|
-
"@akinon/pz-similar-products": "2.0.15
|
|
50
|
-
"@akinon/pz-tabby-extension": "2.0.15
|
|
51
|
-
"@akinon/pz-tamara-extension": "2.0.15
|
|
52
|
-
"@akinon/pz-theme": "2.0.15
|
|
53
|
-
"@akinon/pz-virtual-try-on": "2.0.15
|
|
27
|
+
"@akinon/next": "2.0.15",
|
|
28
|
+
"@akinon/pz-akifast": "2.0.15",
|
|
29
|
+
"@akinon/pz-apple-pay": "2.0.15",
|
|
30
|
+
"@akinon/pz-b2b": "2.0.15",
|
|
31
|
+
"@akinon/pz-basket-gift-pack": "2.0.15",
|
|
32
|
+
"@akinon/pz-bkm": "2.0.15",
|
|
33
|
+
"@akinon/pz-checkout-gift-pack": "2.0.15",
|
|
34
|
+
"@akinon/pz-click-collect": "2.0.15",
|
|
35
|
+
"@akinon/pz-credit-payment": "2.0.15",
|
|
36
|
+
"@akinon/pz-cybersource-uc": "2.0.15",
|
|
37
|
+
"@akinon/pz-flow-payment": "2.0.15",
|
|
38
|
+
"@akinon/pz-google-pay": "2.0.15",
|
|
39
|
+
"@akinon/pz-gpay": "2.0.15",
|
|
40
|
+
"@akinon/pz-haso": "2.0.15",
|
|
41
|
+
"@akinon/pz-hepsipay": "2.0.15",
|
|
42
|
+
"@akinon/pz-masterpass": "2.0.15",
|
|
43
|
+
"@akinon/pz-masterpass-rest": "2.0.15",
|
|
44
|
+
"@akinon/pz-multi-basket": "2.0.15",
|
|
45
|
+
"@akinon/pz-one-click-checkout": "2.0.15",
|
|
46
|
+
"@akinon/pz-otp": "2.0.15",
|
|
47
|
+
"@akinon/pz-pay-on-delivery": "2.0.15",
|
|
48
|
+
"@akinon/pz-saved-card": "2.0.15",
|
|
49
|
+
"@akinon/pz-similar-products": "2.0.15",
|
|
50
|
+
"@akinon/pz-tabby-extension": "2.0.15",
|
|
51
|
+
"@akinon/pz-tamara-extension": "2.0.15",
|
|
52
|
+
"@akinon/pz-theme": "2.0.15",
|
|
53
|
+
"@akinon/pz-virtual-try-on": "2.0.15",
|
|
54
54
|
"@hookform/resolvers": "2.9.0",
|
|
55
55
|
"@next/third-parties": "16.2.6",
|
|
56
56
|
"@react-google-maps/api": "2.17.1",
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
"next": "16.2.6",
|
|
60
60
|
"@serwist/next": "9.5.11",
|
|
61
61
|
"next-auth": "5.0.0-beta.30",
|
|
62
|
-
"pino": "8.
|
|
62
|
+
"pino": "8.11.0",
|
|
63
63
|
"serwist": "9.5.11",
|
|
64
64
|
"postcss": "8.4.49",
|
|
65
65
|
"react": "19.2.5",
|
|
@@ -67,14 +67,14 @@
|
|
|
67
67
|
"react-google-recaptcha": "2.1.0",
|
|
68
68
|
"react-hook-form": "7.71.2",
|
|
69
69
|
"react-intersection-observer": "9.4.0",
|
|
70
|
-
"react-multi-carousel": "2.8.
|
|
71
|
-
"react-string-replace": "1.1.
|
|
72
|
-
"start-server-and-test": "2.0.
|
|
73
|
-
"tailwind-merge": "1.
|
|
70
|
+
"react-multi-carousel": "2.8.4",
|
|
71
|
+
"react-string-replace": "1.1.0",
|
|
72
|
+
"start-server-and-test": "2.0.3",
|
|
73
|
+
"tailwind-merge": "1.8.0",
|
|
74
74
|
"yup": "0.32.11"
|
|
75
75
|
},
|
|
76
76
|
"devDependencies": {
|
|
77
|
-
"@akinon/eslint-plugin-projectzero": "2.0.15
|
|
77
|
+
"@akinon/eslint-plugin-projectzero": "2.0.15",
|
|
78
78
|
"@semantic-release/changelog": "6.0.2",
|
|
79
79
|
"@semantic-release/exec": "6.0.3",
|
|
80
80
|
"@semantic-release/git": "10.0.1",
|
|
@@ -89,25 +89,25 @@
|
|
|
89
89
|
"@types/react": "19.2.14",
|
|
90
90
|
"@types/react-dom": "19.2.3",
|
|
91
91
|
"client-only": "0.0.1",
|
|
92
|
-
"clsx": "1.
|
|
92
|
+
"clsx": "1.1.1",
|
|
93
93
|
"currency-symbol-map": "5.1.0",
|
|
94
94
|
"eslint": "9.39.4",
|
|
95
95
|
"eslint-config-next": "16.2.4",
|
|
96
96
|
"eslint-config-prettier": "10.1.1",
|
|
97
97
|
"husky": "8.0.0",
|
|
98
98
|
"jest": "29.7.0",
|
|
99
|
-
"jest-css-modules-transform": "4.
|
|
99
|
+
"jest-css-modules-transform": "4.3.0",
|
|
100
100
|
"jest-environment-jsdom": "29.7.0",
|
|
101
|
-
"lint-staged": "13.
|
|
102
|
-
"prettier": "2.
|
|
101
|
+
"lint-staged": "13.1.0",
|
|
102
|
+
"prettier": "2.6.2",
|
|
103
103
|
"react-number-format": "5.3.4",
|
|
104
|
-
"sass": "1.
|
|
104
|
+
"sass": "1.49.9",
|
|
105
105
|
"semantic-release": "19.0.5",
|
|
106
106
|
"server-only": "0.0.1",
|
|
107
|
-
"stylelint": "14.
|
|
107
|
+
"stylelint": "14.6.0",
|
|
108
108
|
"stylelint-config-sass-guidelines": "9.0.1",
|
|
109
109
|
"stylelint-config-standard": "25.0.0",
|
|
110
|
-
"stylelint-scss": "4.
|
|
110
|
+
"stylelint-scss": "4.2.0",
|
|
111
111
|
"stylelint-selector-bem-pattern": "2.1.1",
|
|
112
112
|
"tailwindcss": "4.2.0",
|
|
113
113
|
"ts-jest": "29.2.6",
|
|
@@ -14,8 +14,7 @@ export const config = {
|
|
|
14
14
|
'/((?!api|_next|[\\w-\\/*]+\\.\\w+).*)',
|
|
15
15
|
'/(.*sitemap\\.xml)',
|
|
16
16
|
'/(.+\\.)(html|htm|aspx|asp|php)',
|
|
17
|
-
'/(.*orders\\/checkout-with-token.*)'
|
|
18
|
-
'/(.*orders\\/post-checkout.*)'
|
|
17
|
+
'/(.*orders\\/checkout-with-token.*)'
|
|
19
18
|
]
|
|
20
19
|
};
|
|
21
20
|
|
|
@@ -4,7 +4,8 @@ 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
|
-
|
|
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';
|
|
@@ -41,14 +42,6 @@ export default function Search() {
|
|
|
41
42
|
};
|
|
42
43
|
}, [isSearchOpen, dispatch]);
|
|
43
44
|
|
|
44
|
-
const handleSearchTextChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
45
|
-
setSearchText(e.target.value);
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
const handleCloseSearch = () => {
|
|
49
|
-
dispatch(closeSearch());
|
|
50
|
-
};
|
|
51
|
-
|
|
52
45
|
return (
|
|
53
46
|
<>
|
|
54
47
|
<div
|
|
@@ -74,9 +67,9 @@ export default function Search() {
|
|
|
74
67
|
{t('common.search.results_for')}
|
|
75
68
|
</span>
|
|
76
69
|
<div className="flex items-center">
|
|
77
|
-
<
|
|
70
|
+
<input
|
|
78
71
|
value={searchText}
|
|
79
|
-
onChange={
|
|
72
|
+
onChange={(e) => setSearchText(e.target.value)}
|
|
80
73
|
onKeyDown={(e) => {
|
|
81
74
|
if (e.key === 'Enter' && searchText.trim() !== '') {
|
|
82
75
|
router.push(`${ROUTES.LIST}/?search_text=${searchText}`);
|
|
@@ -98,12 +91,11 @@ export default function Search() {
|
|
|
98
91
|
<Icon
|
|
99
92
|
name="close"
|
|
100
93
|
size={14}
|
|
101
|
-
onClick={
|
|
94
|
+
onClick={() => dispatch(closeSearch())}
|
|
102
95
|
className="cursor-pointer"
|
|
103
96
|
/>
|
|
104
97
|
</div>
|
|
105
98
|
</div>
|
|
106
|
-
|
|
107
99
|
<Results searchText={searchText} />
|
|
108
100
|
</div>
|
|
109
101
|
</div>
|
|
@@ -36,100 +36,53 @@ export default function ProductInfoSlider({ product }: ProductSliderItem) {
|
|
|
36
36
|
carouselRef.current?.next();
|
|
37
37
|
};
|
|
38
38
|
|
|
39
|
-
const handleThumbnailClick = (index
|
|
39
|
+
const handleThumbnailClick = (index) => {
|
|
40
40
|
setActiveIndex(index);
|
|
41
41
|
carouselRef.current?.goToSlide(index);
|
|
42
42
|
};
|
|
43
43
|
|
|
44
44
|
return (
|
|
45
|
-
|
|
46
|
-
<div className="lg:
|
|
47
|
-
<div className="
|
|
48
|
-
<
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
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 }}
|
|
45
|
+
<div className="lg:grid lg:grid-cols-6">
|
|
46
|
+
<div className="lg:col-span-1">
|
|
47
|
+
<div className="flex flex-col items-center justify-center md:mr-[6px]">
|
|
48
|
+
<button
|
|
49
|
+
onClick={goToPrev}
|
|
50
|
+
className={twMerge(
|
|
51
|
+
'hidden justify-center p-2 mb-3 border border-gray-100 rounded-full cursor-pointer lg:block',
|
|
52
|
+
[activeIndex === 0 && 'cursor-not-allowed opacity-45']
|
|
53
|
+
)}
|
|
54
|
+
disabled={activeIndex === 0}
|
|
117
55
|
>
|
|
118
|
-
{
|
|
56
|
+
<Icon name="chevron-up" size={15} className="fill-[#000000]" />
|
|
57
|
+
</button>
|
|
58
|
+
<div className="hidden flex-col items-center overflow-scroll w-[80px] max-h-[620px] lg:block">
|
|
59
|
+
{product?.productimage_set?.map((item, index) => (
|
|
119
60
|
<Image
|
|
120
|
-
key={
|
|
61
|
+
key={index}
|
|
121
62
|
src={item.image}
|
|
122
|
-
alt={
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
fill
|
|
63
|
+
alt={`Thumbnail ${index}`}
|
|
64
|
+
width={80}
|
|
65
|
+
height={128}
|
|
66
|
+
className={twMerge('cursor-pointer', [
|
|
67
|
+
activeIndex === index && 'border-2 border-primary'
|
|
68
|
+
])}
|
|
69
|
+
onClick={() => handleThumbnailClick(index)}
|
|
130
70
|
/>
|
|
131
71
|
))}
|
|
132
|
-
</
|
|
72
|
+
</div>
|
|
73
|
+
<button
|
|
74
|
+
onClick={goToNext}
|
|
75
|
+
className={twMerge(
|
|
76
|
+
'hidden justify-center p-2 mt-3 border border-gray-100 rounded-full cursor-pointer lg:block',
|
|
77
|
+
[
|
|
78
|
+
activeIndex === product.productimage_set.length - 1 &&
|
|
79
|
+
'cursor-not-allowed opacity-45'
|
|
80
|
+
]
|
|
81
|
+
)}
|
|
82
|
+
disabled={activeIndex === product.productimage_set.length - 1}
|
|
83
|
+
>
|
|
84
|
+
<Icon name="chevron-down" size={15} className="fill-[#000000]" />
|
|
85
|
+
</button>
|
|
133
86
|
</div>
|
|
134
87
|
</div>
|
|
135
88
|
|
|
@@ -187,6 +140,6 @@ export default function ProductInfoSlider({ product }: ProductSliderItem) {
|
|
|
187
140
|
))}
|
|
188
141
|
</CarouselCore>
|
|
189
142
|
</div>
|
|
190
|
-
|
|
143
|
+
</div>
|
|
191
144
|
);
|
|
192
145
|
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* migrate-page-types: rewrites `PageProps<T>` from `@akinon/next/types` into
|
|
3
|
+
* `AsyncPageProps<T>` / `ResolvedPageProps<T>` across a brand's `src/`.
|
|
4
|
+
*
|
|
5
|
+
* Why: `@next/codemod next-async-request-api` updates the call sites
|
|
6
|
+
* (`await props.params`, `use(props.params)`), but the @akinon/next legacy
|
|
7
|
+
* `PageProps<T>` type is still sync and clashes with Next 16's internal
|
|
8
|
+
* `.next/types/.../page.ts` validator. Manually fixing every brand on every
|
|
9
|
+
* upgrade is the same change repeated — this codemod automates it.
|
|
10
|
+
*
|
|
11
|
+
* Usage:
|
|
12
|
+
* cd <brand-root>
|
|
13
|
+
* npx @akinon/projectzero codemod --codemod=migrate-page-types [--dry-run]
|
|
14
|
+
*
|
|
15
|
+
* Or via the upgrade-to-2 chain (no flag needed).
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
const path = require('path');
|
|
19
|
+
const fs = require('fs');
|
|
20
|
+
const jscodeshift = require('jscodeshift/src/Runner');
|
|
21
|
+
|
|
22
|
+
function log(msg) {
|
|
23
|
+
const ts = new Date().toISOString().replace('T', ' ').slice(0, 19);
|
|
24
|
+
console.log(`[${ts}] [migrate-page-types] ${msg}`);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const transform = () => {
|
|
28
|
+
const workingDir = path.resolve(process.cwd());
|
|
29
|
+
const dryRun = process.argv.includes('--dry-run');
|
|
30
|
+
|
|
31
|
+
log(`starting in ${workingDir}${dryRun ? ' (DRY RUN)' : ''}`);
|
|
32
|
+
|
|
33
|
+
const srcDir = path.join(workingDir, 'src');
|
|
34
|
+
if (!fs.existsSync(srcDir)) {
|
|
35
|
+
log('No src/ directory found, nothing to migrate.');
|
|
36
|
+
return Promise.resolve();
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const transformPath = path.resolve(__dirname, 'transform.js');
|
|
40
|
+
|
|
41
|
+
return jscodeshift
|
|
42
|
+
.run(transformPath, [srcDir], {
|
|
43
|
+
verbose: 0,
|
|
44
|
+
dry: Boolean(dryRun),
|
|
45
|
+
print: Boolean(dryRun),
|
|
46
|
+
extensions: 'ts,tsx',
|
|
47
|
+
parser: 'tsx',
|
|
48
|
+
ignorePattern: '**/node_modules/**',
|
|
49
|
+
silent: true
|
|
50
|
+
})
|
|
51
|
+
.then(
|
|
52
|
+
(stats) => {
|
|
53
|
+
log(
|
|
54
|
+
`${stats.ok} changed, ${stats.nochange} unchanged, ${stats.error} errored`
|
|
55
|
+
);
|
|
56
|
+
log('done');
|
|
57
|
+
},
|
|
58
|
+
(err) => {
|
|
59
|
+
log(`FAILED: ${err.message}`);
|
|
60
|
+
throw err;
|
|
61
|
+
}
|
|
62
|
+
);
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
module.exports = { transform };
|
|
66
|
+
|
|
67
|
+
if (require.main === module) {
|
|
68
|
+
const result = transform();
|
|
69
|
+
if (result && typeof result.then === 'function') {
|
|
70
|
+
result.catch((err) => {
|
|
71
|
+
console.error(err);
|
|
72
|
+
process.exit(1);
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* jscodeshift transform: rewrite `PageProps<T>` from `@akinon/next/types`
|
|
3
|
+
* into `AsyncPageProps<T>` or `ResolvedPageProps<T>` per usage context.
|
|
4
|
+
*
|
|
5
|
+
* Heuristic per occurrence:
|
|
6
|
+
* - Enclosing function is `generateMetadata` → AsyncPageProps
|
|
7
|
+
* - Body uses `await props.params` / `await props.searchParams` or
|
|
8
|
+
* `use(props.params)` / `use(props.searchParams)` → AsyncPageProps
|
|
9
|
+
* - Otherwise (destructured params accessed synchronously, typical Page
|
|
10
|
+
* wrapped in `withSegmentDefaults`) → ResolvedPageProps
|
|
11
|
+
*
|
|
12
|
+
* Import is rewritten: PageProps removed, AsyncPageProps / ResolvedPageProps
|
|
13
|
+
* added as needed, sorted alphabetically (matches prettier output).
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const TARGET_IMPORT = '@akinon/next/types';
|
|
17
|
+
|
|
18
|
+
function getEnclosingFunction(path) {
|
|
19
|
+
let cur = path;
|
|
20
|
+
while (cur.parent) {
|
|
21
|
+
cur = cur.parent;
|
|
22
|
+
const t = cur.node && cur.node.type;
|
|
23
|
+
if (
|
|
24
|
+
t === 'FunctionDeclaration' ||
|
|
25
|
+
t === 'FunctionExpression' ||
|
|
26
|
+
t === 'ArrowFunctionExpression'
|
|
27
|
+
) {
|
|
28
|
+
return cur;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function getFunctionName(fnPath) {
|
|
35
|
+
const node = fnPath.node;
|
|
36
|
+
if (node.id && node.id.name) return node.id.name;
|
|
37
|
+
let p = fnPath.parent;
|
|
38
|
+
while (p) {
|
|
39
|
+
const t = p.node && p.node.type;
|
|
40
|
+
if (t === 'VariableDeclarator' && p.node.id && p.node.id.name) {
|
|
41
|
+
return p.node.id.name;
|
|
42
|
+
}
|
|
43
|
+
if (
|
|
44
|
+
t === 'Property' ||
|
|
45
|
+
t === 'ObjectProperty' ||
|
|
46
|
+
t === 'MethodDefinition'
|
|
47
|
+
) {
|
|
48
|
+
const key = p.node.key;
|
|
49
|
+
if (key && key.name) return key.name;
|
|
50
|
+
}
|
|
51
|
+
if (
|
|
52
|
+
t === 'FunctionDeclaration' ||
|
|
53
|
+
t === 'FunctionExpression' ||
|
|
54
|
+
t === 'ArrowFunctionExpression'
|
|
55
|
+
) {
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
p = p.parent;
|
|
59
|
+
}
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function bodyUsesAsyncResolve(fnPath, j) {
|
|
64
|
+
let found = false;
|
|
65
|
+
const isParamsMember = (node) =>
|
|
66
|
+
node &&
|
|
67
|
+
node.type === 'MemberExpression' &&
|
|
68
|
+
node.property &&
|
|
69
|
+
(node.property.name === 'params' ||
|
|
70
|
+
node.property.name === 'searchParams');
|
|
71
|
+
|
|
72
|
+
j(fnPath)
|
|
73
|
+
.find(j.AwaitExpression)
|
|
74
|
+
.forEach((awaitPath) => {
|
|
75
|
+
if (isParamsMember(awaitPath.node.argument)) found = true;
|
|
76
|
+
});
|
|
77
|
+
j(fnPath)
|
|
78
|
+
.find(j.CallExpression, { callee: { name: 'use' } })
|
|
79
|
+
.forEach((callPath) => {
|
|
80
|
+
const arg = callPath.node.arguments && callPath.node.arguments[0];
|
|
81
|
+
if (isParamsMember(arg)) found = true;
|
|
82
|
+
});
|
|
83
|
+
return found;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function transform(fileInfo, api) {
|
|
87
|
+
const j = api.jscodeshift;
|
|
88
|
+
const root = j(fileInfo.source);
|
|
89
|
+
|
|
90
|
+
const akinonImports = root.find(j.ImportDeclaration, {
|
|
91
|
+
source: { value: TARGET_IMPORT }
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
if (akinonImports.length === 0) return null;
|
|
95
|
+
|
|
96
|
+
let hasPageProps = false;
|
|
97
|
+
akinonImports.forEach((imp) => {
|
|
98
|
+
const specs = imp.node.specifiers || [];
|
|
99
|
+
if (
|
|
100
|
+
specs.some(
|
|
101
|
+
(s) =>
|
|
102
|
+
s.type === 'ImportSpecifier' &&
|
|
103
|
+
s.imported &&
|
|
104
|
+
s.imported.name === 'PageProps'
|
|
105
|
+
)
|
|
106
|
+
) {
|
|
107
|
+
hasPageProps = true;
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
if (!hasPageProps) return null;
|
|
112
|
+
|
|
113
|
+
let usedAsync = false;
|
|
114
|
+
let usedResolved = false;
|
|
115
|
+
|
|
116
|
+
root
|
|
117
|
+
.find(j.TSTypeReference, {
|
|
118
|
+
typeName: { type: 'Identifier', name: 'PageProps' }
|
|
119
|
+
})
|
|
120
|
+
.forEach((path) => {
|
|
121
|
+
const fnPath = getEnclosingFunction(path);
|
|
122
|
+
let target = 'AsyncPageProps';
|
|
123
|
+
if (fnPath) {
|
|
124
|
+
const fnName = getFunctionName(fnPath);
|
|
125
|
+
if (fnName === 'generateMetadata') {
|
|
126
|
+
target = 'AsyncPageProps';
|
|
127
|
+
} else if (bodyUsesAsyncResolve(fnPath, j)) {
|
|
128
|
+
target = 'AsyncPageProps';
|
|
129
|
+
} else {
|
|
130
|
+
target = 'ResolvedPageProps';
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
path.node.typeName = j.identifier(target);
|
|
134
|
+
if (target === 'AsyncPageProps') usedAsync = true;
|
|
135
|
+
else usedResolved = true;
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
akinonImports.forEach((imp) => {
|
|
139
|
+
const specs = imp.node.specifiers || [];
|
|
140
|
+
const existingNames = new Set(
|
|
141
|
+
specs
|
|
142
|
+
.filter((s) => s.type === 'ImportSpecifier' && s.imported)
|
|
143
|
+
.map((s) => s.imported.name)
|
|
144
|
+
);
|
|
145
|
+
const next = specs.filter(
|
|
146
|
+
(s) =>
|
|
147
|
+
!(
|
|
148
|
+
s.type === 'ImportSpecifier' &&
|
|
149
|
+
s.imported &&
|
|
150
|
+
s.imported.name === 'PageProps'
|
|
151
|
+
)
|
|
152
|
+
);
|
|
153
|
+
if (usedAsync && !existingNames.has('AsyncPageProps')) {
|
|
154
|
+
next.push(j.importSpecifier(j.identifier('AsyncPageProps')));
|
|
155
|
+
}
|
|
156
|
+
if (usedResolved && !existingNames.has('ResolvedPageProps')) {
|
|
157
|
+
next.push(j.importSpecifier(j.identifier('ResolvedPageProps')));
|
|
158
|
+
}
|
|
159
|
+
next.sort((a, b) => {
|
|
160
|
+
if (a.type !== 'ImportSpecifier' || b.type !== 'ImportSpecifier') return 0;
|
|
161
|
+
return a.imported.name.localeCompare(b.imported.name);
|
|
162
|
+
});
|
|
163
|
+
imp.node.specifiers = next;
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
return root.toSource({ quote: 'single' });
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
module.exports = transform;
|
|
@@ -11,8 +11,9 @@
|
|
|
11
11
|
* 6. Run migrate-auth-v5 codemod (next-auth v4 -> v5)
|
|
12
12
|
* 7. Run sentry-9 codemod (only when @sentry/nextjs is present)
|
|
13
13
|
* 8. Run migrate-eslint codemod (ESLint v9 flat config)
|
|
14
|
-
* 9.
|
|
15
|
-
* 10.
|
|
14
|
+
* 9. Run migrate-page-types codemod (PageProps -> Async/Resolved)
|
|
15
|
+
* 10. yarn build (validation)
|
|
16
|
+
* 11. Summary report
|
|
16
17
|
*
|
|
17
18
|
* Out of scope in this first version:
|
|
18
19
|
* - Tailwind v3 -> v4 migration (run manually with @tailwindcss/upgrade)
|
|
@@ -32,6 +33,7 @@
|
|
|
32
33
|
* --skip-auth Do not run migrate-auth-v5
|
|
33
34
|
* --skip-sentry Do not run sentry-9 (auto-skipped if not needed)
|
|
34
35
|
* --skip-eslint Do not run migrate-eslint
|
|
36
|
+
* --skip-page-types Do not run migrate-page-types
|
|
35
37
|
* --skip-install Do not run yarn install
|
|
36
38
|
* --skip-build Do not run yarn build
|
|
37
39
|
* --interactive Pause for confirmation after each step
|
|
@@ -46,6 +48,7 @@ const readline = require('readline');
|
|
|
46
48
|
const AUTH_CODEMOD = path.resolve(__dirname, '..', 'migrate-auth-v5');
|
|
47
49
|
const SENTRY_CODEMOD = path.resolve(__dirname, '..', 'sentry-9');
|
|
48
50
|
const ESLINT_CODEMOD = path.resolve(__dirname, '..', 'migrate-eslint');
|
|
51
|
+
const PAGE_TYPES_CODEMOD = path.resolve(__dirname, '..', 'migrate-page-types');
|
|
49
52
|
|
|
50
53
|
const TARGET_MATRIX = {
|
|
51
54
|
dependencies: {
|
|
@@ -134,6 +137,7 @@ function parseArgs(argv) {
|
|
|
134
137
|
skipAuth: argv.includes('--skip-auth'),
|
|
135
138
|
skipSentry: argv.includes('--skip-sentry'),
|
|
136
139
|
skipEslint: argv.includes('--skip-eslint'),
|
|
140
|
+
skipPageTypes: argv.includes('--skip-page-types'),
|
|
137
141
|
skipInstall: argv.includes('--skip-install'),
|
|
138
142
|
skipBuild: argv.includes('--skip-build'),
|
|
139
143
|
interactive: argv.includes('--interactive'),
|
|
@@ -154,7 +158,7 @@ function writePackageJson(cwd, pkg) {
|
|
|
154
158
|
}
|
|
155
159
|
|
|
156
160
|
function stepPreflight(cwd, flags) {
|
|
157
|
-
logStep('[1/
|
|
161
|
+
logStep('[1/11] Preflight', 'starting');
|
|
158
162
|
|
|
159
163
|
const pkg = readPackageJson(cwd);
|
|
160
164
|
if (!pkg) {
|
|
@@ -188,19 +192,19 @@ function stepPreflight(cwd, flags) {
|
|
|
188
192
|
log(` Current: next@${currentNext} react@${currentReact} next-auth@${currentAuth} @akinon/next@${currentAkinon}`);
|
|
189
193
|
log(` Target: next@${TARGET_MATRIX.dependencies.next} react@${TARGET_MATRIX.dependencies.react} next-auth@${TARGET_MATRIX.dependencies['next-auth']} @akinon/next@${TARGET_MATRIX.dependencies['@akinon/next']}`);
|
|
190
194
|
|
|
191
|
-
logStep('[1/
|
|
195
|
+
logStep('[1/11] Preflight', 'ok');
|
|
192
196
|
}
|
|
193
197
|
|
|
194
198
|
function stepBackup(cwd, flags) {
|
|
195
199
|
if (flags.skipBackup) {
|
|
196
|
-
logStep('[2/
|
|
200
|
+
logStep('[2/11] Backup branch', 'skipped');
|
|
197
201
|
return null;
|
|
198
202
|
}
|
|
199
203
|
const today = new Date().toISOString().slice(0, 10).replace(/-/g, '');
|
|
200
204
|
const branchName = `pre-upgrade-2-${today}`;
|
|
201
205
|
|
|
202
206
|
if (flags.dryRun) {
|
|
203
|
-
logStep('[2/
|
|
207
|
+
logStep('[2/11] Backup branch', `[DRY] git branch ${branchName}`);
|
|
204
208
|
return branchName;
|
|
205
209
|
}
|
|
206
210
|
|
|
@@ -210,7 +214,7 @@ function stepBackup(cwd, flags) {
|
|
|
210
214
|
{ cwd, encoding: 'utf-8' }
|
|
211
215
|
);
|
|
212
216
|
if (existing.status === 0) {
|
|
213
|
-
logStep('[2/
|
|
217
|
+
logStep('[2/11] Backup branch', `already exists: ${branchName}`);
|
|
214
218
|
return branchName;
|
|
215
219
|
}
|
|
216
220
|
|
|
@@ -221,7 +225,7 @@ function stepBackup(cwd, flags) {
|
|
|
221
225
|
if (result.status !== 0) {
|
|
222
226
|
throw new Error(`Failed to create backup branch ${branchName}`);
|
|
223
227
|
}
|
|
224
|
-
logStep('[2/
|
|
228
|
+
logStep('[2/11] Backup branch', `created ${branchName}`);
|
|
225
229
|
return branchName;
|
|
226
230
|
}
|
|
227
231
|
|
|
@@ -319,7 +323,7 @@ function pinNextScriptsToWebpack(pkg) {
|
|
|
319
323
|
|
|
320
324
|
function stepBump(cwd, flags) {
|
|
321
325
|
if (flags.skipBump) {
|
|
322
|
-
logStep('[3/
|
|
326
|
+
logStep('[3/11] Bump deps', 'skipped');
|
|
323
327
|
return { hasSentry: false, changes: [] };
|
|
324
328
|
}
|
|
325
329
|
|
|
@@ -367,16 +371,16 @@ function stepBump(cwd, flags) {
|
|
|
367
371
|
allChanges.push(...scriptChanges);
|
|
368
372
|
|
|
369
373
|
if (allChanges.length === 0) {
|
|
370
|
-
logStep('[3/
|
|
374
|
+
logStep('[3/11] Bump deps', 'already at target, no changes');
|
|
371
375
|
return { hasSentry, changes: [] };
|
|
372
376
|
}
|
|
373
377
|
|
|
374
378
|
if (flags.dryRun) {
|
|
375
|
-
logStep('[3/
|
|
379
|
+
logStep('[3/11] Bump deps', `[DRY] ${allChanges.length} changes`);
|
|
376
380
|
allChanges.forEach((c) => log(` - ${c}`));
|
|
377
381
|
} else {
|
|
378
382
|
writePackageJson(cwd, pkg);
|
|
379
|
-
logStep('[3/
|
|
383
|
+
logStep('[3/11] Bump deps', `${allChanges.length} changes applied`);
|
|
380
384
|
if (flags.verbose) allChanges.forEach((c) => log(` - ${c}`));
|
|
381
385
|
}
|
|
382
386
|
|
|
@@ -385,28 +389,28 @@ function stepBump(cwd, flags) {
|
|
|
385
389
|
|
|
386
390
|
function stepNextCodemod(cwd, flags) {
|
|
387
391
|
if (flags.skipNextCodemod) {
|
|
388
|
-
logStep('[5/
|
|
392
|
+
logStep('[5/11] Next codemod', 'skipped');
|
|
389
393
|
return { ok: true };
|
|
390
394
|
}
|
|
391
395
|
const cmd = flags.dryRun
|
|
392
396
|
? 'npx --yes @next/codemod@latest upgrade latest --verbose'
|
|
393
397
|
: 'npx --yes @next/codemod@latest upgrade latest';
|
|
394
|
-
logStep('[5/
|
|
398
|
+
logStep('[5/11] Next codemod', `running ${cmd}`);
|
|
395
399
|
const result = runCommand(cmd, { cwd, dryRun: false, verbose: flags.verbose });
|
|
396
400
|
if (result.status !== 0) {
|
|
397
|
-
logStep('[5/
|
|
401
|
+
logStep('[5/11] Next codemod', `FAILED (exit ${result.status})`);
|
|
398
402
|
return { ok: false };
|
|
399
403
|
}
|
|
400
|
-
logStep('[5/
|
|
404
|
+
logStep('[5/11] Next codemod', 'ok');
|
|
401
405
|
return { ok: true };
|
|
402
406
|
}
|
|
403
407
|
|
|
404
408
|
function stepAuthCodemod(cwd, flags) {
|
|
405
409
|
if (flags.skipAuth) {
|
|
406
|
-
logStep('[6/
|
|
410
|
+
logStep('[6/11] Auth codemod', 'skipped');
|
|
407
411
|
return { ok: true };
|
|
408
412
|
}
|
|
409
|
-
logStep('[6/
|
|
413
|
+
logStep('[6/11] Auth codemod', 'running migrate-auth-v5');
|
|
410
414
|
try {
|
|
411
415
|
const prevArgv = process.argv;
|
|
412
416
|
process.argv = [
|
|
@@ -426,21 +430,21 @@ function stepAuthCodemod(cwd, flags) {
|
|
|
426
430
|
return result.then(
|
|
427
431
|
() => {
|
|
428
432
|
finish();
|
|
429
|
-
logStep('[6/
|
|
433
|
+
logStep('[6/11] Auth codemod', 'ok');
|
|
430
434
|
return { ok: true };
|
|
431
435
|
},
|
|
432
436
|
(err) => {
|
|
433
437
|
finish();
|
|
434
|
-
logStep('[6/
|
|
438
|
+
logStep('[6/11] Auth codemod', `FAILED: ${err.message}`);
|
|
435
439
|
return { ok: false };
|
|
436
440
|
}
|
|
437
441
|
);
|
|
438
442
|
}
|
|
439
443
|
finish();
|
|
440
|
-
logStep('[6/
|
|
444
|
+
logStep('[6/11] Auth codemod', 'ok');
|
|
441
445
|
return { ok: true };
|
|
442
446
|
} catch (err) {
|
|
443
|
-
logStep('[6/
|
|
447
|
+
logStep('[6/11] Auth codemod', `FAILED: ${err.message}`);
|
|
444
448
|
return { ok: false };
|
|
445
449
|
}
|
|
446
450
|
}
|
|
@@ -448,34 +452,34 @@ function stepAuthCodemod(cwd, flags) {
|
|
|
448
452
|
function stepSentryCodemod(cwd, flags, hasSentry) {
|
|
449
453
|
if (flags.skipSentry || !hasSentry) {
|
|
450
454
|
const reason = flags.skipSentry ? 'skipped' : 'no @sentry/nextjs, skipping';
|
|
451
|
-
logStep('[7/
|
|
455
|
+
logStep('[7/11] Sentry codemod', reason);
|
|
452
456
|
return { ok: true };
|
|
453
457
|
}
|
|
454
458
|
if (flags.dryRun) {
|
|
455
|
-
logStep('[7/
|
|
459
|
+
logStep('[7/11] Sentry codemod', '[DRY] would run sentry-9');
|
|
456
460
|
return { ok: true };
|
|
457
461
|
}
|
|
458
|
-
logStep('[7/
|
|
462
|
+
logStep('[7/11] Sentry codemod', 'running sentry-9');
|
|
459
463
|
try {
|
|
460
464
|
const savedCwd = process.cwd();
|
|
461
465
|
process.chdir(cwd);
|
|
462
466
|
const codemod = require(SENTRY_CODEMOD);
|
|
463
467
|
codemod.transform();
|
|
464
468
|
process.chdir(savedCwd);
|
|
465
|
-
logStep('[7/
|
|
469
|
+
logStep('[7/11] Sentry codemod', 'ok');
|
|
466
470
|
return { ok: true };
|
|
467
471
|
} catch (err) {
|
|
468
|
-
logStep('[7/
|
|
472
|
+
logStep('[7/11] Sentry codemod', `FAILED: ${err.message}`);
|
|
469
473
|
return { ok: false };
|
|
470
474
|
}
|
|
471
475
|
}
|
|
472
476
|
|
|
473
477
|
function stepEslintCodemod(cwd, flags) {
|
|
474
478
|
if (flags.skipEslint) {
|
|
475
|
-
logStep('[8/
|
|
479
|
+
logStep('[8/11] ESLint codemod', 'skipped');
|
|
476
480
|
return { ok: true };
|
|
477
481
|
}
|
|
478
|
-
logStep('[8/
|
|
482
|
+
logStep('[8/11] ESLint codemod', 'running migrate-eslint');
|
|
479
483
|
try {
|
|
480
484
|
const prevArgv = process.argv;
|
|
481
485
|
process.argv = [
|
|
@@ -489,24 +493,68 @@ function stepEslintCodemod(cwd, flags) {
|
|
|
489
493
|
codemod.transform();
|
|
490
494
|
process.chdir(savedCwd);
|
|
491
495
|
process.argv = prevArgv;
|
|
492
|
-
logStep('[8/
|
|
496
|
+
logStep('[8/11] ESLint codemod', 'ok');
|
|
493
497
|
return { ok: true };
|
|
494
498
|
} catch (err) {
|
|
495
|
-
logStep('[8/
|
|
499
|
+
logStep('[8/11] ESLint codemod', `FAILED: ${err.message}`);
|
|
500
|
+
return { ok: false };
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
function stepPageTypesCodemod(cwd, flags) {
|
|
505
|
+
if (flags.skipPageTypes) {
|
|
506
|
+
logStep('[9/11] Page types codemod', 'skipped');
|
|
507
|
+
return { ok: true };
|
|
508
|
+
}
|
|
509
|
+
logStep('[9/11] Page types codemod', 'running migrate-page-types');
|
|
510
|
+
try {
|
|
511
|
+
const prevArgv = process.argv;
|
|
512
|
+
process.argv = [
|
|
513
|
+
process.argv[0],
|
|
514
|
+
process.argv[1],
|
|
515
|
+
...(flags.dryRun ? ['--dry-run'] : [])
|
|
516
|
+
];
|
|
517
|
+
const savedCwd = process.cwd();
|
|
518
|
+
process.chdir(cwd);
|
|
519
|
+
const codemod = require(PAGE_TYPES_CODEMOD);
|
|
520
|
+
const result = codemod.transform();
|
|
521
|
+
const finish = () => {
|
|
522
|
+
process.chdir(savedCwd);
|
|
523
|
+
process.argv = prevArgv;
|
|
524
|
+
};
|
|
525
|
+
if (result && typeof result.then === 'function') {
|
|
526
|
+
return result.then(
|
|
527
|
+
() => {
|
|
528
|
+
finish();
|
|
529
|
+
logStep('[9/11] Page types codemod', 'ok');
|
|
530
|
+
return { ok: true };
|
|
531
|
+
},
|
|
532
|
+
(err) => {
|
|
533
|
+
finish();
|
|
534
|
+
logStep('[9/11] Page types codemod', `FAILED: ${err.message}`);
|
|
535
|
+
return { ok: false };
|
|
536
|
+
}
|
|
537
|
+
);
|
|
538
|
+
}
|
|
539
|
+
finish();
|
|
540
|
+
logStep('[9/11] Page types codemod', 'ok');
|
|
541
|
+
return { ok: true };
|
|
542
|
+
} catch (err) {
|
|
543
|
+
logStep('[9/11] Page types codemod', `FAILED: ${err.message}`);
|
|
496
544
|
return { ok: false };
|
|
497
545
|
}
|
|
498
546
|
}
|
|
499
547
|
|
|
500
548
|
function stepInstall(cwd, flags) {
|
|
501
549
|
if (flags.skipInstall) {
|
|
502
|
-
logStep('[4/
|
|
550
|
+
logStep('[4/11] yarn install', 'skipped');
|
|
503
551
|
return { ok: true };
|
|
504
552
|
}
|
|
505
553
|
if (flags.dryRun) {
|
|
506
|
-
logStep('[4/
|
|
554
|
+
logStep('[4/11] yarn install', '[DRY] yarn clean && yarn');
|
|
507
555
|
return { ok: true };
|
|
508
556
|
}
|
|
509
|
-
logStep('[4/
|
|
557
|
+
logStep('[4/11] yarn install', 'running yarn clean && yarn');
|
|
510
558
|
const clean = runCommand('yarn clean', {
|
|
511
559
|
cwd,
|
|
512
560
|
dryRun: false,
|
|
@@ -521,33 +569,33 @@ function stepInstall(cwd, flags) {
|
|
|
521
569
|
verbose: flags.verbose
|
|
522
570
|
});
|
|
523
571
|
if (install.status !== 0) {
|
|
524
|
-
logStep('[4/
|
|
572
|
+
logStep('[4/11] yarn install', `FAILED (exit ${install.status})`);
|
|
525
573
|
return { ok: false };
|
|
526
574
|
}
|
|
527
|
-
logStep('[4/
|
|
575
|
+
logStep('[4/11] yarn install', 'ok');
|
|
528
576
|
return { ok: true };
|
|
529
577
|
}
|
|
530
578
|
|
|
531
579
|
function stepBuild(cwd, flags) {
|
|
532
580
|
if (flags.skipBuild) {
|
|
533
|
-
logStep('[
|
|
581
|
+
logStep('[10/11] yarn build', 'skipped');
|
|
534
582
|
return { ok: true };
|
|
535
583
|
}
|
|
536
584
|
if (flags.dryRun) {
|
|
537
|
-
logStep('[
|
|
585
|
+
logStep('[10/11] yarn build', '[DRY] yarn build');
|
|
538
586
|
return { ok: true };
|
|
539
587
|
}
|
|
540
|
-
logStep('[
|
|
588
|
+
logStep('[10/11] yarn build', 'running');
|
|
541
589
|
const result = runCommand('yarn build', {
|
|
542
590
|
cwd,
|
|
543
591
|
dryRun: false,
|
|
544
592
|
verbose: flags.verbose
|
|
545
593
|
});
|
|
546
594
|
if (result.status !== 0) {
|
|
547
|
-
logStep('[
|
|
595
|
+
logStep('[10/11] yarn build', `FAILED (exit ${result.status})`);
|
|
548
596
|
return { ok: false };
|
|
549
597
|
}
|
|
550
|
-
logStep('[
|
|
598
|
+
logStep('[10/11] yarn build', 'ok');
|
|
551
599
|
return { ok: true };
|
|
552
600
|
}
|
|
553
601
|
|
|
@@ -559,7 +607,7 @@ function countTodoMarkers(cwd) {
|
|
|
559
607
|
}
|
|
560
608
|
|
|
561
609
|
function stepReport(cwd, results) {
|
|
562
|
-
logStep('[
|
|
610
|
+
logStep('[11/11] Report', 'summary');
|
|
563
611
|
const pkg = readPackageJson(cwd) || {};
|
|
564
612
|
const todoCount = countTodoMarkers(cwd);
|
|
565
613
|
|
|
@@ -572,6 +620,7 @@ function stepReport(cwd, results) {
|
|
|
572
620
|
console.log(` Auth codemod: ${results.authCodemod ? 'ok' : 'FAILED'}`);
|
|
573
621
|
console.log(` Sentry codemod: ${results.sentryCodemod ? 'ok' : results.sentrySkippedReason || 'FAILED'}`);
|
|
574
622
|
console.log(` ESLint codemod: ${results.eslintCodemod ? 'ok' : 'FAILED'}`);
|
|
623
|
+
console.log(` Page types: ${results.pageTypesCodemod ? 'ok' : 'FAILED'}`);
|
|
575
624
|
console.log(` Build: ${results.build ? 'ok' : 'FAILED'}`);
|
|
576
625
|
console.log('');
|
|
577
626
|
console.log(` Versions after:`);
|
|
@@ -618,7 +667,7 @@ async function transform() {
|
|
|
618
667
|
results.preflight = true;
|
|
619
668
|
await maybePause(flags, 'preflight');
|
|
620
669
|
} else {
|
|
621
|
-
logStep('[1/
|
|
670
|
+
logStep('[1/11] Preflight', 'skipped');
|
|
622
671
|
results.preflight = true;
|
|
623
672
|
}
|
|
624
673
|
|
|
@@ -652,6 +701,14 @@ async function transform() {
|
|
|
652
701
|
results.eslintCodemod = stepEslintCodemod(cwd, flags).ok;
|
|
653
702
|
await maybePause(flags, 'eslint-codemod');
|
|
654
703
|
|
|
704
|
+
const pageTypesResult = stepPageTypesCodemod(cwd, flags);
|
|
705
|
+
const pageTypesAwaited =
|
|
706
|
+
pageTypesResult && typeof pageTypesResult.then === 'function'
|
|
707
|
+
? await pageTypesResult
|
|
708
|
+
: pageTypesResult;
|
|
709
|
+
results.pageTypesCodemod = pageTypesAwaited.ok;
|
|
710
|
+
await maybePause(flags, 'page-types-codemod');
|
|
711
|
+
|
|
655
712
|
results.build = stepBuild(cwd, flags).ok;
|
|
656
713
|
} catch (err) {
|
|
657
714
|
log(`FATAL: ${err.message}`);
|
package/commands/plugins.ts
CHANGED
package/dist/commands/plugins.js
CHANGED
|
@@ -183,10 +183,6 @@ exports.default = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
|
183
183
|
name: 'Tamara Payment Extension',
|
|
184
184
|
value: 'pz-tamara-extension'
|
|
185
185
|
},
|
|
186
|
-
{
|
|
187
|
-
name: 'Similar Products',
|
|
188
|
-
value: 'pz-similar-products'
|
|
189
|
-
},
|
|
190
186
|
{
|
|
191
187
|
name: 'Hepsipay',
|
|
192
188
|
value: 'pz-hepsipay'
|
package/package.json
CHANGED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import { useSentryUncaughtErrors } from '@akinon/next/hooks';
|
|
4
|
-
|
|
5
|
-
export default function GlobalError({
|
|
6
|
-
error,
|
|
7
|
-
reset
|
|
8
|
-
}: {
|
|
9
|
-
error: Error & { digest?: string };
|
|
10
|
-
reset: () => void;
|
|
11
|
-
}) {
|
|
12
|
-
useSentryUncaughtErrors(error);
|
|
13
|
-
|
|
14
|
-
return (
|
|
15
|
-
<html>
|
|
16
|
-
<body>
|
|
17
|
-
<h2>Something went wrong!</h2>
|
|
18
|
-
<button onClick={() => reset()}>Try again</button>
|
|
19
|
-
</body>
|
|
20
|
-
</html>
|
|
21
|
-
);
|
|
22
|
-
}
|