Skip to content

Commit

Permalink
feat(app-signup): add initial signup form
Browse files Browse the repository at this point in the history
  • Loading branch information
rams23 committed Dec 28, 2020
1 parent 07ce171 commit 09da2c5
Show file tree
Hide file tree
Showing 21 changed files with 379 additions and 13 deletions.
52 changes: 50 additions & 2 deletions packages/game-app/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion packages/game-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,18 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"@hookform/resolvers": "^1.2.0",
"@reduxjs/toolkit": "^1.5.0",
"firebase": "^8.2.1",
"i18n-js": "^3.8.0",
"react": "^17.0.1",
"react-dom": "^17.0.1",
"react-hook-form": "^6.13.1",
"react-redux": "^7.2.2",
"react-router-dom": "^5.2.0",
"redux-saga": "^1.1.3",
"web-vitals": "^0.2.4"
"web-vitals": "^0.2.4",
"yup": "^0.32.8"
},
"scripts": {
"start": "react-app-rewired start",
Expand Down
22 changes: 13 additions & 9 deletions packages/game-app/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,24 @@
import React from 'react';
import React, { Suspense } from 'react';
import { Redirect, Route, Switch } from 'react-router-dom';
import { PrivateRoute, RoutingPath } from '@pipeline/routing';
import { useBootstrapIsFinished } from './_shared';

const Signup = React.lazy(() => import('./signup/components/Signup'));

function App() {
const bootstrapIsFinished = useBootstrapIsFinished();

return bootstrapIsFinished ? (
<Switch>
<Route path={RoutingPath.Login} render={() => <div>Login</div>} />
<Route path={RoutingPath.Signup} render={() => <div>Signup</div>} />
<PrivateRoute path={RoutingPath.Dashboard} render={() => <div>Dashboard</div>} />
<Route path="*">
<Redirect to={RoutingPath.Signup} />
</Route>
</Switch>
<Suspense fallback={null}>
<Switch>
<Route path={RoutingPath.Login} render={() => <div>Login</div>} />
<Route path={RoutingPath.Signup} component={Signup} />
<PrivateRoute path={RoutingPath.Dashboard} render={() => <div>Dashboard</div>} />
<Route path="*">
<Redirect to={RoutingPath.Signup} />
</Route>
</Switch>
</Suspense>
) : (
<div>LOADING ...</div>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import React from 'react';

type Option = string | { value: string; label: string };

type Props = {
name: string;
label: string;
value: string;
options: Option[];
onChange: React.ChangeEventHandler<HTMLSelectElement>;
errorMessage?: string | null;
};

const SelectInput: React.FC<Props> = ({ value, name, label, onChange, options, errorMessage }) => {
return (
<div className="column">
<label htmlFor={name}>{label}</label>
<select name={name} id={name} value={value} onChange={onChange}>
{options.map(o => {
const value = typeof o === 'string' ? o : o.value;
const label = typeof o === 'string' ? o : o.label;
return <option value={value}>{label}</option>;
})}
</select>
{errorMessage ? <span className="error-message">{errorMessage}</span> : null}
</div>
);
};

SelectInput.displayName = 'SelectInput';

export default SelectInput;
3 changes: 3 additions & 0 deletions packages/game-app/src/_shared/components/SelectInput/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import SelectInput from './SelectInput';

export default SelectInput;
23 changes: 23 additions & 0 deletions packages/game-app/src/_shared/components/TextInput/TextInput.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import React from 'react';

type Props = {
name: string;
label: string;
value: string;
onChange: React.ChangeEventHandler<HTMLInputElement>;
errorMessage?: string | null;
};

const TextInput: React.FC<Props> = ({ name, value, errorMessage, label, onChange }) => {
return (
<div className="column">
<label htmlFor={name}>{label}</label>
<input type="text" value={value} name={name} id={name} onChange={onChange} />
{errorMessage ? <span className="error-message">{errorMessage}</span> : null}
</div>
);
};

TextInput.displayName = 'TextInput';

export default TextInput;
3 changes: 3 additions & 0 deletions packages/game-app/src/_shared/components/TextInput/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import TextInput from './TextInput';

export default TextInput;
4 changes: 4 additions & 0 deletions packages/game-app/src/_shared/components/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import SelectInput from './SelectInput';
import TextInput from './TextInput';

export { TextInput, SelectInput };
1 change: 1 addition & 0 deletions packages/game-app/src/_shared/config/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ export interface Config {
REACT_APP_FIREBASE_CONFIG_STORAGE_BUCKET: string;
REACT_APP_FIREBASE_CONFIG_MESSAGING_SENDER_ID: string;
REACT_APP_FIREBASE_CONFIG_APP_ID: string;
REACT_APP_FIREBASE_USE_EMULATORS: string;
}
35 changes: 35 additions & 0 deletions packages/game-app/src/_shared/form/FormCheckbox/FormCheckbox.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import React, { useCallback } from 'react';
import { Controller, ControllerRenderProps, useFormContext } from 'react-hook-form';

type Props = {
name: string;
label: string;
};

const FormCheckbox: React.FC<Props> = ({ name, label }) => {
const data = useFormContext();

const renderInput = useCallback(
(props: ControllerRenderProps) => {
return (
<>
<input
type="checkbox"
id={props.name}
name={props.name}
checked={props.value}
onChange={e => props.onChange(e.target.checked)}
/>
<label htmlFor={props.name}>{label}</label>
</>
);
},
[data.errors[name], label],
);

return <Controller name={name} control={data.control} render={renderInput} />;
};

FormCheckbox.displayName = 'FormCheckbox';

export default FormCheckbox;
3 changes: 3 additions & 0 deletions packages/game-app/src/_shared/form/FormCheckbox/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import FormCheckbox from './FormCheckbox';

export default FormCheckbox;
37 changes: 37 additions & 0 deletions packages/game-app/src/_shared/form/FormSelect/FormSelect.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import React, { useCallback } from 'react';
import { Controller, ControllerRenderProps, useFormContext } from 'react-hook-form';
import { SelectInput } from '@pipeline/components';

type Props = {} & Omit<React.ComponentProps<typeof SelectInput>, 'errorMessage' | 'onChange' | 'value'>;

const FormSelect: React.FC<Props> = ({ name, label, options }) => {
const data = useFormContext();

const error = data.errors[name];

const renderInput = useCallback(
(props: ControllerRenderProps) => {
return (
<SelectInput
name={props.name}
label={label}
value={props.value}
options={options}
onChange={props.onChange}
errorMessage={error ? error.message : null}
/>
);
},
[error, label, options],
);

return (
<>
<Controller name={name} control={data.control} render={renderInput} />
</>
);
};

FormSelect.displayName = 'FormSelect';

export default FormSelect;
3 changes: 3 additions & 0 deletions packages/game-app/src/_shared/form/FormSelect/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import FormSelect from './FormSelect';

export default FormSelect;
39 changes: 39 additions & 0 deletions packages/game-app/src/_shared/form/FormTextField/FormTextField.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import React, { useCallback } from 'react';
import { Controller, ControllerRenderProps, useFormContext } from 'react-hook-form';
import { TextInput } from '@pipeline/components';

type Props = {
name: string;
label: string;
};

const FormTextField: React.FC<Props> = ({ name, label }) => {
const data = useFormContext();

const error = data.errors[name];

const renderInput = useCallback(
(props: ControllerRenderProps) => {
return (
<TextInput
name={props.name}
label={label}
value={props.value}
onChange={props.onChange}
errorMessage={error?.message}
/>
);
},
[error, label],
);

return (
<>
<Controller name={name} control={data.control} render={renderInput} />
</>
);
};

FormTextField.displayName = 'FormTextField';

export default FormTextField;
3 changes: 3 additions & 0 deletions packages/game-app/src/_shared/form/FormTextField/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import FormTextField from './FormTextField';

export default FormTextField;
5 changes: 5 additions & 0 deletions packages/game-app/src/_shared/form/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import FormTextField from './FormTextField';
import FormCheckbox from './FormCheckbox';
import FormSelect from './FormSelect';

export { FormTextField, FormCheckbox, FormSelect };
7 changes: 7 additions & 0 deletions packages/game-app/src/_shared/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import 'firebase/analytics';
import { initializeI18n } from './i18n';
import { actions as authActions, selectors as authSelectors } from './auth';
import { useSelector } from 'react-redux';
import config from '@pipeline/app-config';

export function bootstrap() {
initializeI18n();
Expand All @@ -18,6 +19,12 @@ export function bootstrap() {
messagingSenderId: CONFIG.REACT_APP_FIREBASE_CONFIG_MESSAGING_SENDER_ID,
appId: CONFIG.REACT_APP_FIREBASE_CONFIG_APP_ID,
});
if (config.REACT_APP_FIREBASE_USE_EMULATORS === 'true') {
firebase.auth().useEmulator('http://localhost:9099/');
firebase.functions().useEmulator('localhost', 5001);
firebase.firestore().useEmulator('localhost', 8080);
firebase.database().useEmulator('localhost', 9000);
}

firebase.analytics();

Expand Down
Loading

0 comments on commit 09da2c5

Please sign in to comment.