@akinon/projectzero 1.33.1 → 1.34.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.
package/CHANGELOG.md CHANGED
@@ -1,11 +1,13 @@
1
1
  # @akinon/projectzero
2
2
 
3
- ## 1.33.1
3
+ ## 1.34.0-rc.1
4
4
 
5
5
  ### Patch Changes
6
6
 
7
7
  - 10123f9: ZERO-2632: rename projectzero-cli to projectzero
8
8
 
9
+ ## 1.34.0-rc.0
10
+
9
11
  ## 1.33.0
10
12
 
11
13
  ### Minor Changes
@@ -1,18 +1,56 @@
1
1
  # projectzeronext
2
2
 
3
- ## 1.33.1
3
+ ## 1.34.0-rc.1
4
4
 
5
5
  ### Patch Changes
6
6
 
7
7
  - 10123f9: ZERO-2632: rename projectzero-cli to projectzero
8
8
  - Updated dependencies [10123f9]
9
- - @akinon/next@1.33.1
10
- - @akinon/pz-b2b@1.33.1
11
- - @akinon/pz-gpay@1.33.1
12
- - @akinon/pz-masterpass@1.33.1
13
- - @akinon/pz-one-click-checkout@1.33.1
14
- - @akinon/pz-otp@1.33.1
15
- - @akinon/pz-pay-on-delivery@1.33.1
9
+ - @akinon/next@1.34.0-rc.1
10
+ - @akinon/pz-b2b@1.34.0-rc.1
11
+ - @akinon/pz-gpay@1.34.0-rc.1
12
+ - @akinon/pz-masterpass@1.34.0-rc.1
13
+ - @akinon/pz-one-click-checkout@1.34.0-rc.1
14
+ - @akinon/pz-otp@1.34.0-rc.1
15
+ - @akinon/pz-pay-on-delivery@1.34.0-rc.1
16
+
17
+ ## 1.34.0-rc.0
18
+
19
+ ### Minor Changes
20
+
21
+ - 567e4c1: ZERO-2580:Add checked attribute from props to checkbox
22
+ - d09b677: ZERO-2577: Fix pagination bug and update usePagination hook and ensure pagination controls rendering correctly
23
+ - ebb63ce: ZERO-2525: Fix category facet removal bug and add close icon to active filters
24
+ - f0c23bc: ZERO-2135: add custom not found page
25
+ - 3420416: ZERO-2533: extend eslint config from @akinon/next
26
+ - 6c18543: ZERO-2542:Refactor and show error in OneClickCheckoutButtons
27
+ - 202f84e: ZERO-2569: Fix static keys
28
+ - f046f8e: ZERO-2575: update version for react-number-format
29
+ - 12c10a4: ZERO-2570: Category filters routes to absolute url
30
+
31
+ ### Patch Changes
32
+
33
+ - Updated dependencies [d09b677]
34
+ - Updated dependencies [6d4aadb]
35
+ - Updated dependencies [ebb63ce]
36
+ - Updated dependencies [7cebe87]
37
+ - Updated dependencies [f3b595e]
38
+ - Updated dependencies [f0c23bc]
39
+ - Updated dependencies [3420416]
40
+ - Updated dependencies [495d155]
41
+ - Updated dependencies [6c18543]
42
+ - Updated dependencies [40ad73e]
43
+ - Updated dependencies [495d155]
44
+ - Updated dependencies [f046f8e]
45
+ - Updated dependencies [6b2972b]
46
+ - Updated dependencies [3e68768]
47
+ - @akinon/next@1.34.0-rc.0
48
+ - @akinon/pz-masterpass@1.34.0-rc.0
49
+ - @akinon/pz-one-click-checkout@1.34.0-rc.0
50
+ - @akinon/pz-b2b@1.34.0-rc.0
51
+ - @akinon/pz-gpay@1.34.0-rc.0
52
+ - @akinon/pz-otp@1.34.0-rc.0
53
+ - @akinon/pz-pay-on-delivery@1.34.0-rc.0
16
54
 
17
55
  ## 1.33.0
18
56
 
@@ -0,0 +1,10 @@
1
+ const baseConfig = require('@akinon/next/eslint.config')
2
+
3
+ module.exports = {
4
+ ...baseConfig,
5
+ settings: {
6
+ next: {
7
+ rootDir: ['src/*/']
8
+ }
9
+ },
10
+ };
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "projectzeronext",
3
- "version": "1.33.1",
3
+ "version": "1.34.0-rc.1",
4
4
  "private": true,
