@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.
- package/LICENSE +8 -0
- package/README.md +15 -0
- package/package.json +55 -0
- package/src/components/pages/Locales.d.ts +35 -0
- package/src/components/pages/Locales.js +188 -0
- package/src/components/pages/Locales.tsx +254 -0
- package/src/components/pages/Templates/Create.d.ts +36 -0
- package/src/components/pages/Templates/Create.js +98 -0
- package/src/components/pages/Templates/Create.tsx +139 -0
- package/src/components/pages/Templates/Template/Content/Create/Email.d.ts +39 -0
- package/src/components/pages/Templates/Template/Content/Create/Email.js +51 -0
- package/src/components/pages/Templates/Template/Content/Create/Email.tsx +96 -0
- package/src/components/pages/Templates/Template/Content/Create/SMS.d.ts +37 -0
- package/src/components/pages/Templates/Template/Content/Create/SMS.js +42 -0
- package/src/components/pages/Templates/Template/Content/Create/SMS.tsx +68 -0
- package/src/components/pages/Templates/Template/Content/Create/index.d.ts +42 -0
- package/src/components/pages/Templates/Template/Content/Create/index.js +177 -0
- package/src/components/pages/Templates/Template/Content/Create/index.tsx +257 -0
- package/src/components/pages/Templates/Template/Content/Preview/Email.d.ts +37 -0
- package/src/components/pages/Templates/Template/Content/Preview/Email.js +51 -0
- package/src/components/pages/Templates/Template/Content/Preview/Email.tsx +78 -0
- package/src/components/pages/Templates/Template/Content/Preview/SMS.d.ts +32 -0
- package/src/components/pages/Templates/Template/Content/Preview/SMS.js +38 -0
- package/src/components/pages/Templates/Template/Content/Preview/SMS.tsx +59 -0
- package/src/components/pages/Templates/Template/Content/Preview/index.d.ts +42 -0
- package/src/components/pages/Templates/Template/Content/Preview/index.js +63 -0
- package/src/components/pages/Templates/Template/Content/Preview/index.tsx +107 -0
- package/src/components/pages/Templates/Template/Content/Update/Email.d.ts +39 -0
- package/src/components/pages/Templates/Template/Content/Update/Email.js +51 -0
- package/src/components/pages/Templates/Template/Content/Update/Email.tsx +96 -0
- package/src/components/pages/Templates/Template/Content/Update/SMS.d.ts +37 -0
- package/src/components/pages/Templates/Template/Content/Update/SMS.js +42 -0
- package/src/components/pages/Templates/Template/Content/Update/SMS.tsx +68 -0
- package/src/components/pages/Templates/Template/Content/Update/index.d.ts +42 -0
- package/src/components/pages/Templates/Template/Content/Update/index.js +117 -0
- package/src/components/pages/Templates/Template/Content/Update/index.tsx +162 -0
- package/src/components/pages/Templates/Template/Content/View/Email.d.ts +43 -0
- package/src/components/pages/Templates/Template/Content/View/Email.js +57 -0
- package/src/components/pages/Templates/Template/Content/View/Email.tsx +80 -0
- package/src/components/pages/Templates/Template/Content/View/SMS.d.ts +41 -0
- package/src/components/pages/Templates/Template/Content/View/SMS.js +46 -0
- package/src/components/pages/Templates/Template/Content/View/SMS.tsx +64 -0
- package/src/components/pages/Templates/Template/Content/View/index.d.ts +39 -0
- package/src/components/pages/Templates/Template/Content/View/index.js +50 -0
- package/src/components/pages/Templates/Template/Content/View/index.tsx +78 -0
- package/src/components/pages/Templates/Template/Variables.d.ts +34 -0
- package/src/components/pages/Templates/Template/Variables.js +91 -0
- package/src/components/pages/Templates/Template/Variables.tsx +138 -0
- package/src/components/pages/Templates/Template/index.d.ts +90 -0
- package/src/components/pages/Templates/Template/index.js +207 -0
- package/src/components/pages/Templates/Template/index.tsx +337 -0
- package/src/components/pages/Templates/index.d.ts +35 -0
- package/src/components/pages/Templates/index.js +112 -0
- package/src/components/pages/Templates/index.tsx +165 -0
- package/src/index.d.ts +5 -0
- package/src/index.js +5 -0
- package/src/index.ts +8 -0
- package/src/locales.d.ts +72 -0
- package/src/locales.js +160 -0
- 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
|
+
};
|