@akinon/projectzero 1.41.0-rc.0 → 1.41.0

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 (27) hide show
  1. package/CHANGELOG.md +1 -36
  2. package/app-template/CHANGELOG.md +23 -330
  3. package/app-template/package.json +16 -15
  4. package/app-template/public/locales/en/account.json +4 -4
  5. package/app-template/public/locales/en/auth.json +1 -2
  6. package/app-template/public/locales/tr/account.json +1 -1
  7. package/app-template/public/locales/tr/auth.json +1 -2
  8. package/app-template/src/app/[commerce]/[locale]/[currency]/account/coupons/page.tsx +4 -4
  9. package/app-template/src/app/[commerce]/[locale]/[currency]/account/profile/page.tsx +0 -1
  10. package/app-template/src/app/[commerce]/[locale]/[currency]/orders/completed/[token]/page.tsx +8 -12
  11. package/app-template/src/components/checkbox.tsx +2 -2
  12. package/app-template/src/components/input.tsx +7 -19
  13. package/app-template/src/components/price.tsx +3 -3
  14. package/app-template/src/plugins.js +2 -1
  15. package/app-template/src/views/account/address-form.tsx +7 -22
  16. package/app-template/src/views/account/contact-form.tsx +6 -22
  17. package/app-template/src/views/account/favourite-products/favourite-products-list.tsx +1 -5
  18. package/app-template/src/views/basket/summary.tsx +35 -26
  19. package/app-template/src/views/category/filters/index.tsx +105 -5
  20. package/app-template/src/views/login/index.tsx +20 -9
  21. package/app-template/src/views/product/product-info.tsx +42 -32
  22. package/app-template/tsconfig.json +4 -14
  23. package/commands/create.ts +5 -29
  24. package/dist/commands/create.js +2 -25
  25. package/package.json +1 -1
  26. package/app-template/src/app/[commerce]/[locale]/[currency]/[...prettyurl]/page.tsx +0 -8
  27. package/app-template/src/views/category/filters/filter-item.tsx +0 -131
@@ -1,10 +1,10 @@
1
1
  import { useMemo } from 'react';
