@visns-studio/visns-components 5.0.1-8.1 → 5.0.2

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 (27) hide show
  1. package/package.json +1 -3
  2. package/src/components/crm/AsyncSelect.jsx +15 -121
  3. package/src/components/crm/DataGrid.jsx +5 -25
  4. package/src/components/crm/Field.jsx +148 -174
  5. package/src/components/crm/Form.jsx +28 -41
  6. package/src/components/crm/MultiSelect.jsx +29 -96
  7. package/src/components/crm/Navigation.jsx +40 -2
  8. package/src/components/crm/QrCode.jsx +8 -12
  9. package/src/components/crm/auth/Login.jsx +1 -9
  10. package/src/components/crm/auth/styles/Login.module.scss +3 -4
  11. package/src/components/crm/auth/styles/Profile.module.scss +14 -56
  12. package/src/components/crm/generic/GenericAuth.jsx +2 -5
  13. package/src/components/crm/generic/GenericDetail.jsx +18 -509
  14. package/src/components/crm/generic/styles/AuditLog.module.scss +0 -4
  15. package/src/components/crm/generic/styles/GenericDetail.module.scss +121 -261
  16. package/src/components/crm/generic/styles/GenericDynamic.module.scss +67 -35
  17. package/src/components/crm/generic/styles/GenericFormBuilder.module.scss +43 -4
  18. package/src/components/crm/generic/styles/GenericIndex.module.scss +1 -1
  19. package/src/components/crm/styles/Autocomplete.module.scss +20 -12
  20. package/src/components/crm/styles/DataGrid.module.scss +3 -2
  21. package/src/components/crm/styles/Field.module.scss +13 -19
  22. package/src/components/crm/styles/Form.module.scss +5 -5
  23. package/src/components/crm/styles/Navigation.module.scss +61 -11
  24. package/src/components/crm/styles/QrCode.module.scss +0 -4
  25. package/src/components/styles/global.css +5 -95
  26. package/src/components/crm/generic/GenericEditableTable.jsx +0 -407
  27. package/src/components/crm/generic/styles/GenericEditableTable.module.scss +0 -178
