@ouroboros/mouth-mui 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/LICENSE +8 -0
  2. package/README.md +15 -0
  3. package/package.json +55 -0
  4. package/src/components/pages/Locales.d.ts +35 -0
  5. package/src/components/pages/Locales.js +188 -0
  6. package/src/components/pages/Locales.tsx +254 -0
  7. package/src/components/pages/Templates/Create.d.ts +36 -0
  8. package/src/components/pages/Templates/Create.js +98 -0
  9. package/src/components/pages/Templates/Create.tsx +139 -0
  10. package/src/components/pages/Templates/Template/Content/Create/Email.d.ts +39 -0
  11. package/src/components/pages/Templates/Template/Content/Create/Email.js +51 -0
  12. package/src/components/pages/Templates/Template/Content/Create/Email.tsx +96 -0
  13. package/src/components/pages/Templates/Template/Content/Create/SMS.d.ts +37 -0
  14. package/src/components/pages/Templates/Template/Content/Create/SMS.js +42 -0
  15. package/src/components/pages/Templates/Template/Content/Create/SMS.tsx +68 -0
  16. package/src/components/pages/Templates/Template/Content/Create/index.d.ts +42 -0
  17. package/src/components/pages/Templates/Template/Content/Create/index.js +177 -0
  18. package/src/components/pages/Templates/Template/Content/Create/index.tsx +257 -0
  19. package/src/components/pages/Templates/Template/Content/Preview/Email.d.ts +37 -0
  20. package/src/components/pages/Templates/Template/Content/Preview/Email.js +51 -0
  21. package/src/components/pages/Templates/Template/Content/Preview/Email.tsx +78 -0
  22. package/src/components/pages/Templates/Template/Content/Preview/SMS.d.ts +32 -0
  23. package/src/components/pages/Templates/Template/Content/Preview/SMS.js +38 -0
  24. package/src/components/pages/Templates/Template/Content/Preview/SMS.tsx +59 -0
  25. package/src/components/pages/Templates/Template/Content/Preview/index.d.ts +42 -0
  26. package/src/components/pages/Templates/Template/Content/Preview/index.js +63 -0
  27. package/src/components/pages/Templates/Template/Content/Preview/index.tsx +107 -0
  28. package/src/components/pages/Templates/Template/Content/Update/Email.d.ts +39 -0
  29. package/src/components/pages/Templates/Template/Content/Update/Email.js +51 -0
  30. package/src/components/pages/Templates/Template/Content/Update/Email.tsx +96 -0
  31. package/src/components/pages/Templates/Template/Content/Update/SMS.d.ts +37 -0
  32. package/src/components/pages/Templates/Template/Content/Update/SMS.js +42 -0
  33. package/src/components/pages/Templates/Template/Content/Update/SMS.tsx +68 -0
  34. package/src/components/pages/Templates/Template/Content/Update/index.d.ts +42 -0
  35. package/src/components/pages/Templates/Template/Content/Update/index.js +117 -0
  36. package/src/components/pages/Templates/Template/Content/Update/index.tsx +162 -0
  37. package/src/components/pages/Templates/Template/Content/View/Email.d.ts +43 -0
  38. package/src/components/pages/Templates/Template/Content/View/Email.js +57 -0
  39. package/src/components/pages/Templates/Template/Content/View/Email.tsx +80 -0
  40. package/src/components/pages/Templates/Template/Content/View/SMS.d.ts +41 -0
  41. package/src/components/pages/Templates/Template/Content/View/SMS.js +46 -0
  42. package/src/components/pages/Templates/Template/Content/View/SMS.tsx +64 -0
  43. package/src/components/pages/Templates/Template/Content/View/index.d.ts +39 -0
  44. package/src/components/pages/Templates/Template/Content/View/index.js +50 -0
  45. package/src/components/pages/Templates/Template/Content/View/index.tsx +78 -0
  46. package/src/components/pages/Templates/Template/Variables.d.ts +34 -0
  47. package/src/components/pages/Templates/Template/Variables.js +91 -0
  48. package/src/components/pages/Templates/Template/Variables.tsx +138 -0
  49. package/src/components/pages/Templates/Template/index.d.ts +90 -0
  50. package/src/components/pages/Templates/Template/index.js +207 -0
  51. package/src/components/pages/Templates/Template/index.tsx +337 -0
  52. package/src/components/pages/Templates/index.d.ts +35 -0
  53. package/src/components/pages/Templates/index.js +112 -0
  54. package/src/components/pages/Templates/index.tsx +165 -0
  55. package/src/index.d.ts +5 -0
  56. package/src/index.js +5 -0
  57. package/src/index.ts +8 -0
  58. package/src/locales.d.ts +72 -0
  59. package/src/locales.js +160 -0
  60. package/src/locales.ts +200 -0
