Skip to content

Instantly share code, notes, and snippets.

@mizdra
Created January 16, 2020 14:49
Show Gist options
  • Save mizdra/c05619150f6f7b3f8144ea9e01f7d95e to your computer and use it in GitHub Desktop.
Save mizdra/c05619150f6f7b3f8144ea9e01f7d95e to your computer and use it in GitHub Desktop.
import React from 'react';
import TextField from '@material-ui/core/TextField';
import Button from '@material-ui/core/Button';
import Grid from '@material-ui/core/Grid';
import InputLabel from '@material-ui/core/InputLabel';
import { makeStyles } from '@material-ui/core/styles';
import useForm from 'react-hook-form';
const useStyles = makeStyles((theme) => ({
labelContainer: {
[theme.breakpoints.up('md')]: {
marginTop: theme.spacing(2.5),
},
},
label: {
color: theme.palette.text.primary,
},
}));
export type ItemDataFormData = {
name: string;
tagCount: string;
guestPrice: string;
memberPrice: string;
comment: string;
};
export type Item = {
id: number;
createdAt: string;
updatedAt: string;
revisions: {
name: string;
guestPrice: number;
memberPrice: number;
comment: string | null;
tagCount: number;
}[];
user: {
uid: string;
};
};
export interface ItemDataFormHandler {
focusFirst(): void;
reset(): void;
}
export type ItemDataFormProps = {
onSubmit: (formData: ItemDataFormData) => void;
item?: Item;
submitButtonLabel: string;
};
export const ItemDataForm = React.forwardRef<ItemDataFormHandler, ItemDataFormProps>(function ItemDataForm(props, ref) {
const classes = useStyles();
const { register, handleSubmit, reset } = useForm<ItemDataFormData>();
const firstInputEl = React.useRef<HTMLInputElement | null>(null);
const handleFirstInputRef: React.Ref<HTMLInputElement> = React.useCallback(
(ref) => {
register(ref);
firstInputEl.current = ref;
},
[register],
);
React.useImperativeHandle(ref, () => ({
focusFirst: () => {
firstInputEl.current?.focus();
},
reset,
}));
return (
<form onSubmit={handleSubmit(props.onSubmit)}>
<Grid container spacing={3}>
<Grid className={classes.labelContainer} item xs={12} md={3}>
<InputLabel className={classes.label} htmlFor="name">
商品名 *
</InputLabel>
</Grid>
<Grid item xs={12} md={9}>
<TextField
id="name"
name="name"
label="商品名"
variant="outlined"
required
style={{
width: '100%',
maxWidth: '20em',
}}
inputRef={handleFirstInputRef}
defaultValue={props.item ? props.item.revisions[0].name : undefined}
/>
</Grid>
<Grid className={classes.labelContainer} item xs={12} md={3}>
<InputLabel className={classes.label} htmlFor="tagCount">
値札の枚数 *
</InputLabel>
</Grid>
<Grid item xs={12} md={9}>
<TextField
id="tagCount"
name="tagCount"
label="値札の枚数"
variant="outlined"
type="number"
required
inputProps={{
min: 0,
}}
style={{
width: '100%',
maxWidth: '10em',
}}
inputRef={register}
defaultValue={props.item ? props.item.revisions[0].tagCount : undefined}
/>
</Grid>
<Grid className={classes.labelContainer} item xs={12} md={3}>
<InputLabel className={classes.label} htmlFor="guestPrice">
通常価格 *
</InputLabel>
</Grid>
<Grid item xs={12} md={9}>
<TextField
id="guestPrice"
name="guestPrice"
label="通常価格"
variant="outlined"
type="number"
required
inputProps={{
min: 0,
}}
style={{
width: '100%',
maxWidth: '10em',
}}
inputRef={register}
defaultValue={props.item ? props.item.revisions[0].guestPrice : undefined}
/>
</Grid>
<Grid className={classes.labelContainer} item xs={12} md={3}>
<InputLabel className={classes.label} htmlFor="memberPrice">
部員価格 *
</InputLabel>
</Grid>
<Grid item xs={12} md={9}>
<TextField
id="memberPrice"
name="memberPrice"
label="部員価格"
variant="outlined"
type="number"
required
inputProps={{
min: 0,
}}
style={{
width: '100%',
maxWidth: '10em',
}}
inputRef={register}
defaultValue={props.item ? props.item.revisions[0].memberPrice : undefined}
/>
</Grid>
<Grid className={classes.labelContainer} item xs={12} md={3}>
<InputLabel className={classes.label} htmlFor="comment">
コメント
</InputLabel>
</Grid>
<Grid item xs={12} md={9}>
<TextField
id="comment"
name="comment"
label="コメント"
variant="outlined"
fullWidth
multiline
rows="4"
inputRef={register}
defaultValue={props.item ? props.item.revisions[0].comment : undefined}
/>
</Grid>
<Grid item xs={12} md={12}>
<Button type="submit" variant="contained" color="primary">
{props.submitButtonLabel}
</Button>
</Grid>
</Grid>
</form>
);
});
import React from 'react';
import { Shell } from '../../../components/template/shell';
import Head from 'next/head';
import { useSnackbar } from 'notistack';
import { apiClient } from '../../../singletons/api-client';
import { Me_Items_New_ReqBody } from '../../../../shared/api-types';
import { ItemDataForm, ItemDataFormHandler, ItemDataFormData } from '../../../components/molecules/item-data-form';
export default function MeItemsNewPage() {
const { enqueueSnackbar } = useSnackbar();
const formRef = React.useRef<ItemDataFormHandler>(null);
// フォームがマウントされたら自動的にフォーカスする
React.useEffect(() => {
if (formRef.current) {
formRef.current.focusFirst();
}
}, []);
const onSubmit = async (data: ItemDataFormData) => {
try {
await apiClient.post('/me/items/new', {
name: data.name,
tagCount: +data.tagCount,
guestPrice: +data.guestPrice,
memberPrice: +data.memberPrice,
comment: data.comment === '' ? undefined : data.comment,
} as Me_Items_New_ReqBody);
enqueueSnackbar('商品を登録しました.', {
variant: 'success',
autoHideDuration: 2000,
});
if (formRef.current) {
formRef.current.reset();
formRef.current.focusFirst();
}
} catch (e) {
enqueueSnackbar('商品の登録に失敗しました.', { variant: 'error' });
console.error(e);
}
};
return (
<Shell pageTitle="商品の登録">
<Head>
<title>商品の登録 - Regisys</title>
</Head>
<ItemDataForm ref={formRef} onSubmit={onSubmit} submitButtonLabel="登録" />
</Shell>
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment