-
Notifications
You must be signed in to change notification settings - Fork 0
/
ensure-data.js
156 lines (135 loc) · 4.17 KB
/
ensure-data.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
import { promises as fs } from 'fs'
import path from 'path'
let USE_DATA = `// This file is automatically generated by Views and will be overwritten
// when the morpher runs. If you want to contribute to how it's generated, eg,
// improving the algorithms inside, etc, see this:
// https://github.com/viewstools/morph/blob/master/ensure-data.js
import * as fromValidate from './Data/validators.js';
import get from 'lodash/get';
import produce from 'immer';
import set from 'lodash/set';
import React, { useContext, useEffect, useMemo, useReducer, useRef } from 'react';
import parseDate from 'date-fns/parse';
import parseISO from 'date-fns/parseISO';
import formatDate from 'date-fns/format';
import isValidDate from 'date-fns/isValid';
let identity = { in: i => i, out: i => i };
// show
let ItemContext = React.createContext({});
export let ItemProvider = ItemContext.Provider;
export let useItem = ({ path = null, format = identity } = {}) => {
let item = useContext(ItemContext);
return useMemo(() => (path ? { value: format.in(get(item, path)) } : item), [
item,
path,
format,
]); // eslint-ignore-line
// ignore get
};
// capture
let captureItemReducer = produce((draft, action) => {
switch (action.type) {
case CAPTURE_SET_FIELD: {
set(draft, action.key, action.value);
break;
}
case CAPTURE_RESET: {
return action.state;
}
case CAPTURE_FORCE_REQUIRED: {
draft._forceRequired = true;
break;
}
default: {
throw new Error(
\`Unknown action type "\${action.type}" in update item reducer.\`
);
}
}
});
let CAPTURE_SET_FIELD = 'capture/SET_FIELD';
export let setField = (key, value) => ({
type: CAPTURE_SET_FIELD,
key,
value,
});
let CAPTURE_RESET = 'capture/RESET';
export let reset = state => ({ type: CAPTURE_RESET, state });
let CAPTURE_FORCE_REQUIRED = 'capture/FORCE_REQUIRED';
let CaptureItemContext = React.createContext({});
export let CaptureItemProvider = CaptureItemContext.Provider;
export let useCaptureItem = ({
path = null, format = identity, validate = null, required = false
} = {}) => {
let captureItem = useContext(CaptureItemContext);
let touched = useRef(false);
if (process.env.NODE_ENV === 'development') {
if (validate && !(validate in fromValidate)) {
throw new Error(
\`"\${validate}" function doesn't exist or is not exported in Data/validators.js\`
);
}
}
return useMemo(() => {
if (!path) return captureItem;
let [item, dispatch, onSubmit] = captureItem;
if (!item) return {};
let value = format.in(get(item, path));
let isValid =
validate && (touched.current || (required && item._forceRequired))
? fromValidate[validate](value)
: true;
let onChange = value => {
touched.current = true;
dispatch(setField(path, format.out(value)));
}
return {
onChange,
onSubmit,
value,
isValid,
isInvalid: !isValid
};
}, [captureItem, path, format, validate]);
};
export let useCaptureItemProvider = (item, onSubmit) => {
let [state, dispatch] = useReducer(captureItemReducer, item);
useEffect(() => {
dispatch(reset(item));
}, [item]);
return useMemo(() => {
async function _onSubmit() {
try {
if(!await onSubmit()) return;
} catch(error) {}
dispatch({ type: CAPTURE_FORCE_REQUIRED });
}
return [state, dispatch, _onSubmit];
}, [
state,
dispatch,
onSubmit,
]);
};
function formatDateInOut(rvalue, formatIn, formatOut, whenInvalid = '') {
let value =
formatIn === 'iso'
? parseISO(rvalue)
: parseDate(rvalue, formatIn, new Date());
return isValidDate(value) ? formatDate(value, formatOut) : whenInvalid;
}
export let useMakeFormatDate = (formatIn, formatOut, whenInvalid) =>
useMemo(
() => ({
in: value => formatDateInOut(value, formatIn, formatOut, whenInvalid),
out: value => formatDateInOut(value, formatOut, formatIn, whenInvalid),
}),
[]
); // eslint-disable-line
// ignore formatIn, formatouOut, whenInvalid
`
export default function ensureIsBefore({ src }) {
return fs.writeFile(path.join(src, 'useData.js'), USE_DATA, {
encoding: 'utf8',
})
}