@@ -0,0 +1,139 @@
1
+ /**
2
+ * Templates Create
3
+ *
4
+ * Create component
5
+ *
6
+ * @author Chris Nasr <chris@ouroboroscoding.com>
7
+ * @created 2023-01-20
8
+ */
9
+
10
+ // Ouroboros modules
11
+ import clone from '@ouroboros/clone';
12
+ import { Node } from '@ouroboros/define';
13
+ import { DefineNode } from '@ouroboros/define-mui';
14
+ import mouth, { errors } from '@ouroboros/mouth';
15
+ import TemplateDef from '@ouroboros/mouth/definitions/template.json';
16
+
17
+ // NPM modules
18
+ import PropTypes from 'prop-types';
19
+ import React, { useRef, useState } from 'react';
20
+
21
+ // Material UI
22
+ import Button from '@mui/material/Button';
23
+ import Grid from '@mui/material/Grid';
24
+ import Paper from '@mui/material/Paper';
25
+ import Typography from '@mui/material/Typography';
26
+
27
+ // Locale components
28
+ import Variables from './Template/Variables';
29
+
30
+ // Format Node
31
+ const oNameNode = new Node(TemplateDef.name);
32
+
33
+ // Types
34
+ import { responseErrorStruct } from '@ouroboros/body';
35
+ import { templateStruct } from './Template';
36
+ export interface CreateProps {
37
+ onCancel?: () => void,
38
+ onCreated: (template: templateStruct) => void,
39
+ onError: (error: responseErrorStruct) => void
40
+ }
41
+
42
+ /**
43
+ * Create
44
+ *
45
+ * Form for creating a new template
46
+ *
47
+ * @name Create
48
+ * @access public
49
+ * @param Object props Properties passed to the component
50
+ * @returns React.Component
51
+ */
52
+ export default function Create(props: CreateProps) {
53
+
54
+ // State
55
+ const [record, recordSet] = useState<templateStruct>({
56
+ name: '',
57
+ variables: {}
58
+ });
59
+
60
+ // Refs
61
+ const refName = useRef<DefineNode>(null);
62
+
63
+ // Called when record changes
64
+ function change(field: string, value: any) {
65
+
66
+ // Set the new record
67
+ recordSet(o => {
68
+ const oRecord = clone(o);
69
+ oRecord[field] = value;
70
+ return oRecord;
71
+ });
72
+ }
73
+
74
+ // Called to create the template
75
+ function create() {
76
+
77
+ // Create the data in the system
78
+ mouth.create('template', record).then(data => {
79
+
80
+ // Add the ID to the record
81
+ record._id = data;
82
+
83
+ // Let the parent know
84
+ props.onCreated(clone(record));
85
+ }, error => {
86
+ if(error.code === errors.body.DB_DUPLICATE) {
87
+ refName.current?.error('Duplicate');
88
+ } else {
89
+ if(props.onError) {
90
+ props.onError(error);
91
+ } else {
92
+ throw new Error(JSON.stringify(error));
93
+ }
94
+ }
95
+ })
96
+ }
97
+
98
+ // Render
99
+ return (
100
+ <Paper className="padding">
101
+ <h2>Create new Template</h2>
102
+ <Grid container spacing={2}>
103
+ <Grid item lg={6} md={12} className="field">
104
+ <Typography><strong>Name</strong></Typography>
105
+ <DefineNode
106
+ label="none"
107
+ name="name"
108
+ node={oNameNode}
109
+ onChange={value => change('name', value)}
110
+ onEnterPressed={create}
111
+ ref={refName}
112
+ type="create"
113
+ value={record.name || null}
114
+ />
115
+ </Grid>
116
+ <Grid item lg={6} md={12}>
117
+ <Typography><strong>Variables</strong></Typography>
118
+ <Variables
119
+ onChange={value => change('variables', value)}
120
+ value={record.variables || {}}
121
+ />
122
+ </Grid>
123
+ <Grid item xs={12} className="actions">
124
+ {props.onCancel &&
125
+ <Button variant="contained" color="secondary" onClick={props.onCancel}>Cancel</Button>
126
+ }
127
+ <Button variant="contained" color="primary" onClick={create}>Create Template</Button>
128
+ </Grid>
129
+ </Grid>
130
+ </Paper>
131
+ );
132
+ }
133
+
134
+ // Valid props
135
+ Create.propTypes = {
136
+ onCancel: PropTypes.func,
137
+ onCreated: PropTypes.func.isRequired,
138
+ onError: PropTypes.func.isRequired,
139
+ }
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Communications Templates Template Content Create Email
3
+ *
4
+ * Email component
5
+ *
6
+ * @author Chris Nasr <chris@ouroboroscoding.com>
7
+ * @created 2023-01-22
8
+ */
9
+ /// <reference types="react" />
10
+ import PropTypes from 'prop-types';
11
+ import { contentStruct } from '../../';
12
+ export type EmailProps = {
13
+ errors: Record<string, any>;
14
+ onChanged: (field: string, value: string) => void;
15
+ value: Omit<contentStruct, 'type'>;
16
+ };
17
+ /**
18
+ * Email
19
+ *
20
+ * Handles creating new template content
21
+ *
22
+ * @name Email
23
+ * @access public
24
+ * @param Object props Properties passed to the component
25
+ * @returns React.Component
26
+ */
27
+ declare function Email(props: EmailProps): JSX.Element;
28
+ declare namespace Email {
29
+ var propTypes: {
30
+ errors: PropTypes.Validator<object>;
31
+ onChanged: PropTypes.Validator<(...args: any[]) => any>;
32
+ value: PropTypes.Validator<NonNullable<PropTypes.InferProps<{
33
+ subject: PropTypes.Validator<string>;
34
+ text: PropTypes.Validator<string>;
35
+ html: PropTypes.Validator<string>;
36
+ }>>>;
37
+ };
38
+ }
39
+ export default Email;
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Communications Templates Template Content Create Email
3
+ *
4
+ * Email component
5
+ *
6
+ * @author Chris Nasr <chris@ouroboroscoding.com>
7
+ * @created 2023-01-22
8
+ */
9
+ // Ouroboros modules
10
+ import { Node } from '@ouroboros/define';
11
+ import { DefineNode } from '@ouroboros/define-mui';
12
+ import TemplateEmail from '@ouroboros/mouth/definitions/template_email.json';
13
+ // NPM modules
14
+ import PropTypes from 'prop-types';
15
+ import React from 'react';
16
+ // Material UI
17
+ import Grid from '@mui/material/Grid';
18
+ // Record Nodes
19
+ const oSubjectNode = new Node(TemplateEmail.subject);
20
+ const oTextNode = new Node(TemplateEmail.text);
21
+ const oHtmlNode = new Node(TemplateEmail.html);
22
+ /**
23
+ * Email
24
+ *
25
+ * Handles creating new template content
26
+ *
27
+ * @name Email
28
+ * @access public
29
+ * @param Object props Properties passed to the component
30
+ * @returns React.Component
31
+ */
32
+ export default function Email(props) {
33
+ // Render
34
+ return (React.createElement(Grid, { container: true, className: "content_create_email", spacing: 1 },
35
+ React.createElement(Grid, { item: true, xs: 12, className: "field" },
36
+ React.createElement(DefineNode, { error: props.errors.subject || false, label: "placeholder", name: "subject", node: oSubjectNode, onChange: val => props.onChanged('subject', val), type: "create", value: props.value.subject })),
37
+ React.createElement(Grid, { item: true, xs: 12, lg: 6, className: "field" },
38
+ React.createElement(DefineNode, { error: props.errors.text || false, label: "placeholder", name: "text", node: oTextNode, onChange: val => props.onChanged('text', val), type: "create", value: props.value.text })),
39
+ React.createElement(Grid, { item: true, xs: 12, lg: 6, className: "field" },
40
+ React.createElement(DefineNode, { error: props.errors.html || false, label: "placeholder", name: "html", node: oHtmlNode, onChange: val => props.onChanged('html', val), type: "create", value: props.value.html }))));
41
+ }
42
+ // Valid props
43
+ Email.propTypes = {
44
+ errors: PropTypes.object.isRequired,
45
+ onChanged: PropTypes.func.isRequired,
46
+ value: PropTypes.shape({
47
+ subject: PropTypes.string.isRequired,
48
+ text: PropTypes.string.isRequired,
49
+ html: PropTypes.string.isRequired
50
+ }).isRequired
51
+ };
@@ -0,0 +1,96 @@
1
+ /**
2
+ * Communications Templates Template Content Create Email
3
+ *
4
+ * Email component
5
+ *
6
+ * @author Chris Nasr <chris@ouroboroscoding.com>
7
+ * @created 2023-01-22
8
+ */
9
+
10
+ // Ouroboros modules
11
+ import { Node } from '@ouroboros/define';
12
+ import { DefineNode } from '@ouroboros/define-mui';
13
+ import TemplateEmail from '@ouroboros/mouth/definitions/template_email.json';
14
+
15
+ // NPM modules
16
+ import PropTypes from 'prop-types';
17
+ import React from 'react';
18
+
19
+ // Material UI
20
+ import Grid from '@mui/material/Grid';
21
+
22
+ // Record Nodes
23
+ const oSubjectNode = new Node(TemplateEmail.subject);
24
+ const oTextNode = new Node(TemplateEmail.text);
25
+ const oHtmlNode = new Node(TemplateEmail.html);
26
+
27
+ // Types
28
+ import { contentStruct } from '../../';
29
+ export type EmailProps = {
30
+ errors: Record<string, any>,
31
+ onChanged: (field: string, value: string) => void,
32
+ value: Omit<contentStruct, 'type'>
33
+ }
34
+
35
+ /**
36
+ * Email
37
+ *
38
+ * Handles creating new template content
39
+ *
40
+ * @name Email
41
+ * @access public
42
+ * @param Object props Properties passed to the component
43
+ * @returns React.Component
44
+ */
45
+ export default function Email(props: EmailProps) {
46
+
47
+ // Render
48
+ return (
49
+ <Grid container className="content_create_email" spacing={1}>
50
+ <Grid item xs={12} className="field">
51
+ <DefineNode
52
+ error={props.errors.subject || false}
53
+ label="placeholder"
54
+ name="subject"
55
+ node={oSubjectNode}
56
+ onChange={val => props.onChanged('subject', val)}
57
+ type="create"
58
+ value={props.value.subject}
59
+ />
60
+ </Grid>
61
+ <Grid item xs={12} lg={6} className="field">
62
+ <DefineNode
63
+ error={props.errors.text || false}
64
+ label="placeholder"
65
+ name="text"
66
+ node={oTextNode}
67
+ onChange={val => props.onChanged('text', val)}
68
+ type="create"
69
+ value={props.value.text}
70
+ />
71
+ </Grid>
72
+ <Grid item xs={12} lg={6} className="field">
73
+ <DefineNode
74
+ error={props.errors.html || false}
75
+ label="placeholder"
76
+ name="html"
77
+ node={oHtmlNode}
78
+ onChange={val => props.onChanged('html', val)}
79
+ type="create"
80
+ value={props.value.html}
81
+ />
82
+ </Grid>
83
+ </Grid>
84
+ );
85
+ }
86
+
87
+ // Valid props
88
+ Email.propTypes = {
89
+ errors: PropTypes.object.isRequired,
90
+ onChanged: PropTypes.func.isRequired,
91
+ value: PropTypes.shape({
92
+ subject: PropTypes.string.isRequired,
93
+ text: PropTypes.string.isRequired,
94
+ html: PropTypes.string.isRequired
95
+ }).isRequired
96
+ }
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Communications Templates Template Content Create SMS
3
+ *
4
+ * SMS component
5
+ *
6
+ * @author Chris Nasr <chris@ouroboroscoding.com>
7
+ * @created 2023-01-22
8
+ */
9
+ /// <reference types="react" />
10
+ import PropTypes from 'prop-types';
11
+ import { contentStruct } from '../../';
12
+ export type SMSProps = {
13
+ errors: Record<string, any>;
14
+ onChanged: (field: string, value: string) => void;
15
+ value: Omit<contentStruct, 'type'>;
16
+ };
17
+ /**
18
+ * SMS
19
+ *
20
+ * Handles creating new template content
21
+ *
22
+ * @name SMS
23
+ * @access public
24
+ * @param Object props Properties passed to the component
25
+ * @returns React.Component
26
+ */
27
+ declare function SMS(props: SMSProps): JSX.Element;
28
+ declare namespace SMS {
29
+ var propTypes: {
30
+ errors: PropTypes.Validator<object>;
31
+ onChanged: PropTypes.Validator<(...args: any[]) => any>;
32
+ value: PropTypes.Validator<NonNullable<PropTypes.InferProps<{
33
+ content: PropTypes.Validator<string>;
34
+ }>>>;
35
+ };
36
+ }
37
+ export default SMS;
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Communications Templates Template Content Create SMS
3
+ *
4
+ * SMS component
5
+ *
6
+ * @author Chris Nasr <chris@ouroboroscoding.com>
7
+ * @created 2023-01-22
8
+ */
9
+ // Ouroboros modules
10
+ import { Node } from '@ouroboros/define';
11
+ import { DefineNode } from '@ouroboros/define-mui';
12
+ import TemplateSMS from '@ouroboros/mouth/definitions/template_sms.json';
13
+ // NPM modules
14
+ import PropTypes from 'prop-types';
15
+ import React from 'react';
16
+ // Material UI
17
+ import Box from '@mui/material/Box';
18
+ // Record Nodes
19
+ const oContentNode = new Node(TemplateSMS.content);
20
+ /**
21
+ * SMS
22
+ *
23
+ * Handles creating new template content
24
+ *
25
+ * @name SMS
26
+ * @access public
27
+ * @param Object props Properties passed to the component
28
+ * @returns React.Component
29
+ */
30
+ export default function SMS(props) {
31
+ // Render
32
+ return (React.createElement(Box, { className: "content_create_sms field" },
33
+ React.createElement(DefineNode, { error: props.errors.content || false, label: "placeholder", name: "content", node: oContentNode, onChange: val => props.onChanged('content', val), type: "create", value: props.value.content })));
34
+ }
35
+ // Valid props
36
+ SMS.propTypes = {
37
+ errors: PropTypes.object.isRequired,
38
+ onChanged: PropTypes.func.isRequired,
39
+ value: PropTypes.shape({
40
+ content: PropTypes.string.isRequired
41
+ }).isRequired
42
+ };
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Communications Templates Template Content Create SMS
3
+ *
4
+ * SMS component
5
+ *
6
+ * @author Chris Nasr <chris@ouroboroscoding.com>
7
+ * @created 2023-01-22
8
+ */
9
+
10
+ // Ouroboros modules
11
+ import { Node } from '@ouroboros/define';
12
+ import { DefineNode } from '@ouroboros/define-mui';
13
+ import TemplateSMS from '@ouroboros/mouth/definitions/template_sms.json';
14
+
15
+ // NPM modules
16
+ import PropTypes from 'prop-types';
17
+ import React from 'react';
18
+
19
+ // Material UI
20
+ import Box from '@mui/material/Box';
21
+
22
+ // Record Nodes
23
+ const oContentNode = new Node(TemplateSMS.content);
24
+
25
+ // Types
26
+ import { contentStruct } from '../../';
27
+ export type SMSProps = {
28
+ errors: Record<string, any>,
29
+ onChanged: (field: string, value: string) => void,
30
+ value: Omit<contentStruct, 'type'>
31
+ }
32
+
33
+ /**
34
+ * SMS
35
+ *
36
+ * Handles creating new template content
37
+ *
38
+ * @name SMS
39
+ * @access public
40
+ * @param Object props Properties passed to the component
41
+ * @returns React.Component
42
+ */
43
+ export default function SMS(props: SMSProps) {
44
+
45
+ // Render
46
+ return (
47
+ <Box className="content_create_sms field">
48
+ <DefineNode
49
+ error={props.errors.content || false}
50
+ label="placeholder"
51
+ name="content"
52
+ node={oContentNode}
53
+ onChange={val => props.onChanged('content', val)}
54
+ type="create"
55
+ value={props.value.content}
56
+ />
57
+ </Box>
58
+ );
59
+ }
60
+
61
+ // Valid props
62
+ SMS.propTypes = {
63
+ errors: PropTypes.object.isRequired,
64
+ onChanged: PropTypes.func.isRequired,
65
+ value: PropTypes.shape({
66
+ content: PropTypes.string.isRequired
67
+ }).isRequired
68
+ }
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Communications Templates Template Content Create
3
+ *
4
+ * Create component
5
+ *
6
+ * @author Chris Nasr <chris@ouroboroscoding.com>
7
+ * @created 2023-01-22
8
+ */
9
+ /// <reference types="react" />
10
+ import PropTypes from 'prop-types';
11
+ import { contentStruct } from '../../';
12
+ import { responseErrorStruct } from '@ouroboros/body';
13
+ export type TemplateContentCreateProps = {
14
+ locales: Record<string, string>;
15
+ mobile: boolean;
16
+ onCreated: (content: contentStruct) => void;
17
+ onError: (error: responseErrorStruct) => void;
18
+ template: string;
19
+ };
20
+ /**
21
+ * Create
22
+ *
23
+ * Handles creating new template content
24
+ *
25
+ * @name Create
26
+ * @access public
27
+ * @param Object props Properties passed to the component
28
+ * @returns React.Component
29
+ */
30
+ declare function Create(props: TemplateContentCreateProps): JSX.Element;
31
+ declare namespace Create {
32
+ var propTypes: {
33
+ locales: PropTypes.Validator<{
34
+ [x: string]: string | null | undefined;
35
+ }>;
36
+ mobile: PropTypes.Validator<boolean>;
37
+ onCreated: PropTypes.Validator<(...args: any[]) => any>;
38
+ onError: PropTypes.Requireable<(...args: any[]) => any>;
39
+ template: PropTypes.Validator<string>;
40
+ };
41
+ }
42
+ export default Create;
@@ -0,0 +1,177 @@
1
+ /**
2
+ * Communications Templates Template Content Create
3
+ *
4
+ * Create component
5
+ *
6
+ * @author Chris Nasr <chris@ouroboroscoding.com>
7
+ * @created 2023-01-22
8
+ */
9
+ // Ouroboros modules
10
+ import clone from '@ouroboros/clone';
11
+ import { errorTree } from '@ouroboros/define-mui';
12
+ import mouth, { errors } from '@ouroboros/mouth';
13
+ import RadioButtons from '@ouroboros/react-radiobuttons-mui';
14
+ import { omap, opop } from '@ouroboros/tools';
15
+ // NPM modules
16
+ import PropTypes from 'prop-types';
17
+ import React, { useState } from 'react';
18
+ // Material UI
19
+ import Button from '@mui/material/Button';
20
+ import FormControl from '@mui/material/FormControl';
21
+ import FormHelperText from '@mui/material/FormHelperText';
22
+ import Grid from '@mui/material/Grid';
23
+ import InputLabel from '@mui/material/InputLabel';
24
+ import Select from '@mui/material/Select';
25
+ // Local components
26
+ import Email from './Email';
27
+ import Preview from '../Preview';
28
+ import SMS from './SMS';
29
+ /**
30
+ * Create
31
+ *
32
+ * Handles creating new template content
33
+ *
34
+ * @name Create
35
+ * @access public
36
+ * @param Object props Properties passed to the component
37
+ * @returns React.Component
38
+ */
39
+ export default function Create(props) {
40
+ // State
41
+ const [fieldErrors, fieldErrorsSet] = useState({});
42
+ const [preview, previewSet] = useState(false);
43
+ const [record, recordSet] = useState({
44
+ locale: Object.keys(props.locales)[0],
45
+ template: props.template,
46
+ subject: '',
47
+ text: '',
48
+ html: ''
49
+ });
50
+ const [type, typeSet] = useState('email');
51
+ // Called to create the new content record
52
+ function create() {
53
+ // Send the record data to the server
54
+ mouth.create(`template/${type}`, record).then((data) => {
55
+ // Add the type and ID
56
+ const oRecord = { ...record, type, _id: data };
57
+ // Tell the parent about the new record
58
+ props.onCreated(oRecord);
59
+ }, (error) => {
60
+ if (error.code === errors.body.DATA_FIELDS) {
61
+ fieldErrorsSet(errorTree(error.msg));
62
+ }
63
+ else if (error.code === errors.body.DB_DUPLICATE) {
64
+ fieldErrorsSet({ locale: 'Already used' });
65
+ }
66
+ else if (error.code === errors.TEMPLATE_CONTENT_ERROR) {
67
+ const oLines = { templates: [], variables: [] };
68
+ for (const l of error.msg) {
69
+ if (l[0] === 'template') {
70
+ oLines.templates.push(l[1]);
71
+ }
72
+ else if (l[0] === 'variable') {
73
+ oLines.variables.push(l[1]);
74
+ }
75
+ }
76
+ const lLines = [];
77
+ if (oLines.templates.length) {
78
+ lLines.push('The following templates are invalid: ' + oLines.templates.join(', '));
79
+ }
80
+ if (oLines.variables.length) {
81
+ lLines.push('The following variables are invalid: ' + oLines.variables.join(', '));
82
+ }
83
+ // Show the errors
84
+ if (props.onError) {
85
+ props.onError({ code: 0, msg: lLines.join('\n') });
86
+ }
87
+ }
88
+ else {
89
+ props.onError(error);
90
+ }
91
+ });
92
+ }
93
+ // Called when any fields in the record are changed
94
+ function recordChanged(field, value) {
95
+ // Clear error
96
+ if (field in fieldErrors) {
97
+ const oErrors = clone(fieldErrors);
98
+ delete oErrors[field];
99
+ fieldErrorsSet(oErrors);
100
+ }
101
+ // Clone the record
102
+ const oRecord = clone(record);
103
+ // Update the field
104
+ oRecord[field] = value;
105
+ // Store the new record
106
+ recordSet(oRecord);
107
+ }
108
+ // Called when the type is changed
109
+ function typeChanged(value) {
110
+ // Clone the current record
111
+ const oRecord = clone(record);
112
+ // If the new type is email
113
+ if (value === 'email') {
114
+ // Store the content in the text field and remove it
115
+ oRecord.text = opop(oRecord, 'content');
116
+ // Add the subject and html fields
117
+ oRecord.subject = '';
118
+ oRecord.html = '';
119
+ }
120
+ // Else, if it's SMS
121
+ else if (value === 'sms') {
122
+ // Store the text in the content field and remove it
123
+ oRecord.content = opop(oRecord, 'text');
124
+ // Remove the subject and html fields
125
+ delete oRecord.subject;
126
+ delete oRecord.html;
127
+ }
128
+ // Else, invalid value
129
+ else {
130
+ throw new Error('invalid `value`');
131
+ }
132
+ // Set the type
133
+ typeSet(value);
134
+ // Set the record
135
+ recordSet(oRecord);
136
+ }
137
+ // Render
138
+ return (React.createElement(Grid, { container: true, spacing: 2, className: "content_create" },
139
+ React.createElement(Grid, { item: true, xs: 12, md: 6 },
140
+ React.createElement(RadioButtons, { border: true, gridContainerProps: { spacing: 2 }, gridItemProps: {
141
+ xs: 12,
142
+ sm: 6
143
+ }, label: "Type", onChange: typeChanged, options: [
144
+ { text: 'E-Mail', value: 'email' },
145
+ { text: 'SMS', value: 'sms' }
146
+ ], value: type, variant: "grid" })),
147
+ React.createElement(Grid, { item: true, xs: 12, md: 6, className: "field" },
148
+ React.createElement(FormControl, { variant: "outlined", error: 'locale' in fieldErrors ? true : false },
149
+ React.createElement(InputLabel, { id: "content_create_locale" }, "Locale"),
150
+ React.createElement(Select, { label: "Locale", labelId: "content_create_locale", native: true, onChange: ev => recordChanged('locale', ev.target.value), value: record.locale }, omap(props.locales, (v, k) => React.createElement("option", { key: k, value: k }, v))),
151
+ fieldErrors.locale &&
152
+ React.createElement(FormHelperText, null, fieldErrors.locale))),
153
+ React.createElement(Grid, { item: true, xs: 12 }, (type === 'email' &&
154
+ React.createElement(Email, { errors: fieldErrors, onChanged: recordChanged, value: record })) || (type === 'sms' &&
155
+ React.createElement(SMS, { errors: fieldErrors, onChanged: recordChanged, value: record }))),
156
+ React.createElement(Grid, { item: true, xs: 12, className: "actions" },
157
+ React.createElement(Button, { color: "info", onClick: () => previewSet(true), variant: "contained" }, "Preview"),
158
+ React.createElement(Button, { color: "primary", onClick: create, variant: "contained" }, "Add Content"),
159
+ preview &&
160
+ React.createElement(Preview, { mobile: props.mobile, onClose: () => previewSet(false), onError: (error) => {
161
+ if (error.code === errors.body.DATA_FIELDS) {
162
+ fieldErrorsSet(errorTree(error.msg));
163
+ }
164
+ else {
165
+ props.onError(error);
166
+ }
167
+ previewSet(false);
168
+ }, value: { ...record, type } }))));
169
+ }
170
+ // Valid props
171
+ Create.propTypes = {
172
+ locales: PropTypes.objectOf(PropTypes.string).isRequired,
173
+ mobile: PropTypes.bool.isRequired,
174
+ onCreated: PropTypes.func.isRequired,
175
+ onError: PropTypes.func,
176
+ template: PropTypes.string.isRequired
177
+ };