5
5
  "license": "MIT",
6
6
  "scripts": {
@@ -22,13 +22,13 @@
22
22
  "prestart": "pz-prestart"
23
23
  },
24
24
  "dependencies": {
25
- "@akinon/next": "1.33.1",
26
- "@akinon/pz-b2b": "1.33.1",
27
- "@akinon/pz-gpay": "1.33.1",
28
- "@akinon/pz-masterpass": "1.33.1",
29
- "@akinon/pz-one-click-checkout": "1.33.1",
30
- "@akinon/pz-otp": "1.33.1",
31
- "@akinon/pz-pay-on-delivery": "1.33.1",
25
+ "@akinon/next": "1.34.0-rc.1",
26
+ "@akinon/pz-b2b": "1.34.0-rc.1",
27
+ "@akinon/pz-gpay": "1.34.0-rc.1",
28
+ "@akinon/pz-masterpass": "1.34.0-rc.1",
29
+ "@akinon/pz-one-click-checkout": "1.34.0-rc.1",
30
+ "@akinon/pz-otp": "1.34.0-rc.1",
31
+ "@akinon/pz-pay-on-delivery": "1.34.0-rc.1",
32
32
  "@hookform/resolvers": "2.9.0",
33
33
  "@next/third-parties": "14.1.0",
34
34
  "@react-google-maps/api": "2.17.1",
@@ -52,7 +52,7 @@
52
52
  "yup": "0.32.11"
53
53
  },
