Created
January 8, 2020 22:27
-
-
Save SvitlanaShepitsena/8b4f33d9b5607d628d1687957e62975c to your computer and use it in GitHub Desktop.
ProductForm.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as faker from 'faker' | |
import Select from 'react-select' | |
require('dotenv').config() | |
import React, { useState, useEffect, FormEvent } from 'react' | |
import * as yup from 'yup' | |
import CancelSubmitButtons from '../../common/buttons/CancelSubmitButtons' | |
const ProductSchema = yup.object().shape({ | |
name: yup.string().required(), | |
description: yup.string().required(), | |
}) | |
import { | |
Grid, | |
Button, | |
Segment, | |
Card, | |
Form, | |
TextArea, | |
Header, | |
Icon, | |
Input, | |
Loader, | |
Message, | |
TextAreaProps, | |
Dropdown, | |
} from 'semantic-ui-react' | |
import { SingletonRouter } from 'next/router' | |
import withUser from '../../../lib/withUser' | |
import { ElementLike, FieldErrors, useForm } from 'react-hook-form' | |
import styled from 'styled-components' | |
import { | |
useCreateProductMutation, | |
useDepartmentsQuery, | |
useProductTypesQuery, | |
useCategoriesQuery, | |
useBrandsQuery, | |
useMaterialsQuery, | |
CreateProductDocument, | |
CreateProductMutationVariables, | |
} from '../../../generated/apollo-components' | |
type FormData = { | |
brand: string | |
department: string | |
productType: string | |
category: string | |
material: string | |
upc: string | |
style: string | |
key: string | |
tags: string | |
features: string | |
feature: string | |
name: string | |
description: string | |
} | |
import { ApolloError } from 'apollo-client' | |
type FormError = typeof ApolloError | undefined | |
type Props = { | |
id: String | |
router: SingletonRouter | |
} | |
type SelectProps = { | |
label: string | |
error: any | |
loading: boolean | |
pluralKey: string | |
name: string | |
setValue?: any | |
data: any | |
register?: any | |
handleChange?: any | |
} | |
const SvSelect = (props: SelectProps) => { | |
const { | |
label, | |
error, | |
loading, | |
data, | |
pluralKey, | |
name, | |
register, | |
setValue, | |
} = props | |
const [value, setReactSelect] = useState({ | |
selectedOption: [], | |
}) | |
useEffect(() => { | |
let newData = data[`${pluralKey}`].map((e: any) => ({ | |
label: e.value, | |
key: e.id, | |
value: e.id, | |
})) | |
// @ts-ignore | |
if (typeof register === 'function') { | |
register({ name }) | |
} | |
const selectedOption = newData[0] | |
if (typeof setValue === 'function') { | |
setValue(name, selectedOption) | |
} | |
// @ts-ignore | |
setReactSelect({ selectedOption }) | |
}, [data]) | |
const handleMultiChange = (selectedOption: any) => { | |
// setValue('reactSelect', selectedOption) | |
// @ts-ignore | |
setReactSelect({ selectedOption }) | |
} | |
return ( | |
<div> | |
<StyledLabel>{label}</StyledLabel> | |
{error ? ( | |
<div>Error Loading {label}</div> | |
) : loading ? ( | |
<div>Loading {label}</div> | |
) : ( | |
data && | |
data[`${pluralKey}`] && ( | |
<Select | |
placeholder={`Select a ${label}`} | |
options={data[`${pluralKey}`].map((e: any) => ({ | |
label: e.value, | |
key: e.id, | |
value: e.id, | |
}))} | |
value={value.selectedOption} | |
onChange={handleMultiChange} | |
name={`${name}`} | |
/> | |
) | |
)} | |
</div> | |
) | |
} | |
function SvInput(props: { | |
defaultValue?: string | |
label: string | |
errors: any | |
handleChange: any | |
placeholder: string | |
name: string | |
}) { | |
const { | |
placeholder, | |
name, | |
errors, | |
label, | |
handleChange, | |
defaultValue, | |
} = props | |
let errorMessage = errors[name] | |
return ( | |
<> | |
<StyledLabel>{label}</StyledLabel> | |
<Form.Input | |
defaultValue={defaultValue ? defaultValue : ''} | |
placeholder={placeholder} | |
name={name} | |
onChange={handleChange} | |
/> | |
{errors && errorMessage && ( | |
<Message negative>{errorMessage.message}</Message> | |
)} | |
</> | |
) | |
} | |
function SvTextArea(props: { | |
defaultValue: string | |
label: string | |
errors: any | |
handleChange: any | |
placeholder: string | |
name: string | |
}) { | |
const { | |
placeholder, | |
name, | |
errors, | |
label, | |
handleChange, | |
defaultValue, | |
} = props | |
const [val, setVal] = useState(defaultValue) | |
const onChange = ( | |
e: React.FormEvent<HTMLTextAreaElement>, | |
data: TextAreaProps | |
) => { | |
handleChange(e, data) | |
// @ts-ignore | |
setVal(data.value) | |
} | |
let errorMessage = errors[name] | |
return ( | |
<> | |
<StyledLabel>{label}</StyledLabel> | |
<TextArea | |
rows={5} | |
value={val} | |
placeholder={placeholder} | |
name={name} | |
onChange={( | |
e: React.FormEvent<HTMLTextAreaElement>, | |
data: TextAreaProps | |
) => { | |
onChange(e, data) | |
}} | |
/> | |
{errors && errorMessage && ( | |
<Message negative>{errorMessage.message}</Message> | |
)} | |
</> | |
) | |
} | |
const ProductForm = (props: Props) => { | |
const [createProduct, { data, error, loading }] = useCreateProductMutation() | |
const [values, setReactSelect] = useState({ | |
selectedOption: [], | |
}) | |
const handleSelectChange = (selectedOption: any) => { | |
setValue('reactSelect', selectedOption) | |
setReactSelect({ selectedOption }) | |
} | |
const { | |
data: dataDep, | |
error: errDep, | |
loading: loadDep, | |
} = useDepartmentsQuery() | |
const { | |
data: dataProductType, | |
error: errProductType, | |
loading: loadProductType, | |
} = useProductTypesQuery() | |
const { | |
data: dataCategory, | |
error: errCategory, | |
loading: loadCategory, | |
} = useCategoriesQuery() | |
const { | |
data: dataBrand, | |
error: errBrand, | |
loading: loadBrand, | |
} = useBrandsQuery() | |
const { | |
data: dataMaterial, | |
error: errMaterial, | |
loading: loadMaterial, | |
} = useMaterialsQuery() | |
const { id, router } = props | |
const defaultValues = { | |
name: faker.commerce.productName(), | |
description: faker.lorem.sentences(12), | |
productNum: faker.random.uuid(), | |
key: faker.random.uuid().substr(0, 4), | |
style: faker.commerce.productAdjective(), | |
features: 'Features', | |
tags: `${faker.hacker.noun()}, ${faker.hacker.noun()}, ${faker.hacker.noun()}`, | |
} | |
const { register, setValue, handleSubmit, errors } = useForm<FormData>({ | |
validationSchema: ProductSchema, | |
defaultValues: defaultValues, | |
}) | |
const onSubmit = async (data: FormData) => { | |
let newData: any = { ...data } | |
// @ts-ignore | |
newData.department = { connect: { id: data.department.key } } | |
// @ts-ignore | |
newData.brand = { connect: { id: data.brand.key } } | |
// @ts-ignore | |
newData.productType = { connect: { id: data.productType.key } } | |
// @ts-ignore | |
newData.category = { connect: { id: data.category.key } } | |
// @ts-ignore | |
newData.material = { connect: { id: data.material.key } } | |
// @ts-ignore | |
newData.department = { connect: { id: data.department.key } } | |
console.log( | |
'newData' + | |
JSON.stringify(newData, null, 2) + | |
'ProductForm.tsx, 295' | |
) | |
let res | |
try { | |
// @ts-ignore | |
res = await createProduct({ variables: { ...newData } }) | |
} catch (error) { | |
console.log('error', error) | |
} | |
} | |
const handleChange = (e: any, data: any) => { | |
setValue(e.target.name, e.target.value) | |
} | |
useEffect(() => { | |
register({ name: 'name' }) | |
register({ name: 'brand' }) | |
register({ name: 'upc' }) | |
register({ name: 'department' }) | |
register({ name: 'category' }) | |
register({ name: 'style' }) | |
register({ name: 'features' }) | |
register({ name: 'material' }) | |
register({ name: 'productType' }) | |
register({ name: 'key' }) | |
register({ name: 'tags' }) | |
register({ name: 'description' }) | |
}, []) | |
return ( | |
<> | |
<StyledHeader as="h1">Create a Product</StyledHeader> | |
<StyledForm onSubmit={handleSubmit(onSubmit)}> | |
<SegmentStyled raised> | |
<Grid stackable columns={3}> | |
<Grid.Column> | |
<SvInput | |
label="* Name" | |
defaultValue={defaultValues['name']} | |
name="name" | |
placeholder="Enter a Product Name" | |
handleChange={handleChange} | |
errors={errors} | |
/> | |
</Grid.Column> | |
<Grid.Column> | |
<SvSelect | |
register={register} | |
setValue={setValue} | |
error={errBrand} | |
loading={loadBrand} | |
data={dataBrand} | |
label="Brand" | |
name="brand" | |
pluralKey="brands" | |
/> | |
</Grid.Column> | |
<Grid.Column> | |
<SvInput | |
label="Unique Product Number" | |
name="productNum" | |
defaultValue={defaultValues['productNum']} | |
placeholder="Enter a UPC number" | |
handleChange={handleChange} | |
errors={errors} | |
/> | |
</Grid.Column> | |
</Grid> | |
</SegmentStyled> | |
<SegmentStyled raised> | |
<Grid stackable columns={3}> | |
<Grid.Column> | |
<SvSelect | |
register={register} | |
setValue={setValue} | |
error={errProductType} | |
loading={loadProductType} | |
data={dataProductType} | |
label="Product Type (Shoes, Clothes, Jewerly)" | |
pluralKey="productTypes" | |
name="productType" | |
handleChange={handleSelectChange} | |
/> | |
</Grid.Column> | |
<Grid.Column> | |
<SvSelect | |
error={errCategory} | |
loading={loadCategory} | |
data={dataCategory} | |
register={register} | |
setValue={setValue} | |
label="Category (Dress, Coat, Boots etc)" | |
pluralKey="categories" | |
name="category" | |
handleChange={handleSelectChange} | |
/> | |
</Grid.Column> | |
<Grid.Column> | |
<SvSelect | |
error={errDep} | |
data={dataDep} | |
loading={loadDep} | |
register={register} | |
setValue={setValue} | |
label="Department (Baby, Mans Shoes etc)" | |
pluralKey="departments" | |
name="department" | |
handleChange={handleSelectChange} | |
/> | |
</Grid.Column> | |
</Grid> | |
</SegmentStyled> | |
<SegmentStyled raised> | |
<Grid stackable columns={3}> | |
<Grid.Column> | |
<SvInput | |
label="Style (Cocktail dress, classic)" | |
name="style" | |
defaultValue={defaultValues['style']} | |
placeholder="Enter a product style" | |
handleChange={handleChange} | |
errors={errors} | |
/> | |
</Grid.Column> | |
<Grid.Column> | |
<SvInput | |
label="Features (Hooded, 3/4 sleeves)" | |
name="features" | |
defaultValue={defaultValues['features']} | |
placeholder="Enter main product features" | |
handleChange={handleChange} | |
errors={errors} | |
/> | |
</Grid.Column> | |
<Grid.Column> | |
<SvSelect | |
error={errMaterial} | |
data={dataMaterial} | |
loading={loadMaterial} | |
register={register} | |
setValue={setValue} | |
label="Material" | |
pluralKey="materials" | |
name="material" | |
handleChange={handleSelectChange} | |
/> | |
</Grid.Column> | |
</Grid> | |
<br /> | |
<Grid stackable columns={1}> | |
<Grid.Column> | |
<SvTextArea | |
label="* Description" | |
defaultValue={defaultValues['description']} | |
name="description" | |
placeholder="Enter a product description" | |
handleChange={handleChange} | |
errors={errors} | |
/> | |
</Grid.Column> | |
<Grid.Column> | |
<SvInput | |
label="Tags" | |
name="tags" | |
defaultValue={defaultValues['tags']} | |
placeholder="Enter a product feature" | |
handleChange={handleChange} | |
errors={errors} | |
/> | |
</Grid.Column> | |
<Grid.Column> | |
<SvInput | |
label="Key" | |
name="key" | |
defaultValue={defaultValues['key']} | |
placeholder="Enter a product key" | |
handleChange={handleChange} | |
errors={errors} | |
/> | |
</Grid.Column> | |
</Grid> | |
</SegmentStyled> | |
<br /> | |
<CancelSubmitButtons /> | |
</StyledForm> | |
</> | |
) | |
} | |
export default withUser(ProductForm) | |
const StyledForm = styled(Form)` | |
&&& { | |
font-size: 16px; | |
} | |
` | |
const StyledLabel = styled.label` | |
&&& { | |
font-size: 16px; | |
display: block; | |
margin-bottom: 5px !important; | |
} | |
` | |
const StyledHeader = styled.label` | |
&&& { | |
color: #595959; | |
} | |
` | |
const FixedNav = styled.div` | |
&&& { | |
position: fixed !important; | |
@media only screen and (min-width: 815px) { | |
// background: rgba(0, 0, 0, 0.87); | |
border-bottom-right-radius: 4px; | |
padding: 7px; | |
top: 0px; | |
left: 600px; | |
z-index: 102 !important; | |
max-width: 220px; | |
} | |
@media (max-width: 814px) { | |
top: 10px; | |
right: 10px; | |
} | |
} | |
` | |
const SegmentStyled = styled(Segment)` | |
&&& { | |
@media only screen and (min-width: 815px) { | |
margin-bottom: 28px; | |
} | |
@media (max-width: 814px) { | |
padding-left: 0 !important; | |
padding-right: 0 !important; | |
} | |
} | |
` |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment