summaryrefslogtreecommitdiff
path: root/packages/create-astro/src/components/App.tsx
blob: 4cf9f38526321dcee80fbb505938c48c834aa3ec (plain) (blame)
1
2
3
4
5
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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
import React, { FC, useEffect } from 'react';
import { prepareTemplate, isEmpty, emptyDir } from '../utils';
import Header from './Header';
import Install from './Install';
import ProjectName from './ProjectName';
import Template from './Template';
import Confirm from './Confirm';
import Finalize from './Finalize';

interface Context {
  use: 'npm' | 'yarn';
  skipInstall?: boolean;
  projectExists?: boolean;
  force?: boolean;
  projectName?: string;
  template?: string;
  templates: string[];
  ready?: boolean;
}

const getStep = ({ projectName, projectExists: exists, template, force, ready, skipInstall }: Context) => {
  switch (true) {
    case !projectName:
      return {
        key: 'projectName',
        Component: ProjectName,
      };
    case projectName && exists === true && typeof force === 'undefined':
      return {
        key: 'force',
        Component: Confirm,
      };
    case (exists === false || force) && !template:
      return {
        key: 'template',
        Component: Template,
      };
    case !ready && !skipInstall:
      return {
        key: 'install',
        Component: Install,
      };
    case ready:
      return {
        key: 'final',
        Component: Finalize,
      };
    default:
      return {
        key: 'empty',
        Component: () => <></>,
      };
  }
};

const App: FC<{ context: Context }> = ({ context }) => {
  const [state, setState] = React.useState(context);
  const step = React.useRef(getStep(context));
  const onSubmit = (value: string | boolean) => {
    const { key } = step.current;
    const newState = { ...state, [key]: value };
    step.current = getStep(newState);
    setState(newState);
  };

  useEffect(() => {
    let isSubscribed = true;
    if (state.projectName && typeof state.projectExists === 'undefined') {
      const newState = { ...state, projectExists: !isEmpty(state.projectName) };
      step.current = getStep(newState);
      if (isSubscribed) {
        setState(newState);
      }
    }

    if (state.projectName && (state.projectExists === false || state.force) && state.template) {
      if (state.force) emptyDir(state.projectName);
      prepareTemplate({
        use: context.use,
        templateName: state.template,
        projectName: state.projectName,
        skipInstall: state.skipInstall,
      }).then(() => {
        if (isSubscribed) {
          setState((v) => {
            const newState = { ...v, ready: true };
            step.current = getStep(newState);
            return newState;
          });
        }
      });
    }

    return () => {
      isSubscribed = false;
    };
  }, [state]);
  const { Component } = step.current;

  return (
    <>
      <Header context={state} />
      <Component context={state} onSubmit={onSubmit} />
    </>
  );
};

export default App;