@@ -82,7 +82,6 @@ function Field({
82
82
  useEffect(() => {
83
83
  const fetchOptions = () => {
84
84
  let filter = {};
85
-
86
85
  if (settings.where?.length > 0) {
87
86
  filter = {
88
87
  where: settings.where,
@@ -208,12 +207,6 @@ function Field({
208
207
  filter.orderBy = s.orderBy;
209
208
  }
210
209
 
211
- if (a.where) {
212
- forEach(a.where, (w) => {
213
- filter.where.push(w);
214
- });
215
- }
216
-
217
210
  CustomFetch(s.child.url, 'POST', filter, function (result) {
218
211
  childDropdownCallback({
219
212
  id: s.child.id,
@@ -260,70 +253,65 @@ function Field({
260
253
  }, [settings.options, settings, counter]);
261
254
 
262
255
  const renderLabel = () => {
263
- if (settings.label && settings.label !== '') {
264
- if (
265
- [
266
- 'address',
267
- 'async-dropdown-ajax',
268
- 'checkbox',
269
- 'colour',
270
- 'copytoclipboard',
271
- 'date',
272
- 'datetime',
273
- 'dropdown',
274
- 'dropdown-ajax',
275
- 'dynamicdata',
276
- 'file',
277
- 'gallery',
278
- 'image',
279
- 'multi-dropdown',
280
- 'multi-dropdown-ajax',
281
- 'plaindate',
282
- 'plaindatetime',
283
- 'plainrelation',
284
- 'plainrelationarray',
285
- 'radio',
286
- 'radio-ajax',
287
- 'signature',
288
- 'table_radio',
289
- 'table_text',
290
- 'time',
291
- ].includes(settings.type)
292
- ) {
256
+ if (
257
+ [
258
+ 'address',
259
+ 'async-dropdown-ajax',
260
+ 'checkbox',
261
+ 'colour',
262
+ 'copytoclipboard',
263
+ 'date',
264
+ 'datetime',
265
+ 'dropdown',
266
+ 'dropdown-ajax',
267
+ 'dynamicdata',
268
+ 'file',
269
+ 'gallery',
270
+ 'image',
271
+ 'multi-dropdown',
272
+ 'multi-dropdown-ajax',
273
+ 'plaindate',
274
+ 'plaindatetime',
275
+ 'plainrelation',
276
+ 'plainrelationarray',
277
+ 'radio',
278
+ 'radio-ajax',
279
+ 'richeditor',
280
+ 'signature',
281
+ 'table_radio',
282
+ 'table_text',
283
+ 'time',
284
+ ].includes(settings.type)
285
+ ) {
286
+ return (
287
+ <span className={`${styles.fi__span} ${styles.prefocus}`}>
288
+ {settings.label} {settings.required ? '*' : ''}
289
+ </span>
290
+ );
291
+ } else if (['plaintext'].includes(settings.type)) {
292
+ if (settings.description) {
293
293
  return (
294
- <span className={`${styles.fi__span} ${styles.prefocus}`}>
295
- {settings.label} {settings.required ? '*' : ''}
294
+ <span>
295
+ {settings.description
296
+ ? parse(settings.description)
297
+ : ''}
296
298
  </span>
297
299
  );
298
- } else if (['plaintext'].includes(settings.type)) {
299
- if (settings.description) {
300
- return (
301
- <span>
302
- {settings.description
303
- ? parse(settings.description)
304
- : ''}
305
- </span>
306
- );
307
- } else {
308
- return (
309
- <span
310
- className={`${styles.fi__span} ${styles.prefocus}`}
311
- >
312
- {settings.label} {settings.required ? '*' : ''}
313
- </span>
314
- );
315
- }
316
- } else if (['plaintextheading'].includes(settings.type)) {
317
- return <h2>{settings.label ? settings.label : ''}</h2>;
318
- } else if (['section'].includes(settings.type)) {
300
+ } else {
319
301
  return (
320
- <div className={styles.gridtxt__header}>
321
- <span>{settings.label}</span>
322
- </div>
302
+ <span className={`${styles.fi__span} ${styles.prefocus}`}>
303
+ {settings.label} {settings.required ? '*' : ''}
304
+ </span>
323
305
  );
324
- } else if (['richeditor', 'textarea'].includes(settings.type)) {
325
- return settings.label;
326
306
  }
307
+ } else if (['plaintextheading'].includes(settings.type)) {
308
+ return <h2>{settings.label ? settings.label : ''}</h2>;
309
+ } else if (['section'].includes(settings.type)) {
310
+ return (
311
+ <div className={styles.gridtxt__header}>
312
+ <span>{settings.label}</span>
313
+ </div>
314
+ );
327
315
  }
328
316
  };
329
317
 
@@ -380,26 +368,23 @@ function Field({
380
368
  );
381
369
  case 'async-dropdown-ajax':
382
370
  return (
383
- <div className={styles.dropdownContainer}>
384
- <VisnsAsyncSelect
385
- settings={settings}
386
- className={inputClass[settings.id]}
387
- multi={
388
- settings.hasOwnProperty('multi')
389
- ? settings.multi
390
- : false
391
- }
392
- onChange={onChangeSelect}
393
- inputValue={
394
- inputValue === null || inputValue === undefined
395
- ? ''
396
- : inputValue
397
- }
398
- options={options}
399
- dataOptions={dataOptions}
400
- isCreatable={settings.isCreatable || false}
401
- />
402
- </div>
371
+ <VisnsAsyncSelect
372
+ settings={settings}
373
+ className={inputClass[settings.id]}
374
+ multi={
375
+ settings.hasOwnProperty('multi')
376
+ ? settings.multi
377
+ : false
378
+ }
379
+ onChange={onChangeSelect}
380
+ inputValue={
381
+ inputValue === null || inputValue === undefined
382
+ ? ''
383
+ : inputValue
384
+ }
385
+ options={options}
386
+ dataOptions={dataOptions}
387
+ />
403
388
  );
404
389
  case 'checkbox':
405
390
  return (
@@ -688,6 +673,7 @@ function Field({
688
673
  className={inputClass[settings.id]}
689
674
  onChange={onChange}
690
675
  />
676
+ {console.info(inputValue)}
691
677
  {inputValue && inputValue.length > 0 && (
692
678
  <ul className="file-list">
693
679
  {inputValue.map((file, index) => (
@@ -821,13 +807,6 @@ function Field({
821
807
 
822
808
  return htmlContainer;
823
809
  case 'html5_date':
824
- // Convert inputValue to 'YYYY-MM-DD' if necessary
825
- const formattedDate =
826
- inputValue &&
827
- moment(inputValue, moment.ISO_8601, true).isValid()
828
- ? moment(inputValue).format('YYYY-MM-DD')
829
- : inputValue; // Use as-is if it's already in the correct format or invalid
830
-
831
810
  return (
832
811
  <input
833
812
  type="date"
@@ -835,7 +814,11 @@ function Field({
835
814
  className={inputClass[settings.id]}
836
815
  placeholder=" "
837
816
  onChange={onChange}
838
- value={formattedDate || ''}
817
+ value={
818
+ inputValue && inputValue !== 'null'
819
+ ? inputValue
820
+ : ''
821
+ }
839
822
  autoComplete="off"
840
823
  />
841
824
  );
@@ -987,7 +970,6 @@ function Field({
987
970
  ? settings.options
988
971
  : options
989
972
  }
990
- isCreatable={settings.isCreatable || false}
991
973
  dataOptions={dataOptions}
992
974
  style={style}
993
975
  />
@@ -1190,6 +1172,77 @@ function Field({
1190
1172
  ))}
1191
1173
  </div>
1192
1174
  ) : null;
1175
+ case 'richeditor':
1176
+ return (
1177
+ <Editor
1178
+ tinymceScriptSrc="https://d16lktya8ojp5z.cloudfront.net/generic/packages/tinymce_v701/tinymce.min.js"
1179
+ licenseKey="gpl"
1180
+ onEditorChange={(value, e) => {
1181
+ onChangeRicheditor(e, value, settings.id);
1182
+ }}
1183
+ onInit={(evt, editor) => (editorRef.current = editor)}
1184
+ value={inputValue || ''}
1185
+ init={{
1186
+ branding: false,
1187
+ height: settings.height ? settings.height : 500,
1188
+ menubar: false,
1189
+ plugins: [
1190
+ 'advlist',
1191
+ 'autolink',
1192
+ 'lists',
1193
+ 'link',
1194
+ 'image',
1195
+ 'charmap',
1196
+ 'preview',
1197
+ 'anchor',
1198
+ 'searchreplace',
1199
+ 'visualblocks',
1200
+ 'code',
1201
+ 'fullscreen',
1202
+ 'insertdatetime',
1203
+ 'media',
1204
+ 'table',
1205
+ 'code',
1206
+ ],
1207
+ toolbar:
1208
+ 'insertTextDropdown | undo redo | blocks | ' +
1209
+ 'bold italic forecolor | alignleft aligncenter ' +
1210
+ 'alignright alignjustify | bullist numlist outdent indent | ' +
1211
+ 'removeformat | table',
1212
+ content_style:
1213
+ 'body { font-family:Helvetica,Arial,sans-serif; font-size:14px }',
1214
+ setup: (editor) => {
1215
+ // Check if insertText exists and is an array of objects
1216
+ if (
1217
+ settings.insertText &&
1218
+ Array.isArray(settings.insertText) &&
1219
+ settings.insertText.length > 0
1220
+ ) {
1221
+ editor.ui.registry.addMenuButton(
1222
+ 'insertTextDropdown',
1223
+ {
1224
+ text: 'Insert Text',
1225
+ fetch: (callback) => {
1226
+ const items =
1227
+ settings.insertText.map(
1228
+ (textObj) => ({
1229
+ type: 'menuitem',
1230
+ text: textObj.text,
1231
+ onAction: () =>
1232
+ editor.insertContent(
1233
+ textObj.content
1234
+ ),
1235
+ })
1236
+ );
1237
+ callback(items);
1238
+ },
1239
+ }
1240
+ );
1241
+ }
1242
+ },
1243
+ }}
1244
+ />
1245
+ );
1193
1246
  case 'signature':
1194
1247
  return (
1195
1248
  <>
@@ -1671,7 +1724,6 @@ function Field({
1671
1724
  'signature',
1672
1725
  'table_radio',
1673
1726
  'table_text',
1674
- 'textarea',
1675
1727
  'time',
1676
1728
  'toggle',
1677
1729
  ].includes(settings.type)
@@ -1715,78 +1767,6 @@ function Field({
1715
1767
  shouldCloseOnSelect={true}
1716
1768
  />
1717
1769
  );
1718
- case 'richeditor':
1719
- return (
1720
- <Editor
1721
- tinymceScriptSrc="https://d16lktya8ojp5z.cloudfront.net/generic/packages/tinymce_v701/tinymce.min.js"
1722
- licenseKey="gpl"
1723
- onEditorChange={(value, e) => {
1724
- onChangeRicheditor(e, value, settings.id);
1725
- }}
1726
- onInit={(evt, editor) => (editorRef.current = editor)}
1727
- value={inputValue || ''}
1728
- init={{
1729
- branding: false,
1730
- height: settings.height ? settings.height : 500,
1731
- menubar: false,
1732
- plugins: [
1733
- 'advlist',
1734
- 'autolink',
1735
- 'lists',
1736
- 'link',
1737
- 'image',
1738
- 'charmap',
1739
- 'preview',
1740
- 'anchor',
1741
- 'searchreplace',
1742
- 'visualblocks',
1743
- 'code',
1744
- 'fullscreen',
1745
- 'insertdatetime',
1746
- 'media',
1747
- 'table',
1748
- 'code',
1749
- 'hr',
1750
- ],
1751
- toolbar:
1752
- 'insertTextDropdown | undo redo | blocks | ' +
1753
- 'bold italic forecolor | alignleft aligncenter ' +
1754
- 'alignright alignjustify | bullist numlist outdent indent | ' +
1755
- 'hr | removeformat | table | code',
1756
- content_style:
1757
- 'body { font-family:Helvetica,Arial,sans-serif; font-size:14px }',
1758
- setup: (editor) => {
1759
- // Check if insertText exists and is an array of objects
1760
- if (
1761
- settings.insertText &&
1762
- Array.isArray(settings.insertText) &&
1763
- settings.insertText.length > 0
1764
- ) {
1765
- editor.ui.registry.addMenuButton(
1766
- 'insertTextDropdown',
1767
- {
1768
- text: 'Insert Text',
1769
- fetch: (callback) => {
1770
- const items =
1771
- settings.insertText.map(
1772
- (textObj) => ({
1773
- type: 'menuitem',
1774
- text: textObj.text,
1775
- onAction: () =>
1776
- editor.insertContent(
1777
- textObj.content
1778
- ),
1779
- })
1780
- );
1781
- callback(items);
1782
- },
1783
- }
1784
- );
1785
- }
1786
- },
1787
- }}
1788
- />
1789
- );
1790
1770
  case 'time':
1791
1771
  return (
1792
1772
  <DatePicker
@@ -1888,13 +1868,7 @@ function Field({
1888
1868
 
1889
1869
  return (
1890
1870
  <div className={formItemClass} style={formItemStyle}>
1891
- <label
1892
- className={
1893
- ['richeditor', 'textarea'].includes(settings.type)
1894
- ? ''
1895
- : styles.fi__label
1896
- }
1897
- >
1871
+ <label className={styles.fi__label}>
1898
1872
  {renderLabel()}
1899
1873
  {renderInput()}
1900
1874
  {renderFieldLabel()}
@@ -215,9 +215,9 @@ function Form({
215
215
  const handleSelectOption = () => {
216
216
  updateFormData({ [id]: inputValue });
217
217
 
218
- // Update any matching form data properties except for the second item
219
- Object.keys(inputValue).forEach((key, index) => {
220
- if (index !== 1 && formData.hasOwnProperty(key)) {
218
+ // Update any matching form data properties
219
+ Object.keys(inputValue).forEach((key) => {
220
+ if (formData.hasOwnProperty(key)) {
221
221
  updateFormData({ [key]: inputValue[key] });
222
222
  }
223
223
  });
@@ -287,7 +287,6 @@ function Form({
287
287
  // Switch cases to handle different actions
288
288
  switch (action.action) {
289
289
  case 'select-option':
290
- case 'create-option': // New case to handle create-option
291
290
  handleSelectOption();
292
291
  break;
293
292
  case 'clear':
@@ -585,39 +584,41 @@ function Form({
585
584
 
586
585
  if (['create', 'update'].includes(formType)) {
587
586
  fields.forEach((item) => {
588
- // Skip createOnly fields if formType is 'update'
589
587
  if (formType === 'update' && item.createOnly) {
590
588
  return;
591
589
  }
592
590
 
593
- // Check if the item is required
594
591
  if (item.required) {
595
- // Check if formData[item.id] is null, undefined, or an empty string
596
- if (!formData[item.id]) {
597
- // Check for required_check dependency
592
+ if (
593
+ formData[item.id] === null ||
594
+ formData[item.id] === ''
595
+ ) {
598
596
  if (
597
+ item.hasOwnProperty('required_check') &&
599
598
  item.required_check &&
600
599
  !formData[item.required_check]
601
600
  ) {
602
601
  validation += `${item.label} is a required field.<br/>`;
603
602
  _inputClass[item.id] = styles.inputError;
604
603
  } else {
604
+ console.info('b', formData, item.id);
605
605
  validation += `${item.label} is a required field.<br/>`;
606
606
  _inputClass[item.id] = styles.inputError;
607
607
  }
608
608
  } else {
609
- _inputClass[item.id] = ''; // Clear error class if valid
609
+ _inputClass[item.id] = '';
610
610
  }
611
611
  } else if (
612
+ item.hasOwnProperty('required_rely') &&
612
613
  item.required_rely &&
613
614
  formData[item.required_rely] &&
614
- !formData[item.id]
615
+ (formData[item.id] === null ||
616
+ formData[item.id] === '')
615
617
  ) {
616
- // Check if the dependent required field is empty when it should be filled
617
618
  validation += `${item.label} is a required field.<br/>`;
618
619
  _inputClass[item.id] = styles.inputError;
619
620
  } else {
620
- _inputClass[item.id] = ''; // Clear error class if not required
621
+ _inputClass[item.id] = '';
621
622
  }
622
623
  });
623
624
 
@@ -670,14 +671,7 @@ function Form({
670
671
 
671
672
  if (!_.isEmpty(formData)) {
672
673
  Object.keys(formData).forEach((item) => {
673
- const value = formData[item];
674
-
675
- // Check if it's a single File or an array of File objects
676
- if (
677
- value instanceof File ||
678
- (Array.isArray(value) &&
679
- value.every((file) => file instanceof File))
680
- ) {
674
+ if (formData[item] instanceof File) {
681
675
  fileUpload = true;
682
676
  fileKey = item;
683
677
 
@@ -871,9 +865,7 @@ function Form({
871
865
  _formData[id] =
872
866
  newValue instanceof Date
873
867
  ? newValue
874
- : newValue !== undefined
875
- ? moment(newValue).toDate()
876
- : '';
868
+ : moment(newValue).toDate();
877
869
  } else {
878
870
  _formData[id] = newValue;
879
871
  }
@@ -890,25 +882,23 @@ function Form({
890
882
  method,
891
883
  payload = {};
892
884
 
893
- if (ajaxSetting?.where) {
894
- const getDataId = () => {
895
- for (const item of ajaxSetting.where) {
896
- if (
897
- item.hasOwnProperty('urlParam') &&
898
- item.urlParam === 'dataId'
899
- ) {
900
- return item.value;
901
- }
885
+ const getDataId = () => {
886
+ for (const item of ajaxSetting.where) {
887
+ if (
888
+ item.hasOwnProperty('urlParam') &&
889
+ item.urlParam === 'dataId'
890
+ ) {
891
+ return item.value;
902
892
  }
903
- return 0;
904
- };
905
- }
893
+ }
894
+ return 0;
895
+ };
906
896
 
907
897
  if (
908
898
  formSettings.hasOwnProperty('json') &&
909
899
  formSettings.json === true
910
900
  ) {
911
- let dataId = paramValue || getDataId();
901
+ let dataId = getDataId();
912
902
 
913
903
  urlSuffix = '/json/get';
914
904
  method = 'POST';
@@ -1381,10 +1371,7 @@ function Form({
1381
1371
  <div className={styles.modal}>
1382
1372
  <div className={styles.modal__header}>
1383
1373
  <h1>{formSettings[formType]?.title}</h1>
1384
- <button
1385
- className={styles.modal__close}
1386
- onClick={closeModal}
1387
- >
1374
+ <button className={styles.modal__close} onClick={closeModal}>
1388
1375
  <CircleX strokeWidth={2} size={24} />
1389
1376
  </button>
1390
1377
  </div>