1 | import { Component, h } from 'preact'
|
2 |
|
3 | class FormContainer extends Component {
|
4 | constructor (props) {
|
5 | super(props)
|
6 | this.getSetter = this.getSetter.bind(this)
|
7 | this.startingData = props.values
|
8 | this.validity = {}
|
9 | this.state = Object.assign({}, props.values)
|
10 | }
|
11 |
|
12 | clearState () {
|
13 | const changes = {
|
14 | submitting: false,
|
15 | submitError: false
|
16 | }
|
17 | for (const key in this.state) {
|
18 | if (key !== 'submitting' && key !== 'submitError') {
|
19 | changes[key] = ''
|
20 | }
|
21 | }
|
22 | this.setState(changes)
|
23 | }
|
24 |
|
25 | setValidity (name, valid) {
|
26 | this.validity[name] = !!valid
|
27 | }
|
28 |
|
29 | getSetter (name) {
|
30 | return ({validity, value}) => {
|
31 | if (typeof validity !== 'undefined') {
|
32 | this.setValidity(name, !!validity)
|
33 | }
|
34 | if (typeof value !== 'undefined') {
|
35 | this.setState({[name]: value})
|
36 | }
|
37 | }
|
38 | }
|
39 |
|
40 | isValid () {
|
41 | for (const key in this.validity) {
|
42 | if (!this.validity[key]) {
|
43 | return false
|
44 | }
|
45 | }
|
46 | return true
|
47 | }
|
48 |
|
49 | getChanged () {
|
50 | if (!this.startingData) {
|
51 | return Object.assign({}, this.state)
|
52 | }
|
53 | const changes = {}
|
54 | for (const key in this.state) {
|
55 | const currentVal = this.state[key]
|
56 | if (currentVal !== this.startingData[key]) {
|
57 | changes[key] = currentVal
|
58 | }
|
59 | }
|
60 | for (const key in this.startingData) {
|
61 | const currentVal = this.state[key]
|
62 | if (currentVal !== this.startingData[key]) {
|
63 | changes[key] = currentVal
|
64 | }
|
65 | }
|
66 | if (!Object.keys(changes).length) {
|
67 | return null
|
68 | }
|
69 | return changes
|
70 | }
|
71 |
|
72 | render () {
|
73 | const changes = this.getChanged()
|
74 | const hasChanged = !!changes
|
75 | const isValid = this.isValid()
|
76 |
|
77 | const {submitting, submitError} = this.state
|
78 |
|
79 | const hasNotSubmitted = !submitting && !submitError
|
80 |
|
81 | return (
|
82 | h('form', {
|
83 | className: this.props.className,
|
84 | onSubmit: (e) => {
|
85 | e.preventDefault()
|
86 | if (isValid && (this.props.submitWhenUnchanged || hasChanged)) {
|
87 | const values = Object.assign({}, this.state)
|
88 |
|
89 | delete values.submitting
|
90 | delete values.submitError
|
91 | const res = this.props.onSubmit({
|
92 | values,
|
93 | changes
|
94 | })
|
95 | if (res && res.then) {
|
96 | this.setState({submitting: true})
|
97 | res.then(
|
98 | () => {
|
99 | this.clearState()
|
100 | },
|
101 | () => {
|
102 | this.setState({submitError: true, submitting: false})
|
103 | }
|
104 | )
|
105 | }
|
106 | }
|
107 | }
|
108 | },
|
109 | submitting && submitting && h('div', null, this.props.submitMessage),
|
110 | submitError && submitting && h('div', null, 'Something went wrong'),
|
111 | hasNotSubmitted && this.props.children[0]({
|
112 | values: this.state,
|
113 | validity: this.validity,
|
114 | getSetter: this.getSetter,
|
115 | formIsValid: isValid
|
116 | })
|
117 | )
|
118 | )
|
119 | }
|
120 | }
|
121 |
|
122 | FormContainer.defaultProps = {
|
123 | submitMessage: 'Sending...'
|
124 | }
|
125 |
|
126 | export default FormContainer
|