Created
November 12, 2017 20:26
-
-
Save ferdinandsalis/703737daec26daffe056cd043b6f7551 to your computer and use it in GitHub Desktop.
This file contains 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 React from 'react' | |
import revalidation from 'revalidation' | |
import gql from 'graphql-tag.macro' | |
import { filter } from 'graphql-anywhere' | |
import { curry } from 'ramda' | |
import { compose, withProps, withHandlers } from 'recompose' | |
import { graphql } from 'react-apollo' | |
import { Button } from '../common/styled' | |
import { getValue } from '../form/utils' | |
import { isRequired } from '../../utils/validation' | |
import { connectionQuery } from './connection' | |
import Field from '../form/field' | |
import Fieldset from '../form/fieldset' | |
import Input from '../form/input' | |
const Form = ({ | |
revalidation: { | |
form, | |
onChange, | |
valid, | |
onSubmit, | |
submitted, | |
updateValueAndValidate, | |
errors = [] | |
}, | |
onSubmit: submitCb | |
}) => ( | |
<form> | |
<Field | |
required | |
name="name" | |
label="Name des Standortes" | |
onChange={updateValueAndValidate} | |
value={form.name} | |
errors={errors.name} | |
control={Input} | |
placeholder="Lager" | |
/> | |
<Fieldset heading="Adresse"> | |
<Field | |
required | |
name="street" | |
label="Straße" | |
value={form.address.street} | |
errors={errors.address.street} | |
onChange={e => onChange(['address', 'street'], getValue(e))} | |
control={Input} | |
placeholder="Parkring 18/4" | |
/> | |
<Field | |
required | |
name="postalcode" | |
label="Postleitzahl" | |
value={form.address.postalcode} | |
errors={errors.postalcode} | |
onChange={e => onChange(['address', 'postalcode'], getValue(e))} | |
control={Input} | |
placeholder="1010" | |
/> | |
<Field | |
required | |
name="locality" | |
label="Ort" | |
value={form.address.locality} | |
errors={errors.address.locality} | |
onChange={e => onChange(['address', 'locality'], getValue(e))} | |
control={Input} | |
placeholder="Wien" | |
/> | |
<Field | |
required | |
name="country" | |
label="Land" | |
value={form.address.country} | |
errors={errors.address.country} | |
onChange={e => onChange(['address', 'country'], getValue(e))} | |
control={Input} | |
placeholder="AT" | |
/> | |
</Fieldset> | |
<Button | |
children="Speichern" | |
disabled={!valid} | |
onClick={e => { | |
e.preventDefault() | |
onSubmit(({ valid, form }) => { | |
if (valid) { | |
return submitCb(form) | |
} else { | |
return null | |
} | |
}) | |
}} | |
/> | |
</form> | |
) | |
const model = { | |
name: '', | |
address: { | |
street: '', | |
postalcode: '', | |
locality: '', | |
country: '' | |
} | |
} | |
const rules = { | |
name: [[isRequired, 'Name darf nicht leer sein']], | |
address: { | |
street: [[isRequired, 'Straße darf nicht leer sein']], | |
postalcode: [[isRequired, 'Postleitzahl darf nicht leer sein']], | |
locality: [[isRequired, 'Ort darf nicht leer sein']], | |
country: [[isRequired, 'Land darf nicht leer sein']] | |
} | |
} | |
export const formFragment = gql` | |
fragment LocationForm on Location { | |
name | |
address { | |
street | |
postalcode | |
locality | |
country | |
} | |
} | |
` | |
const BaseForm = revalidation(Form) | |
// # Create Form | |
export const createMutation = gql` | |
mutation createLocation($input: CreateLocationInput!) { | |
createLocation(input: $input) { | |
location { | |
id | |
locationId | |
...LocationForm | |
} | |
} | |
} | |
${formFragment} | |
` | |
const withCreateMutation = graphql(createMutation, { name: 'createLocation' }) | |
const handleCreate = curry(async ({ onSuccess, createLocation }, values) => { | |
try { | |
const result = await createLocation({ | |
variables: { input: { location: values } }, | |
refetchQueries: [ | |
{ | |
query: connectionQuery, | |
variables: { | |
limit: 25, | |
offset: 0, | |
condition: null, | |
orderBy: { attribute: 'CREATED_AT', descending: true } | |
} | |
} | |
] | |
}) | |
typeof onSuccess === 'function' && onSuccess(result) | |
} catch (error) { | |
console.log(error) | |
} | |
}) | |
export const CreateForm = compose( | |
withCreateMutation, | |
withHandlers({ handleCreate }), | |
withProps(({ handleCreate }) => ({ | |
initialState: model, | |
rules: rules, | |
onSubmit: handleCreate, | |
validateSingle: true, | |
validateOnChange: true | |
})) | |
)(BaseForm) | |
// # Update Form | |
export const initialDataQuery = gql` | |
query showLocation($id: ID!) { | |
location(id: $id) { | |
id | |
...LocationForm | |
} | |
} | |
${formFragment} | |
` | |
const withInitialData = graphql(initialDataQuery, { | |
options: ({ id }) => ({ variables: { id } }) | |
}) | |
export const updateMutation = gql` | |
mutation updateLocation($input: UpdateLocationInput!) { | |
updateLocation(input: $input) { | |
location { | |
id | |
locationId | |
...LocationForm | |
} | |
} | |
} | |
${formFragment} | |
` | |
const withUpdateMutation = graphql(updateMutation, { name: 'updateLocation' }) | |
const handleUpdate = curry( | |
async ({ onSuccess, id, updateLocation }, values) => { | |
try { | |
const result = await updateLocation({ | |
variables: { input: { id, locationPatch: values } } | |
}) | |
typeof onSuccess === 'function' && onSuccess(result) | |
} catch (error) { | |
console.log(error) | |
} | |
} | |
) | |
export const UpdateForm = compose( | |
withInitialData, | |
withUpdateMutation, | |
withHandlers({ handleUpdate }), | |
withProps(({ data, handleUpdate }) => ({ | |
initialState: model, | |
updateForm: data.loading ? null : filter(formFragment, data.location), | |
rules: rules, | |
onSubmit: handleUpdate, | |
validateSingle: true, | |
validateOnChange: true | |
})) | |
)(BaseForm) |
@b2whats sorry for the late reply. The field is really quite dumb.
Here you go
import { head, equals } from 'ramda'
import React, { Component } from 'react'
import { isValid } from 'revalidation'
import { Text } from 'galeriste-design'
import Label from '../form/label'
import Container from '../form/field-container'
import Input from '../form/input'
const createErrorMessage = errorMsgs =>
isValid(errorMsgs) ? null : (
<Text mt={2} f={1} color="red.5">
{head(errorMsgs)}
</Text>
)
class Field extends Component {
shouldComponentUpdate({ value, errors, asyncErrors }) {
const unchanged =
equals(value, this.props.value) &&
equals(errors, this.props.errors) &&
equals(asyncErrors, this.props.asyncErrors)
return unchanged ? false : true
}
render() {
const {
name,
label,
required,
errors,
asyncErrors,
value = '',
onChange,
control: Control = Input,
onBlur = () => {},
...props
} = this.props
return (
<Container>
<Label required={required} name={name}>
{label}
</Label>
<Control
name={name}
value={value}
onBlur={onBlur}
onChange={onChange}
hasErrors={!isValid(errors)}
{...props}
/>
{createErrorMessage(errors)}
{createErrorMessage(asyncErrors)}
</Container>
)
}
}
export default Field
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Show implement '../form/field' please