@visns-studio/visns-components 1.0.0 → 1.0.1-2.1

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.
@@ -0,0 +1,427 @@
1
+ import React, { useState, useEffect } from "react";
2
+ import CustomFetch from "../crm/visns-fetch";
3
+ import Field from "./visns-field";
4
+ import slugify from "react-slugify";
5
+ import moment from "moment";
6
+ import Reveal from "react-reveal/Reveal";
7
+ import parse from "html-react-parser";
8
+ import { confirmAlert } from "react-confirm-alert";
9
+ import { toast } from "react-toastify";
10
+ import { Copy, TrashBin } from "akar-icons";
11
+
12
+ import "react-confirm-alert/src/react-confirm-alert.css";
13
+
14
+ function Form(props) {
15
+ const { dataId, navigate, form, setActiveNav } = props;
16
+ const [data, setData] = useState({});
17
+ const [dataClass, setDataClass] = useState({});
18
+ const [audit, setAudit] = useState({
19
+ createdBy: {},
20
+ created: "",
21
+ updatedBy: {},
22
+ updated: "",
23
+ });
24
+ const [uploadProgress, setUploadProgress] = useState({});
25
+
26
+ const handleChange = (e) => {
27
+ if (e) {
28
+ switch (e.target.name) {
29
+ case "title":
30
+ setData((prevState) => ({
31
+ ...prevState,
32
+ [e.target.name]: e.target.value,
33
+ }));
34
+
35
+ setData((prevState) => ({
36
+ ...prevState,
37
+ slug: slugify(e.target.value),
38
+ }));
39
+ break;
40
+ default:
41
+ setData((prevState) => ({
42
+ ...prevState,
43
+ [e.target.name]: e.target.value,
44
+ }));
45
+ break;
46
+ }
47
+ }
48
+ };
49
+
50
+ const handleChangeSelect = (value, action, id) => {
51
+ if (value && action && id) {
52
+ setData((prevState) => ({
53
+ ...prevState,
54
+ [id]: value,
55
+ }));
56
+ }
57
+ };
58
+
59
+ const handleChangeRicheditor = (value, name) => {
60
+ setData((prevState) => ({
61
+ ...prevState,
62
+ [name]: value,
63
+ }));
64
+ };
65
+
66
+ const handleChangeFile = (e) => {
67
+ if (e) {
68
+ setData((prevState) => ({
69
+ ...prevState,
70
+ [e.target.name]: e.target.files[0],
71
+ }));
72
+
73
+ Vapor.store(e.target.files[0], {
74
+ progress: (progress) => {
75
+ setUploadProgress((prevState) => ({
76
+ ...prevState,
77
+ [e.target.name]: progress * 100,
78
+ }));
79
+ },
80
+ }).then((response) => {
81
+ if (data.hasOwnProperty("files")) {
82
+ let _files = data.files;
83
+ let _new = true;
84
+
85
+ data.files.forEach((a, b) => {
86
+ if (e.target.name === a.field) {
87
+ _files[b] = {
88
+ field: e.target.name,
89
+ uuid: response.uuid,
90
+ key: response.key,
91
+ bucket: response.bucket,
92
+ filename: e.target.files[0].name,
93
+ filesize: e.target.files[0].size,
94
+ extension: response.extension,
95
+ };
96
+
97
+ _new = false;
98
+ }
99
+ });
100
+
101
+ if (_new === true) {
102
+ setData((prevState) => ({
103
+ ...prevState,
104
+ files: [
105
+ ...prevState.files,
106
+ {
107
+ field: e.target.name,
108
+ uuid: response.uuid,
109
+ key: response.key,
110
+ bucket: response.bucket,
111
+ filename: e.target.files[0].name,
112
+ filesize: e.target.files[0].size,
113
+ extension: response.extension,
114
+ },
115
+ ],
116
+ }));
117
+ } else {
118
+ setData((prevState) => ({
119
+ ...prevState,
120
+ files: _files,
121
+ }));
122
+ }
123
+ } else {
124
+ setData((prevState) => ({
125
+ ...prevState,
126
+ files: [
127
+ {
128
+ field: e.target.name,
129
+ uuid: response.uuid,
130
+ key: response.key,
131
+ bucket: response.bucket,
132
+ filename: e.target.files[0].name,
133
+ filesize: e.target.files[0].size,
134
+ extension: response.extension,
135
+ },
136
+ ],
137
+ }));
138
+ }
139
+ });
140
+ }
141
+ };
142
+
143
+ const handleSubmit = (e) => {
144
+ if (e) {
145
+ e.preventDefault();
146
+
147
+ let error = "";
148
+ let url = "";
149
+ let method = "";
150
+ let message = "";
151
+
152
+ if (data.title === "") {
153
+ error += "Please enter a title.<br />";
154
+ }
155
+
156
+ if (data.summary === "") {
157
+ error += "Please enter a summary.<br />";
158
+ }
159
+
160
+ if (error === "") {
161
+ if (dataId === "create") {
162
+ url = form.url;
163
+ method = "POST";
164
+ message = "You have successfully created a new entry.";
165
+ } else {
166
+ url = form.url + "/" + dataId;
167
+ method = "PUT";
168
+ message = "You have successfully updated this entry.";
169
+ }
170
+
171
+ CustomFetch(url, method, data, function (result) {
172
+ if (result.error === "") {
173
+ let _uploadProgress = uploadProgress;
174
+
175
+ Object.keys(_uploadProgress).forEach((a, b) => {
176
+ setUploadProgress((prevState) => ({
177
+ ...prevState,
178
+ [b]: 0,
179
+ }));
180
+ });
181
+
182
+ toast.success(message);
183
+
184
+ if (dataId === "create") {
185
+ navigate(
186
+ form.url.replace("/ajax", "") +
187
+ "/" +
188
+ result.data.id,
189
+ {
190
+ state: {
191
+ form: form,
192
+ },
193
+ }
194
+ );
195
+ }
196
+ } else {
197
+ toast.error(result.error);
198
+ }
199
+ });
200
+ } else {
201
+ toast.error(<div>{parse(error)}</div>);
202
+ }
203
+ }
204
+ };
205
+
206
+ const handleDelete = (e) => {
207
+ if (e) {
208
+ confirmAlert({
209
+ title: "Delete this entry",
210
+ message: "Are you sure you want to delete it?",
211
+ buttons: [
212
+ {
213
+ label: "Yes",
214
+ onClick: () =>
215
+ CustomFetch(
216
+ `${form.url}/${dataId}`,
217
+ "DELETE",
218
+ {},
219
+ function (result) {
220
+ if (result.error === "") {
221
+ navigate(form.url.replace("/ajax", ""));
222
+ toast.success(
223
+ "You have successfully deleted this entry."
224
+ );
225
+ } else {
226
+ toast.error(result.error);
227
+ }
228
+ }
229
+ ),
230
+ },
231
+ {
232
+ label: "No",
233
+ onClick: () => close(),
234
+ },
235
+ ],
236
+ });
237
+ }
238
+ };
239
+
240
+ const fetchData = () => {
241
+ form.fields.forEach((a) => {
242
+ setData((prevState) => ({
243
+ ...prevState,
244
+ [a.id]: "",
245
+ }));
246
+ });
247
+
248
+ if (dataId !== "create") {
249
+ CustomFetch(
250
+ `${form.url}/${dataId}`,
251
+ "GET",
252
+ {},
253
+ function (result) {
254
+ let now = moment();
255
+ let created = moment.duration(
256
+ now.diff(result.data.created_at)
257
+ );
258
+ let updated = moment.duration(
259
+ now.diff(result.data.updated_at)
260
+ );
261
+
262
+ setData(result.data);
263
+ setAudit((prevState) => ({
264
+ ...prevState,
265
+ createdBy: result.audit_first,
266
+ created:
267
+ created.hours() > 24
268
+ ? created.days() +
269
+ " Days " +
270
+ created.hours() +
271
+ " Hour(s) " +
272
+ created.minutes() +
273
+ " Minutes"
274
+ : created.hours() +
275
+ " Hour(s) " +
276
+ created.minutes() +
277
+ " Minutes",
278
+ updatedBy: result.audit_latest,
279
+ updated:
280
+ updated.hours() > 24
281
+ ? updated.days() +
282
+ " Days " +
283
+ updated.hours() +
284
+ " Hour(s) " +
285
+ updated.minutes() +
286
+ " Minutes"
287
+ : updated.hours() +
288
+ " Hour(s) " +
289
+ updated.minutes() +
290
+ " Minutes",
291
+ }));
292
+ },
293
+ function (error) {
294
+ navigate("/insights");
295
+
296
+ toast.error(String(error));
297
+ }
298
+ );
299
+ }
300
+ };
301
+
302
+ useEffect(() => {
303
+ form.fields.forEach((a) => {
304
+ if (a.type === "image") {
305
+ setUploadProgress((prevState) => ({
306
+ ...prevState,
307
+ [a.id]: 0,
308
+ }));
309
+ }
310
+
311
+ setData((prevState) => ({
312
+ ...prevState,
313
+ [a.id]: "",
314
+ }));
315
+
316
+ setDataClass((prevState) => ({
317
+ ...prevState,
318
+ [a.id]: "",
319
+ }));
320
+ });
321
+
322
+ fetchData();
323
+ setActiveNav();
324
+ }, [dataId]);
325
+
326
+ return (
327
+ <Reveal effect="fadeInUp">
328
+ <div className="grid">
329
+ <div className="grid__row">
330
+ <div className="grid__full cmstitle">
331
+ <h1>{data.title}</h1>
332
+ <div className="cmstitle__actions">
333
+ <button
334
+ className="btn actionbtn"
335
+ onClick={handleSubmit}
336
+ >
337
+ <Copy size={18} strokeWidth={2} />{" "}
338
+ {dataId !== "create" ? "Save" : "Create"}
339
+ </button>
340
+ </div>
341
+ </div>
342
+ </div>
343
+ </div>
344
+ <div className="dynamic">
345
+ <div className="dynamic__left">
346
+ <div className="formcontainer">
347
+ <div className="dynamicform">
348
+ {form.fields.map((a, b) => (
349
+ <Field
350
+ settings={a}
351
+ key={
352
+ b +
353
+ "-fields-" +
354
+ (a.hasOwnProperty("key")
355
+ ? a.id + "-" + a.key
356
+ : a.id)
357
+ }
358
+ inputValue={
359
+ a.hasOwnProperty("key")
360
+ ? data[a.key]
361
+ : Array.isArray(data[a.id]) &&
362
+ a.type === "image"
363
+ ? data[a.id].length > 0
364
+ ? data[a.id][0]
365
+ : ""
366
+ : data[a.id]
367
+ }
368
+ inputClass={dataClass}
369
+ onChange={handleChange}
370
+ onChangeFile={handleChangeFile}
371
+ onChangeRicheditor={handleChangeRicheditor}
372
+ onChangeSelect={handleChangeSelect}
373
+ setFormData={setData}
374
+ uploadProgress={uploadProgress}
375
+ />
376
+ ))}
377
+ </div>
378
+ </div>
379
+ </div>
380
+ <div className="dynamic__right">
381
+ <h1>Information</h1>
382
+ <ul>
383
+ <li>
384
+ Created: <span>{audit.created} Ago</span>
385
+ </li>
386
+ <li>
387
+ By:{" "}
388
+ <span>
389
+ {audit &&
390
+ audit.createdBy &&
391
+ audit.createdBy.user
392
+ ? audit.createdBy.user.name
393
+ : null}
394
+ </span>
395
+ </li>
396
+ <li>
397
+ Last Update: <span>{audit.updated} Ago</span>
398
+ </li>
399
+ <li>
400
+ by:{" "}
401
+ <span>
402
+ {audit &&
403
+ audit.updatedBy &&
404
+ audit.updatedBy.user
405
+ ? audit.updatedBy.user.name
406
+ : null}
407
+ </span>
408
+ </li>
409
+ {dataId !== "create" ? (
410
+ <li>
411
+ <button
412
+ className="btn actionbtn deletebtn"
413
+ onClick={handleDelete}
414
+ >
415
+ <TrashBin size={14} strokeWidth={2} />{" "}
416
+ Delete Entry
417
+ </button>
418
+ </li>
419
+ ) : null}
420
+ </ul>
421
+ </div>
422
+ </div>
423
+ </Reveal>
424
+ );
425
+ }
426
+
427
+ export default Form;
@@ -3,7 +3,7 @@ import DatePicker from "react-datepicker";
3
3
  import _ from "lodash";