54
54
  "devDependencies": {
55
- "@akinon/eslint-plugin-projectzero": "1.33.1",
55
+ "@akinon/eslint-plugin-projectzero": "1.34.0-rc.1",
56
56
  "@semantic-release/changelog": "6.0.2",
57
57
  "@semantic-release/exec": "6.0.3",
58
58
  "@semantic-release/git": "10.0.1",
@@ -79,7 +79,7 @@
79
79
  "jest-css-modules-transform": "4.3.0",
80
80
  "lint-staged": "13.1.0",
81
81
  "prettier": "2.6.2",
82
- "react-number-format": "4.9.3",
82
+ "react-number-format": "5.3.4",
83
83
  "sass": "1.49.9",
84
84
  "semantic-release": "19.0.5",
85
85
  "server-only": "0.0.1",
@@ -0,0 +1,5 @@
1
+ {
2
+ "title": "Page Not Found",
3
+ "sub_title": "It looks like the page you're looking for doesn't exist.",
4
+ "button": "Return to Home Page"
5
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "title": "Sayfa Bulunamadı",
3
+ "sub_title": "Aradığınız sayfa bulunamadı gibi görünüyor.",
4
+ "button": "Ana Sayfaya Dön"
5
+ }
@@ -247,6 +247,7 @@ export default function Page() {
247
247
  className="mb-5"
248
248
  required
249
249
  />
250
+
250
251
  <div className="mb-5">
251
252
  <Input
252
253
  label={t('account.my_profile.form.phone.placeholder')}
@@ -0,0 +1,24 @@
1
+ 'use client';
2
+
3
+ import React from 'react';
4
+ import { Button, Link } from '@theme/components';
5
+ import { useLocalization } from '@akinon/next/hooks';
6
+
7
+ const NotFound = () => {
8
+ const { t } = useLocalization();
9
+
10
+ return (
11
+ <div className="py-6 flex flex-col items-center justify-center">
12
+ <div className="text-8xl font-bold">404</div>
13
+ <h1 className="text-4xl font-bold mb-4">{t('not_found.title')}</h1>
14
+ <p className="text-lg mb-6">{t('not_found.sub_title')}</p>
15
+ <Link href={'/'}>
16
+ <Button className="h-auto mt-4 text-base py-3 px-6">
17
+ {t('not_found.button')}
18
+ </Button>
19
+ </Link>
20
+ </div>
21
+ );
22
+ };
23
+
24
+ export default NotFound;
@@ -3,7 +3,7 @@ import { CheckboxProps } from '@theme/components/types';
3
3
  import { twMerge } from 'tailwind-merge';
4
4
 
5
5
  const Checkbox = forwardRef<HTMLInputElement, CheckboxProps>((props, ref) => {
6
- const { children, error, ...rest } = props;
6
+ const { children, checked, error, ...rest } = props;
7
7
 
8
8
  return (
9
9
  <label className={twMerge('flex flex-col text-xs', props.className)}>
@@ -12,6 +12,7 @@ const Checkbox = forwardRef<HTMLInputElement, CheckboxProps>((props, ref) => {
12
12
  type="checkbox"
13
13
  {...rest}
14
14
  ref={ref}
15
+ checked={checked ?? false}
15
16
  className="w-4 h-4 shrink-0"
16
17
  />
17
18
  {children && <span className="ml-2">{children}</span>}
@@ -1,17 +1,28 @@
1
1
  import clsx from 'clsx';
2
- import { forwardRef, FocusEvent, useState } from 'react';
2
+ import { forwardRef, FocusEvent, useState, Ref } from 'react';
3
3
  import { Controller } from 'react-hook-form';
4
- import NumberFormat, { NumberFormatProps } from 'react-number-format';
4
+ import { PatternFormat, PatternFormatProps } from 'react-number-format';
5
5
  import { InputProps } from '@theme/components/types';
6
6
  import { twMerge } from 'tailwind-merge';
7
7
 
8
+ const PatternFormatWithRef = forwardRef(
9
+ (props: PatternFormatProps, ref: Ref<HTMLInputElement>) => {
10
+ return <PatternFormat {...props} getInputRef={ref} />;
11
+ }
12
+ );
13
+ PatternFormatWithRef.displayName = 'PatternFormatWithRef';
14
+
8
15
  export const Input = forwardRef<
9
16
  HTMLInputElement,
10
17
  InputProps &
11
18
  Pick<
12
- NumberFormatProps,
13
- 'format' | 'mask' | 'allowEmptyFormatting' | 'onValueChange'
14
- >
19
+ PatternFormatProps,
20
+ 'mask' | 'allowEmptyFormatting' | 'onValueChange'
21
+ > & {
22
+ format?: string;
23
+ defaultValue?: string;
24
+ type?: string;
25
+ }
15
26
  >((props, ref) => {
16
27
  const [focused, setFocused] = useState(false);
17
28
  const [hasValue, setHasValue] = useState(false);
@@ -37,6 +48,7 @@ export const Input = forwardRef<
37
48
  ),
38
49
  props.className
39
50
  );
51
+
40
52
  const inputProps: any = {
41
53
  id,
42
54
  ref,
@@ -79,14 +91,14 @@ export const Input = forwardRef<
79
91
  <Controller
80
92
  name={props.name ?? ''}
81
93
  control={props.control}
82
- defaultValue={false}
83
94
  render={({ field }) => (
84
- <NumberFormat
95
+ <PatternFormatWithRef
85
96
  format={format}
86
97
  mask={mask ?? ''}
87
98
  {...rest}
88
99
  {...field}
89
100
  {...inputProps}
101
+ type={props.type as 'text' | 'password' | 'tel'}
90
102
  />
91
103
  )}
92
104
  />
@@ -198,7 +198,7 @@ export const Pagination = (props: PaginationProps) => {
198
198
  containerClassName
199
199
  )}
200
200
  >
201
- {prev && (
201
+ {prev && currentPage !== 1 && (
202
202
  <li>
203
203
  <Link
204
204
  onClick={(e) => handleClick(e, prev)}
@@ -1,10 +1,10 @@
1
1
  import { useMemo } from 'react';
2
- import NumberFormat, { NumberFormatProps } from 'react-number-format';
2
+ import { NumericFormat, NumericFormatProps } from 'react-number-format';
3
3
  import { getCurrency } from '@akinon/next/utils';
4
4
  import { PriceProps } from '@theme/types';
5
5
  import { useLocalization } from '@akinon/next/hooks';
6
6
 
7
- export const Price = (props: NumberFormatProps & PriceProps) => {
7
+ export const Price = (props: NumericFormatProps & PriceProps) => {
8
8
  const {
9
9
  value,
10
10
  currencyCode,
@@ -38,7 +38,7 @@ export const Price = (props: NumberFormatProps & PriceProps) => {
38
38
  );
39
39
 
40
40
  return (
41
- <NumberFormat
41
+ <NumericFormat
42
42
  value={useNegative ? `-${useNegativeSpace}${_value}` : _value}
43
43
  {...{
44
44
  [useCurrencyAfterPrice ? 'suffix' : 'prefix']: currency
@@ -31,7 +31,10 @@ const categorySlice = createSlice({
31
31
  if (facet.key === action.payload.facet.key) {
32
32
  facet.data.choices = facet.data.choices
33
33
  .map((choice) => {
34
- if (action.payload.facet.widget_type === WIDGET_TYPE.category) {
34
+ if (
35
+ action.payload.facet.widget_type === WIDGET_TYPE.category &&
36
+ choice.is_selected
37
+ ) {
35
38
  choice.is_selected = false;
36
39
  }
37
40
  return choice;
@@ -48,6 +51,24 @@ const categorySlice = createSlice({
48
51
  return facet;
49
52
  });
50
53
  },
54
+ removeCategoryFacet(state, action) {
55
+ state.selectedFacets = state.selectedFacets.map((facet) => {
56
+ if (facet.key === action.payload.facet.key) {
57
+ facet.data.choices = facet.data.choices.map((choice) => {
58
+ if (choice.value === action.payload.choice.value) {
59
+ choice.is_selected = false;
60
+ }
61
+ return choice;
62
+ });
63
+ }
64
+
65
+ return facet;
66
+ });
67
+
68
+ state.selectedFacets = state.selectedFacets.filter(
69
+ (facet) => facet.key !== action.payload.facet.key
70
+ );
71
+ },
51
72
  resetSelectedFacets(state) {
52
73
  return {
53
74
  ...state,
@@ -61,6 +82,7 @@ export const {
61
82
  setFacets,
62
83
  setSelectedFacets,
63
84
  toggleFacet,
85
+ removeCategoryFacet,
64
86
  resetSelectedFacets
65
87
  } = categorySlice.actions;
66
88
 
@@ -58,5 +58,6 @@ module.exports = {
58
58
  ],
59
59
  redis: {
60
60
  defaultExpirationTime: 900 // 15 min
61
- }
61
+ },
62
+ customNotFoundEnabled: false
62
63
  };
@@ -1,11 +1,15 @@
1
1
  import { useAppDispatch, useAppSelector } from '@akinon/next/redux/hooks';
2
2
  import React, { useEffect, useMemo } from 'react';
3
- import { toggleFacet } from '@theme/redux/reducers/category';
3
+ import {
4
+ removeCategoryFacet,
5
+ toggleFacet
6
+ } from '@theme/redux/reducers/category';
4
7
  import { useRouter } from '@akinon/next/hooks';
5
8
  import convertFacetSearchParams from '@theme/utils/convert-facet-search-params';
6
9
  import { usePathname } from 'next/navigation';
7
10
  import { WIDGET_TYPE } from '@theme/types';
8
11
  import { useSearchParams } from 'next/dist/client/components/navigation';
12
+ import { Icon } from '@theme/components';
9
13
 
10
14
  const CategoryActiveFilters = () => {
11
15
  const dispatch = useAppDispatch();
@@ -16,6 +20,11 @@ const CategoryActiveFilters = () => {
16
20
  const { facets, selectedFacets } = useAppSelector((state) => state.category);
17
21
 
18
22
  const handleRemoveFilter = ({ facet, choice }) => {
23
+ if (facet.widget_type === WIDGET_TYPE.category) {
24
+ dispatch(removeCategoryFacet({ facet, choice }));
25
+ return;
26
+ }
27
+
19
28
  dispatch(toggleFacet({ facet, choice }));
20
29
  };
21
30
 
@@ -53,43 +62,23 @@ const CategoryActiveFilters = () => {
53
62
  {facets.map((facet) =>
54
63
  facet.data.choices
55
64
  .filter((choice) => choice.is_selected)
56
- .map((choice) => (
57
- <div
58
- className="flex justify-between text-xs text-black-800 py-3.5 px-4 border border-gray-400 hover:bg-gray-300 cursor-default items-center"
59
- key={`${facet.key}-${choice.label}`}
60
- >
61
- <div>
62
- {facet.widget_type !== WIDGET_TYPE.category && (
63
- <span>{facet.name}: </span>
64
- )}
65
- <span>{choice.label}</span>
66
- </div>
67
- {facet.widget_type !== WIDGET_TYPE.category && (
65
+ .map(
66
+ (choice) =>
67
+ Number(choice.real_depth) !== 2 && (
68
68
  <div
69
- className="cursor-pointer ml-4"
70
- onClick={() => handleRemoveFilter({ facet, choice })}
69
+ className="flex justify-between text-xs text-black-800 py-3.5 px-4 border border-gray-400 hover:bg-gray-300 cursor-default items-center"
70
+ key={`${facet.key}-${choice.label}`}
71
71
  >
72
- <svg
73
- xmlns="http://www.w3.org/2000/svg"
74
- viewBox="0 0 13.5 13.5"
75
- width="1em"
76
- height="1em"
77
- >
78
- <path
79
- d="m.75 12.75 12-12m-12 0 12 12"
80
- style={{
81
- fill: 'none',
82
- stroke: '#000',
83
- strokeLinecap: 'round',
84
- strokeLinejoin: 'round',
85
- strokeWidth: '1.5px'
86
- }}
87
- />
88
- </svg>
72
+ <span>{choice.label}</span>
73
+ <Icon
74
+ className="cursor-pointer"
75
+ name="close"
76
+ size={12}
77
+ onClick={() => handleRemoveFilter({ facet, choice })}
78
+ />
89
79
  </div>
90
- )}
91
- </div>
92
- ))
80
+ )
81
+ )
93
82
  )}
94
83
  </div>
95
84
  );
@@ -70,7 +70,7 @@ export default function ListPage(props: ListPageProps) {
70
70
  ></div>
71
71
  <div className="flex flex-col items-center lg:items-stretch col-span-2 lg:col-span-1">
72
72
  <CategoryHeader
73
- totalCount={data.pagination.total_count}
73
+ totalCount={data.pagination?.total_count}
74
74
  setMenuStatus={() => setIsMenuOpen(true)}
75
75
  sortOptions={data.sorters}
76
76
  />
@@ -78,7 +78,7 @@ export default function ListPage(props: ListPageProps) {
78
78
  <CategoryActiveFilters />
79
79
  </div>
80
80
 
81
- {data.products.length === 0 && page === 1 && (
81
+ {data.products?.length === 0 && page === 1 && (
82
82
  <div className="text-center bg-gray-200 px-5 py-20">
83
83
  <p className="pb-4">{t('category.search.not_found')}</p>
84
84
  <Link className="underline" href={ROUTES.HOME}>
@@ -6,7 +6,7 @@ import clsx from 'clsx';
6
6
  import { Accordion, Button, Checkbox, Icon, Radio } from '@theme/components';
7
7
  import { SizeFilter } from './size-filter';
8
8
 
9
- import { useLocalization } from '@akinon/next/hooks';
9
+ import { useLocalization, useRouter } from '@akinon/next/hooks';
10
10
  import { Facet, FacetChoice } from '@akinon/next/types';
11
11
  import { useAppDispatch, useAppSelector } from '@akinon/next/redux/hooks';
12
12
  import {
@@ -14,7 +14,8 @@ import {
14
14
  toggleFacet
15
15
  } from '@theme/redux/reducers/category';
16
16
  import CategoryActiveFilters from '@theme/views/category/category-active-filters';
17
- import { useMemo } from 'react';
17
+ import { useEffect, useMemo } from 'react';
18
+ import { commonProductAttributes } from '@theme/settings';
18
19
 
19
20
  const COMPONENT_TYPES = {
20
21
  [WIDGET_TYPE.category]: Radio,
@@ -27,6 +28,7 @@ interface Props {
27
28
  }
28
29
 
29
30
  export const Filters = (props: Props) => {
31
+ const router = useRouter();
30
32
  const facets = useAppSelector((state) => state.category.facets);
31
33
  const dispatch = useAppDispatch();
32
34
  const { t } = useLocalization();
@@ -39,12 +41,16 @@ export const Filters = (props: Props) => {
39
41
  facet: Facet;
40
42
  choice: FacetChoice;
41
43
  }) => {
42
- dispatch(
43
- toggleFacet({
44
- facet,
45
- choice
46
- })
47
- );
44
+ if (facet.key === 'category_ids') {
45
+ router.push(choice.url);
46
+ } else {
47
+ dispatch(
48
+ toggleFacet({
49
+ facet,
50
+ choice
51
+ })
52
+ );
53
+ }
48
54
  };
49
55
 
50
56
  const haveFilter = useMemo(() => {
@@ -60,6 +66,19 @@ export const Filters = (props: Props) => {
60
66
  dispatch(resetSelectedFacets());
61
67
  };
62
68
 
69
+ useEffect(() => {
70
+ const url = new URL(window.location.href);
71
+ if (url.searchParams.has('category_ids')) {
72
+ url.searchParams.delete('category_ids');
73
+ const newHref = url.pathname + url.search;
74
+ window.history.replaceState({}, '', newHref);
75
+ }
76
+ }, [router]);
77
+
78
+ const sizeKey = commonProductAttributes.find(
79
+ (item) => item.translationKey === 'size'
80
+ ).key;
81
+
63
82
  return (
64
83
  <div
65
84
  className={clsx(
@@ -81,7 +100,7 @@ export const Filters = (props: Props) => {
81
100
  let Component = null;
82
101
  const choices = [...facet.data.choices];
83
102
 
84
- if (facet.key === 'integration_SizeId') {
103
+ if (facet.key === sizeKey) {
85
104
  // If it's a size facet, use the custom size filter component
86
105
  Component = SizeFilter;
87
106
 
@@ -107,8 +126,8 @@ export const Filters = (props: Props) => {
107
126
  >
108
127
  <div
109
128
  className={clsx(
110
- 'flex gap-4',
111
- facet.key === 'integration_SizeId' ? 'flex-row' : 'flex-col' // TODO: This condition must be refactor to a better way
129
+ 'flex gap-4 flex-wrap',
130
+ facet.key === sizeKey ? 'flex-row' : 'flex-col' // TODO: This condition must be refactor to a better way
112
131
  )}
113
132
  >
114
133
  {choices.map((choice, index) => (
@@ -117,13 +136,13 @@ export const Filters = (props: Props) => {
117
136
  data={choice}
118
137
  name={facet.key}
119
138
  onChange={() => {
120
- if (facet.key !== 'integration_SizeId') {
139
+ if (facet.key !== sizeKey) {
121
140
  // TODO: This condition must be refactor to a better way
122
141
  handleSelectFilter({ facet, choice });
123
142
  }
124
143
  }}
125
144
  onClick={() => {
126
- if (facet.key === 'integration_SizeId') {
145
+ if (facet.key === sizeKey) {
127
146
  // TODO: This condition must be refactor to a better way
128
147
  handleSelectFilter({ facet, choice });
129
148
  }
@@ -206,7 +206,14 @@ export default function ProductInfo({ data }: ProductPageProps) {
206
206
  'after:bg-[#d02c2f]',
207
207
  'after:rounded-xl',
208
208
  'after:left-1'
209
- ])
209
+ ]),
210
+ onError: (error) =>
211
+ setProductError(
212
+ error?.data?.non_field_errors ||
213
+ Object.keys(error?.data).map(
214
+ (key) => `${key}: ${error?.data[key].join(', ')}`
215
+ )
216
+ )
210
217
  }}
211
218
  />
212
219
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@akinon/projectzero",
3
- "version": "1.33.1",
3
+ "version": "1.34.0-rc.1",
4
4
  "private": false,
5
5
  "description": "CLI tool to manage your Project Zero Next project",
6
6
  "bin": {
@@ -1,31 +0,0 @@
1
- module.exports = {
2
- env: {
3
- browser: true,
4
- es6: true,
5
- node: true,
6
- jest: true
7
- },
8
- extends: [
9
- 'next/core-web-vitals',
10
- 'eslint:recommended',
11
- 'plugin:@typescript-eslint/recommended',
12
- 'prettier',
13
- 'plugin:@akinon/projectzero/core', // DO NOT remove this config for stability
14
- 'plugin:@akinon/projectzero/recommended' // Optional
15
- ],
16
- plugins: ['@typescript-eslint', '@akinon/projectzero'],
17
- parser: '@typescript-eslint/parser',
18
- parserOptions: {
19
- ecmaVersion: 2021,
20
- sourceType: 'module'
21
- },
22
- settings: {
23
- next: {
24
- rootDir: ['src/*/']
25
- }
26
- },
27
- rules: {
28
- '@typescript-eslint/no-unused-vars': 'warn',
29
- '@typescript-eslint/no-explicit-any': 'warn'
30
- }
31
- };