2
- import { NumericFormat, NumericFormatProps } from 'react-number-format';
2
+ import NumberFormat, { NumberFormatProps } 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: NumericFormatProps & PriceProps) => {
7
+ export const Price = (props: NumberFormatProps & PriceProps) => {
8
8
  const {
9
9
  value,
10
10
  currencyCode,
@@ -38,7 +38,7 @@ export const Price = (props: NumericFormatProps & PriceProps) => {
38
38
  );
39
39
 
40
40
  return (
41
- <NumericFormat
41
+ <NumberFormat
42
42
  value={useNegative ? `-${useNegativeSpace}${_value}` : _value}
43
43
  {...{
44
44
  [useCurrencyAfterPrice ? 'suffix' : 'prefix']: currency
@@ -10,5 +10,6 @@ module.exports = [
10
10
  'pz-bkm',
11
11
  'pz-credit-payment',
12
12
  'pz-masterpass',
13
- 'pz-b2b'
13
+ 'pz-b2b',
14
+ 'pz-akifast'
14
15
  ];
@@ -31,7 +31,7 @@ interface Props {
31
31
  onSubmit: (data: any) => void;
32
32
  }
33
33
 
34
- const makeAddressFormSchema = (t, { phoneNumberLength, postCodeLength }) =>
34
+ const makeAddressFormSchema = (t, { phoneNumberLength }) =>
35
35
  yup.object().shape({
36
36
  title: yup.string().required(t('account.address_book.form.error.required')),
37
37
  first_name: yup
@@ -65,9 +65,8 @@ const makeAddressFormSchema = (t, { phoneNumberLength, postCodeLength }) =>
65
65
  .max(255, t('account.address_book.form.error.line_max')),
66
66
  postcode: yup
67
67
  .string()
68
- .transform((value: string) => value.replace(/_/g, '').replace(/ /g, ''))
69
- .min(postCodeLength, t('account.address_book.form.error.postcode_min'))
70
- .max(postCodeLength, t('account.address_book.form.error.postcode_max'))
68
+ .min(5, t('account.address_book.form.error.postcode_min'))
69
+ .max(5, t('account.address_book.form.error.postcode_max'))
71
70
  .required(t('account.address_book.form.error.required')),
72
71
  company_name: yup.string().nullable(),
73
72
  tax_no: yup.string().nullable(),
@@ -81,8 +80,7 @@ export const AddressForm = (props: Props) => {
81
80
  const { data, onSubmit } = props;
82
81
  const config = useAppSelector((state) => state.config);
83
82
  const addressFormSchema = makeAddressFormSchema(t, {
84
- phoneNumberLength: config.user_phone_format.length,
85
- postCodeLength: config.user_post_code_format.length
83
+ phoneNumberLength: config.user_phone_format.length
86
84
  });
87
85
  const {
88
86
  register,
@@ -183,22 +181,12 @@ export const AddressForm = (props: Props) => {
183
181
  if (data && country) {
184
182
  reset({
185
183
  ...data,
186
- is_corporate: String(data.is_corporate)
184
+ is_corporate:
185
+ String(data.is_corporate) === AddressType.company ? 'true' : 'false' // TODO: Fix this! This hack for radio buttons can't be set to boolean value
187
186
  });
188
187
  }
189
188
  }, [data, country, reset]);
190
189
 
191
- useEffect(() => {
192
- if (selectedFormType !== AddressType.company) {
193
- reset({
194
- ...watch(),
195
- company_name: '',
196
- tax_office: '',
197
- tax_no: ''
198
- });
199
- }
200
- }, [selectedFormType, reset, watch]);
201
-
202
190
  return (
203
191
  <form
204
192
  onSubmit={handleSubmit(onSubmit)}
@@ -334,15 +322,12 @@ export const AddressForm = (props: Props) => {
334
322
  )}
335
323
  </label>
336
324
  <Input
325
+ type="number"
337
326
  label={t('account.address_book.form.post_code.placeholder')}
338
327
  {...register('postcode')}
339
328
  error={errors.postcode}
340
329
  data-testid="address-form-post-code"
341
330
  required
342
- format={config.user_post_code_format.replaceAll(/\9/g, '#')}
343
- control={control}
344
- mask="_"
345
- allowEmptyFormatting
346
331
  />
347
332
  {selectedFormType === AddressType.company && (
348
333
  <>
@@ -3,9 +3,9 @@ import {
3
3
  Button,
4
4
  FileInput,
5
5
  Input,
6
- Link,
7
6
  LoaderSpinner,
8
- Select
7
+ Select,
8
+ Link
9
9
  } from '@theme/components';
10
10
  import { useSession } from 'next-auth/react';
11
11
  import { useEffect, useState } from 'react';
@@ -45,8 +45,7 @@ const contactFormSchema = (t) =>
45
45
  .when('subject', {
46
46
  is: (value) => value === '2',
47
47
  then: yup.string().required(t('account.contact.form.error.required'))
48
- }),
49
- file: yup.mixed()
48
+ })
50
49
  });
51
50
 
52
51
  const ContactForm = () => {
@@ -111,18 +110,8 @@ const ContactForm = () => {
111
110
  resolver: yupResolver(contactFormSchema(t))
112
111
  });
113
112
 
114
- const onSubmit: SubmitHandler<ContactFormType> = (data, event) => {
115
- const formData = new FormData()
116
-
117
- Object.keys(data ?? {}).forEach((key) => {
118
- if (key === "file" && data[key]){
119
- formData.append(key, data[key][0]);
120
- } else if (data[key]) {
121
- formData.append(key, data[key]);
122
- }
123
- });
124
-
125
- sendContact(formData);
113
+ const onSubmit: SubmitHandler<ContactFormType> = (data) => {
114
+ sendContact(data);
126
115
  };
127
116
 
128
117
  const handleChange = (e) => {
@@ -253,12 +242,7 @@ const ContactForm = () => {
253
242
  <label className="text-xs text-gray-800 mb-2 block">
254
243
  {t('account.contact.form.file.title')}
255
244
  </label>
256
- <FileInput
257
- name="file"
258
- title="file"
259
- className="w-full mb-5"
260
- {...register('file')}
261
- />
245
+ <FileInput className="w-full mb-5" title="test" />
262
246
  <Button type="submit" className="w-full font-medium">
263
247
  {t('account.contact.form.submit_button')}
264
248
  </Button>
@@ -30,11 +30,7 @@ const FavoriteProductsList = () => {
30
30
  }
31
31
 
32
32
  if (isLoading || isFetching) {
33
- return (
34
- <div className="flex items-center justify-center h-80">
35
- <LoaderSpinner />
36
- </div>
37
- );
33
+ return <LoaderSpinner />; // TODO: Fix loader spinner position
38
34
  }
39
35
 
40
36
  return (
@@ -1,4 +1,4 @@
1
- import { useEffect } from 'react';
1
+ import React, { useEffect } from 'react';
2
2
  import { useAppDispatch } from '@akinon/next/redux/hooks';
3
3
  import { useForm } from 'react-hook-form';
4
4
  import { yupResolver } from '@hookform/resolvers/yup';
@@ -9,10 +9,10 @@ import {
9
9
  useRemoveVoucherCodeMutation
10
10
  } from '@akinon/next/data/client/basket';
11
11
  import { Basket, Error } from '@akinon/next/types';
12
- import { Price, Button, Input } from '@theme/components';
12
+ import { Button, Input, Price } from '@theme/components';
13
13
  import { pushBeginCheckout } from '@theme/utils/gtm';
14
14
  import { ROUTES } from '@theme/routes';
15
- import { useRouter, useLocalization } from '@akinon/next/hooks';
15
+ import { useLocalization, useRouter } from '@akinon/next/hooks';
16
16
  import PluginModule, { Component } from '@akinon/next/components/plugin-module';
17
17
  import clsx from 'clsx';
18
18
 
@@ -35,7 +35,9 @@ export const Summary = (props: Props) => {
35
35
  setError,
36
36
  reset,
37
37
  formState: { errors }
38
- } = useForm<{ voucherCode: string }>({
38
+ } = useForm<{
39
+ voucherCode: string;
40
+ }>({
39
41
  resolver: yupResolver(voucherCodeFormSchema(t))
40
42
  });
41
43
  const dispatch = useAppDispatch();
@@ -88,6 +90,29 @@ export const Summary = (props: Props) => {
88
90
  });
89
91
  };
90
92
 
93
+ const checkoutProviderProps = {
94
+ className: clsx([
95
+ 'py-2.5',
96
+ 'bg-black',
97
+ 'relative',
98
+ 'hover:bg-black',
99
+ 'before:content-[""]',
100
+ 'before:w-6',
101
+ 'before:h-6',
102
+ 'before:bg-white',
103
+ 'before:absolute',
104
+ 'before:rounded-r-[18px]',
105
+ 'before:left-0',
106
+ 'after:content-[""]',
107
+ 'after:absolute',
108
+ 'after:w-3',
109
+ 'after:h-3',
110
+ 'after:bg-[#d02c2f]',
111
+ 'after:rounded-xl',
112
+ 'after:left-1'
113
+ ])
114
+ };
115
+
91
116
  useEffect(() => {
92
117
  const products = basket.basketitem_set.map((basketItem) => ({
93
118
  ...basketItem.product
@@ -189,30 +214,14 @@ export const Summary = (props: Props) => {
189
214
  {t('basket.summary.proceed_to_checkout')}
190
215
  </Button>
191
216
 
217
+ <PluginModule
218
+ component={Component.AkifastCheckoutButton}
219
+ props={checkoutProviderProps}
220
+ />
221
+
192
222
  <PluginModule
193
223
  component={Component.OneClickCheckoutButtons}
194
- props={{
195
- className: clsx([
196
- 'py-2.5',
197
- 'bg-black',
198
- 'relative',
199
- 'hover:bg-black',
200
- 'before:content-[""]',
201
- 'before:w-6',
202
- 'before:h-6',
203
- 'before:bg-white',
204
- 'before:absolute',
205
- 'before:rounded-r-[18px]',
206
- 'before:left-0',
207
- 'after:content-[""]',
208
- 'after:absolute',
209
- 'after:w-3',
210
- 'after:h-3',
211
- 'after:bg-[#d02c2f]',
212
- 'after:rounded-xl',
213
- 'after:left-1'
214
- ])
215
- }}
224
+ props={checkoutProviderProps}
216
225
  />
217
226
  </div>
218
227
  </div>
@@ -1,14 +1,26 @@
1
1
  'use client';
2
2
 
3
+ import { WIDGET_TYPE } from '@theme/types';
3
4
  import clsx from 'clsx';
4
5
 
5
- import { Button, Icon } from '@theme/components';
6
- import { useLocalization } from '@akinon/next/hooks';
6
+ import { Accordion, Button, Checkbox, Icon, Radio } from '@theme/components';
7
+ import { SizeFilter } from './size-filter';
8
+
9
+ import { useLocalization, useRouter } from '@akinon/next/hooks';
10
+ import { Facet, FacetChoice } from '@akinon/next/types';
7
11
  import { useAppDispatch, useAppSelector } from '@akinon/next/redux/hooks';
8
- import { resetSelectedFacets } from '@theme/redux/reducers/category';
12
+ import {
13
+ resetSelectedFacets,
14
+ toggleFacet
15
+ } from '@theme/redux/reducers/category';
9
16
  import CategoryActiveFilters from '@theme/views/category/category-active-filters';
10
17
  import { useMemo } from 'react';
11
- import { FilterItem } from './filter-item';
18
+ import { commonProductAttributes } from '@theme/settings';
19
+
20
+ const COMPONENT_TYPES = {
21
+ [WIDGET_TYPE.category]: Radio,
22
+ [WIDGET_TYPE.multiselect]: Checkbox
23
+ };
12
24
 
13
25
  interface Props {
14
26
  isMenuOpen: boolean;
@@ -16,11 +28,31 @@ interface Props {
16
28
  }
17
29
 
18
30
  export const Filters = (props: Props) => {
31
+ const router = useRouter();
19
32
  const facets = useAppSelector((state) => state.category.facets);
20
33
  const dispatch = useAppDispatch();
21
34
  const { t } = useLocalization();
22
35
  const { isMenuOpen, setIsMenuOpen } = props;
23
36
 
37
+ const handleSelectFilter = ({
38
+ facet,
39
+ choice
40
+ }: {
41
+ facet: Facet;
42
+ choice: FacetChoice;
43
+ }) => {
44
+ if (facet.key === 'category_ids') {
45
+ router.push(choice.url);
46
+ } else {
47
+ dispatch(
48
+ toggleFacet({
49
+ facet,
50
+ choice
51
+ })
52
+ );
53
+ }
54
+ };
55
+
24
56
  const haveFilter = useMemo(() => {
25
57
  return (
26
58
  facets.filter(
@@ -34,6 +66,10 @@ export const Filters = (props: Props) => {
34
66
  dispatch(resetSelectedFacets());
35
67
  };
36
68
 
69
+ const sizeKey = commonProductAttributes.find(
70
+ (item) => item.translationKey === 'size'
71
+ ).key;
72
+
37
73
  return (
38
74
  <div
39
75
  className={clsx(
@@ -52,7 +88,71 @@ export const Filters = (props: Props) => {
52
88
  <span>{t('category.filters.ready_to_wear')}</span>
53
89
  </div>
54
90
  {facets.map((facet) => {
55
- return <FilterItem key={facet.key} facet={facet} />;
91
+ let Component = null;
92
+ const choices = [...facet.data.choices];
93
+
94
+ if (facet.key === sizeKey) {
95
+ // If it's a size facet, use the custom size filter component
96
+ Component = SizeFilter;
97
+
98
+ const order = ['xs', 's', 'm', 'l', 'xl'];
99
+ choices.sort((a, b) => {
100
+ return (
101
+ order.indexOf(a.label.toLowerCase()) -
102
+ order.indexOf(b.label.toLowerCase())
103
+ );
104
+ });
105
+ } else {
106
+ Component =
107
+ COMPONENT_TYPES[facet.widget_type] ||
108
+ COMPONENT_TYPES[WIDGET_TYPE.category];
109
+ }
110
+
111
+ return (
112
+ <Accordion
113
+ key={facet.key}
114
+ title={facet.name}
115
+ isCollapse={choices.some((choice) => choice.is_selected)}
116
+ dataTestId={`filter-${facet.name}`}
117
+ >
118
+ <div
119
+ className={clsx(
120
+ 'flex gap-4 flex-wrap',
121
+ facet.key === sizeKey ? 'flex-row' : 'flex-col' // TODO: This condition must be refactor to a better way
122
+ )}
123
+ >
124
+ {choices.map((choice, index) => (
125
+ <Component // TODO: This dynamic component can be a hook or higher order component so it props can be standardized
126
+ key={choice.label}
127
+ data={choice}
128
+ name={facet.key}
129
+ onChange={() => {
130
+ if (facet.key !== sizeKey) {
131
+ // TODO: This condition must be refactor to a better way
132
+ handleSelectFilter({ facet, choice });
133
+ }
134
+ }}
135
+ onClick={() => {
136
+ if (facet.key === sizeKey) {
137
+ // TODO: This condition must be refactor to a better way
138
+ handleSelectFilter({ facet, choice });
139
+ }
140
+ }}
141
+ checked={choice.is_selected}
142
+ data-testid={`${choice.label.trim()}`}
143
+ >
144
+ {choice.label} (
145
+ <span
146
+ data-testid={`filter-count-${facet.name.toLowerCase()}-${index}`}
147
+ >
148
+ {choice.quantity}
149
+ </span>
150
+ )
151
+ </Component>
152
+ ))}
153
+ </div>
154
+ </Accordion>
155
+ );
56
156
  })}
57
157
  <div className="lg:hidden">
58
158
  <CategoryActiveFilters />
@@ -11,12 +11,17 @@ import * as yup from 'yup';
11
11
  import { yupResolver } from '@hookform/resolvers/yup';
12
12
  import clsx from 'clsx';
13
13
  import { useGetBasketQuery } from '@akinon/next/data/client/basket';
14
- import { useCaptcha } from '@akinon/next/hooks';
14
+ import { useCaptcha, useLocalization } from '@akinon/next/hooks';
15
15
  import { AuthError } from '@akinon/next/types';
16
- import { useLocalization } from '@akinon/next/hooks';
17
16
  import { Image } from '@akinon/next/components/image';
18
-
19
- const oauthProviders = [
17
+ import PluginModule, { Component } from '@akinon/next/components/plugin-module';
18
+
19
+ const oauthProviders: Array<{
20
+ key: string;
21
+ label?: string;
22
+ image?: string;
23
+ localeKey?: string;
24
+ }> = [
20
25
  {
21
26
  key: 'google',
22
27
  label: 'Google',
@@ -31,10 +36,6 @@ const oauthProviders = [
31
36
  key: 'apple',
32
37
  label: 'Apple',
33
38
  image: '/apple.svg'
34
- },
35
- {
36
- key: 'akifast',
37
- localeKey: 'auth.login.form.quick_login'
38
39
  }
39
40
  ];
40
41
 
@@ -93,7 +94,10 @@ export const Login = () => {
93
94
  }
94
95
 
95
96
  const fieldErrors = errors.find((error) => error.type === 'field_errors')
96
- ?.data as { name: string; value: string[] }[];
97
+ ?.data as {
98
+ name: string;
99
+ value: string[];
100
+ }[];
97
101
  const nonFieldErrors = errors.find(
98
102
  (error) => error.type === 'non_field_errors'
99
103
  )?.data as string[];
@@ -227,6 +231,13 @@ export const Login = () => {
227
231
  {provider.localeKey ? t(provider.localeKey) : provider.label}
228
232
  </Button>
229
233
  ))}
234
+ <PluginModule
235
+ component={Component.AkifastQuickLoginButton}
236
+ props={{
237
+ isCaptchaVisible,
238
+ captchaValidated
239
+ }}
240
+ />
230
241
  </div>
231
242
  </section>
232
243
  );
@@ -123,6 +123,40 @@ export default function ProductInfo({ data }: ProductPageProps) {
123
123
  }
124
124
  };
125
125
 
126
+ const checkoutProviderProps = {
127
+ product: data.product,
128
+ clearBasket: true,
129
+ addBeforeClick: variantsSelectionCheck,
130
+ openMiniBasket: false,
131
+ className: clsx([
132
+ 'py-2.5',
133
+ 'bg-black',
134
+ 'relative',
135
+ 'hover:bg-black',
136
+ 'before:content-[""]',
137
+ 'before:w-6',
138
+ 'before:h-6',
139
+ 'before:bg-white',
140
+ 'before:absolute',
141
+ 'before:rounded-r-[18px]',
142
+ 'before:left-0',
143
+ 'after:content-[""]',
144
+ 'after:absolute',
145
+ 'after:w-3',
146
+ 'after:h-3',
147
+ 'after:bg-[#d02c2f]',
148
+ 'after:rounded-xl',
149
+ 'after:left-1'
150
+ ]),
151
+ onError: (error) =>
152
+ setProductError(
153
+ error?.data?.non_field_errors ||
154
+ Object.keys(error?.data).map(
155
+ (key) => `${key}: ${error?.data[key].join(', ')}`
156
+ )
157
+ )
158
+ };
159
+
126
160
  return (
127
161
  <>
128
162
  <div
@@ -181,42 +215,18 @@ export default function ProductInfo({ data }: ProductPageProps) {
181
215
  </Button>
182
216
 
183
217
  <PluginModule
184
- component={Component.OneClickCheckoutButtons}
218
+ component={Component.AkifastCheckoutButton}
185
219
  props={{
186
- product: data.product,
187
- clearBasket: true,
188
- addBeforeClick: variantsSelectionCheck,
189
- openMiniBasket: false,
190
- className: clsx([
191
- 'py-2.5',
192
- 'bg-black',
193
- 'relative',
194
- 'hover:bg-black',
195
- 'before:content-[""]',
196
- 'before:w-6',
197
- 'before:h-6',
198
- 'before:bg-white',
199
- 'before:absolute',
200
- 'before:rounded-r-[18px]',
201
- 'before:left-0',
202
- 'after:content-[""]',
203
- 'after:absolute',
204
- 'after:w-3',
205
- 'after:h-3',
206
- 'after:bg-[#d02c2f]',
207
- 'after:rounded-xl',
208
- 'after:left-1'
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
- )
220
+ ...checkoutProviderProps,
221
+ isPdp: true
217
222
  }}
218
223
  />
219
224
 
225
+ <PluginModule
226
+ component={Component.OneClickCheckoutButtons}
227
+ props={checkoutProviderProps}
228
+ />
229
+
220
230
  <MiscButtons
221
231
  productName={data.product.name}
222
232
  productPk={data.product.pk}
@@ -3,19 +3,7 @@
3
3
  "display": "Default",
4
4
  "compilerOptions": {
5
5
  "baseUrl": "./src",
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
- },
6
+ "paths": { "@theme/*": ["./*"] },
19
7
  "allowSyntheticDefaultImports": true,
20
8
  "composite": false,
21
9
  "declaration": true,
@@ -52,5 +40,7 @@
52
40
  ".next/types/**/*.ts",
53
41
  "../../packages/**/*"
54
42
  ],
55
- "exclude": ["node_modules", "../../packages/projectzero/app-template"]
43
+ "exclude": ["node_modules",
44
+ "../../packages/projectzero/app-template"
45
+ ]
56
46
  }
@@ -3,7 +3,6 @@ import * as fs from 'fs';
3
3
  import * as readline from 'readline';
4
4
  import { slugify } from '../utils';
5
5
 
6
- const { execSync } = require('child_process');
7
6
  const loadingSpinner = require('loading-spinner');
8
7
 
9
8
  interface Question {
@@ -140,8 +139,7 @@ export default async (): Promise<void> => {
140
139
  const answers = await getAnswers();
141
140
  const brandName =
142
141
  answers.brandName === '.' ? path.basename(workingDir) : answers.brandName;
143
- const projectDir = answers.brandName === '.' ? workingDir : path.resolve(workingDir, slugify(brandName));
144
- const relativeProjectDir = answers.brandName === '.' ? '.' : slugify(brandName);
142
+ const projectDir = path.resolve(workingDir, slugify(brandName));
145
143
 
146
144
  if (!fs.existsSync(projectDir)) {
147
145
  fs.mkdirSync(projectDir, { recursive: true });
@@ -174,34 +172,12 @@ export default async (): Promise<void> => {
174
172
  name: slugify(brandName)
175
173
  });
176
174
 
177
-
178
- console.log('\x1b[34m%s\x1b[0m', '\nšŸš€ Installing packages...\n');
179
-
180
- execSync(`cd ${relativeProjectDir} && yarn install`, { stdio: 'ignore' });
181
-
182
175
  loadingSpinner.stop();
183
176
 
184
- const successMessage = `
185
- ✨ ${brandName} project is ready at \x1b[4m${projectDir}\x1b[0m
186
-
187
- Within the directory, the following commands are available:
188
-
189
- \x1b[35m$ yarn dev\x1b[0m
190
- \x1b[32mLaunches the development server.\x1b[0m
191
-
192
- \x1b[35m$ yarn build\x1b[0m
193
- \x1b[32mCompiles the app into static files for production.\x1b[0m
194
-
195
- \x1b[35m$ yarn start\x1b[0m
196
- \x1b[32mRuns the production server.\x1b[0m
197
- `;
198
-
199
- const getStartedMessage = answers.brandName === '.'
200
- ? 'To get started, you can type:\n\n \x1b[35m$ yarn dev\x1b[0m\n'
201
- : `To get started, you can type:\n\n \x1b[35m$ cd ${relativeProjectDir}\x1b[0m\n \x1b[35m$ yarn dev\x1b[0m\n`;
177
+ console.log(
178
+ '\x1b[32m%s\x1b[0m',
179
+ `\n āœ“ ${answers.brandName} project is ready.\n`
180
+ );
202
181
 
203
- console.log('\x1b[32m%s\x1b[0m', successMessage);
204
- console.log('\x1b[36m%s\x1b[0m', getStartedMessage);
205
- console.log('\x1b[33m%s\x1b[0m', 'Project setup is complete\n');
206
182
  console.log('\x1b[33m%s\x1b[0m', 'Project Zero - Akinon\n');
207
183
  };