4
4
  import ReactQuill from "react-quill";
5
5
  import Toggle from "react-toggle";
6
- import NumberFormat from "react-number-format";
6
+ import { NumericFormat, PatternFormat } from "react-number-format";
7
7
 
8
8
  import CustomFetch from "./visns-fetch";
9
9
  import Select from "./visns-select";
@@ -304,7 +304,7 @@ function Field(props) {
304
304
  break;
305
305
  case "phone":
306
306
  htmlContainer = (
307
- <NumberFormat
307
+ <PatternFormat
308
308
  data-name={settings.id}
309
309
  className={inputClass[settings.id]}
310
310
  onValueChange={(values) => {
@@ -314,6 +314,8 @@ function Field(props) {
314
314
  );
315
315
  }}
316
316
  format="## #### ####"
317
+ allowEmptyFormatting
318
+ mask="_"
317
319
  value={
318
320
  inputValue && inputValue !== "null"
319
321
  ? inputValue
@@ -324,7 +326,7 @@ function Field(props) {
324
326
  break;
325
327
  case "mobile":
326
328
  htmlContainer = (
327
- <NumberFormat
329
+ <PatternFormat
328
330
  className={inputClass[settings.id]}
329
331
  onValueChange={(values) => {
330
332
  onChangeNumberFormat(
@@ -333,6 +335,8 @@ function Field(props) {
333
335
  );
334
336
  }}
335
337
  format="#### ### ###"
338
+ allowEmptyFormatting
339
+ mask="_"
336
340
  value={
337
341
  inputValue && inputValue !== "null"
338
342
  ? inputValue
@@ -343,7 +347,7 @@ function Field(props) {
343
347
  break;
344
348
  case "currency":
345
349
  htmlContainer = (
346
- <NumberFormat
350
+ <NumericFormat
347
351
  data-name={settings.id}
348
352
  className={inputClass[settings.id]}
349
353
  onValueChange={(values) => {
@@ -362,6 +366,60 @@ function Field(props) {
362
366
  />
363
367
  );
364
368
  break;
369
+ case "number":
370
+ htmlContainer = (
371
+ <NumericFormat
372
+ data-name={settings.id}
373
+ className={inputClass[settings.id]}
374
+ onValueChange={(values) => {
375
+ onChangeNumberFormat(
376
+ values,
377
+ settings.id
378
+ );
379
+ }}
380
+ thousandSeparator={
381
+ settings.hasOwnProperty(
382
+ "thousandSeperator"
383
+ )
384
+ ? settings.thousandSeperator
385
+ : true
386
+ }
387
+ value={
388
+ inputValue && inputValue !== "null"
389
+ ? inputValue
390
+ : ""
391
+ }
392
+ />
393
+ );
394
+ break;
395
+ case "decimal":
396
+ htmlContainer = (
397
+ <NumericFormat
398
+ data-name={settings.id}
399
+ className={inputClass[settings.id]}
400
+ onValueChange={(values) => {
401
+ onChangeNumberFormat(
402
+ values,
403
+ settings.id
404
+ );
405
+ }}
406
+ thousandSeparator={
407
+ settings.hasOwnProperty(
408
+ "thousandSeperator"
409
+ )
410
+ ? settings.thousandSeperator
411
+ : true
412
+ }
413
+ decimalSeparator="."
414
+ decimalScale={2}
415
+ value={
416
+ inputValue && inputValue !== "null"
417
+ ? inputValue
418
+ : ""
419
+ }
420
+ />
421
+ );
422
+ break;
365
423
  case "textarea":
366
424
  htmlContainer = (
367
425
  <textarea
@@ -0,0 +1,130 @@
1
+ import React from "react";
2
+
3
+ function TableFilter(props) {
4
+ const { filters, setFilters, setSettings } = props;
5
+
6
+ const filterTable = (e) => {
7
+ const { id, value, url } = e.target.dataset;
8
+
9
+ console.info("a", url);
10
+
11
+ if (props.hasOwnProperty("setSettings") === true) {
12
+ console.info("b");
13
+ if (url && url !== "") {
14
+ console.info("c");
15
+ window.open(url);
16
+ } else {
17
+ console.info("d");
18
+ setSettings((prevState) => {
19
+ if (prevState.ajaxSetting) {
20
+ let _where = [];
21
+
22
+ prevState.ajaxSetting.where.forEach((a) => {
23
+ if (a.id === id) {
24
+ let _push = true;
25
+
26
+ _where.forEach((b) => {
27
+ if (b.id === id) {
28
+ _push = false;
29
+ }
30
+ });
31
+
32
+ if (_push === true) {
33
+ _where.push({
34
+ id: id,
35
+ value: value,
36
+ });
37
+ }
38
+ } else {
39
+ _where.push(a);
40
+ }
41
+ });
42
+
43
+ let _push = true;
44
+
45
+ _where.forEach((a) => {
46
+ if (a.id === id) {
47
+ _push = false;
48
+ }
49
+ });
50
+
51
+ if (_push === true) {
52
+ _where.push({
53
+ id: id,
54
+ value: value,
55
+ });
56
+ }
57
+
58
+ return {
59
+ ...prevState,
60
+ ajaxSetting: {
61
+ ...prevState.ajaxSetting,
62
+ where: _where,
63
+ },
64
+ };
65
+ } else {
66
+ let w = prevState.where;
67
+
68
+ prevState.where.forEach((a, b) => {
69
+ if (id === a.id) {
70
+ w[b].value = value;
71
+ }
72
+ });
73
+
74
+ return { ...prevState, where: w };
75
+ }
76
+ });
77
+ }
78
+ }
79
+
80
+ let tempFilters = filters;
81
+
82
+ filters.map((item, index) => {
83
+ if (
84
+ e.target.dataset.hasOwnProperty("value") &&
85
+ parseInt(value) >= 0
86
+ ) {
87
+ if (parseInt(value) === parseInt(item.value)) {
88
+ tempFilters[index].class = "subactive";
89
+ tempFilters[index].show = true;
90
+ } else {
91
+ tempFilters[index].class = "";
92
+ tempFilters[index].show = false;
93
+ }
94
+ } else {
95
+ if (id === item.id) {
96
+ tempFilters[index].class = "subactive";
97
+ tempFilters[index].show = true;
98
+ } else {
99
+ tempFilters[index].class = "";
100
+ tempFilters[index].show = false;
101
+ }
102
+ }
103
+ });
104
+
105
+ setFilters(tempFilters);
106
+ setFilters((prevState) => [...prevState]);
107
+ };
108
+
109
+ return (
110
+ <ul>
111
+ {filters.map((item, key) => (
112
+ <li key={"table-filter-" + key}>
113
+ <a
114
+ data-id={item.id}
115
+ data-value={
116
+ item.hasOwnProperty("value") ? item.value : ""
117
+ }
118
+ data-url={item.url || ""}
119
+ onClick={filterTable}
120
+ className={item.class}
121
+ >
122
+ {item.label}
123
+ </a>
124
+ </li>
125
+ ))}
126
+ </ul>
127
+ );
128
+ }
129
+
130
+ export default TableFilter;
package/index.js CHANGED
@@ -1,12 +1,42 @@
1
- import React from "react";
2
- import ReactDOM from "react-dom";
3
- import DataGrid from "./components/visns-data-grid";
4
- import Fetch from "./components/visns-fetch";
1
+ /** CMS Components */
2
+ import CmsForm from "./components/cms/visns-form";
3
+ import DataGrid from "./components/cms/visns-data-grid";
4
+ import DropZone from "./components/cms/visns-dropzone";
5
+ import SortableList from "./components/cms/sorting/list";
5
6
 
6
- ReactDOM.render(
7
- <React.Fragment>
8
- <DataGrid />
9
- <Fetch />
10
- </React.Fragment>,
11
- document.getElementById("root")
12
- );
7
+ /** CRM Components */
8
+ import AsyncSelect from "./components/crm/visns-async-select";
9
+ import Autocomplete from "./components/crm/visns-autocomplete";
10
+ import Call from "./components/crm/visns-call";
11
+ import CustomFetch from "./components/crm/visns-fetch";
12
+ import Download from "./components/crm/visns-download";
13
+ import Field from "./components/crm/visns-field";
14
+ import Form from "./components/crm/visns-form";
15
+ import Loader from "./components/crm/visns-loader";
16
+ import MultiSelect from "./components/crm/visns-multi-select";
17
+ import Notification from "./components/crm/visns-notification";
18
+ import SelectList from "./components/crm/visns-select-list";
19
+ import Select from "./components/crm/visns-select";
20
+ import Table from "./components/crm/visns-data-grid";
21
+ import TableFilter from "./components/crm/visns-table-filter";
22
+
23
+ export {
24
+ AsyncSelect,
25
+ Autocomplete,
26
+ Call,
27
+ CmsForm,
28
+ CustomFetch,
29
+ DataGrid,
30
+ Download,
31
+ DropZone,
32
+ Field,
33
+ Form,
34
+ Loader,
35
+ MultiSelect,
36
+ Notification,
37
+ SelectList,
38
+ Select,
39
+ SortableList,
40
+ Table,
41
+ TableFilter,
42
+ };