@visns-studio/visns-components 4.0.9 → 4.1.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.
@@ -95,7 +95,7 @@ const SortableItem = ({
95
95
 
96
96
  {handleDelete && (
97
97
  <TrashCan
98
- className="delete trash-delete"
98
+ className="delete"
99
99
  strokeWidth={1}
100
100
  size={26}
101
101
  onClick={(e) => {
@@ -254,6 +254,8 @@ function Field({
254
254
  'radio-ajax',
255
255
  'richeditor',
256
256
  'signature',
257
+ 'table_radio',
258
+ 'table_text',
257
259
  'time',
258
260
  ].includes(settings.type)
259
261
  ) {
@@ -1096,6 +1098,102 @@ function Field({
1096
1098
  )}
1097
1099
  </>
1098
1100
  );
1101
+ case 'table_radio':
1102
+ let tableRadioColumns = [];
1103
+ let tableRadioRows = [];
1104
+
1105
+ for (const key in formData) {
1106
+ if (formData[key].id === settings.id) {
1107
+ if (formData[key].hasOwnProperty('options')) {
1108
+ tableRadioColumns = formData[key].options;
1109
+ tableRadioRows = formData[key].rows;
1110
+ break; // Assuming there's only one match needed, break out of the loop
1111
+ }
1112
+ }
1113
+ }
1114
+
1115
+ return (
1116
+ <table className={styles.contentTable}>
1117
+ <thead>
1118
+ <tr>
1119
+ <th></th>
1120
+ {tableRadioColumns.map((column, columnKey) => (
1121
+ <th
1122
+ key={`${settings.id}-${columnKey.id}`}
1123
+ style={{
1124
+ width: '250px',
1125
+ whiteSpace: 'nowrap',
1126
+ }}
1127
+ >
1128
+ {column.label}
1129
+ </th>
1130
+ ))}
1131
+ </tr>
1132
+ </thead>
1133
+ <tbody>
1134
+ {tableRadioRows.map((row, rowKey) => (
1135
+ <tr
1136
+ key={`table-radio-row-${settings.id}-${rowKey}`}
1137
+ >
1138
+ <td
1139
+ style={{
1140
+ whiteSpace: 'nowrap',
1141
+ }}
1142
+ >
1143
+ {row.label}
1144
+ </td>
1145
+ {tableRadioColumns.map(
1146
+ (column, columnKey) => (
1147
+ <td
1148
+ key={`table-radio-cell-${settings.id}-${rowKey}-${columnKey}`}
1149
+ >
1150
+ <input
1151
+ type="radio"
1152
+ name={`radio-${settings.id}-${rowKey}`}
1153
+ />
1154
+ </td>
1155
+ )
1156
+ )}
1157
+ </tr>
1158
+ ))}
1159
+ </tbody>
1160
+ </table>
1161
+ );
1162
+ case 'table_text':
1163
+ let tableTextColumns = [];
1164
+
1165
+ for (const key in formData) {
1166
+ if (formData[key].id === settings.id) {
1167
+ if (formData[key].hasOwnProperty('options')) {
1168
+ tableTextColumns = formData[key].options;
1169
+ break; // Assuming there's only one match needed, break out of the loop
1170
+ }
1171
+ }
1172
+ }
1173
+ return (
1174
+ <table className={styles.contentTable}>
1175
+ <thead>
1176
+ <tr>
1177
+ {tableTextColumns.map((column, columnKey) => (
1178
+ <th key={`${settings.id}-${columnKey.id}`}>
1179
+ {column.label}
1180
+ </th>
1181
+ ))}
1182
+ </tr>
1183
+ </thead>
1184
+ <tbody>
1185
+ <tr>
1186
+ {tableTextColumns.map((column, columnKey) => (
1187
+ <td
1188
+ key={`${settings.id}-${columnKey.id}-input`}
1189
+ >
1190
+ <input type="text" />
1191
+ </td>
1192
+ ))}
1193
+ </tr>
1194
+ </tbody>
1195
+ </table>
1196
+ );
1099
1197
  case 'textarea':
1100
1198
  return (
1101
1199
  <textarea
@@ -1160,6 +1258,8 @@ function Field({
1160
1258
  'radio-ajax',
1161
1259
  'richeditor',
1162
1260
  'signature',
1261
+ 'table_radio',
1262
+ 'table_text',
1163
1263
  'time',
1164
1264
  'toggle',
1165
1265
  ].includes(settings.type)
@@ -101,8 +101,8 @@ const Profile = ({ userProfile, setUserProfile }) => {
101
101
 
102
102
  setUserProfile((prevState) => ({
103
103
  ...prevState,
104
- name: res.data.name,
105
- signature: res.data.signature,
104
+ name: res.data.user.name,
105
+ signature: res.data.user.signature,
106
106
  }));
107
107
  toast.success('Your profile has been successfully updated.');
108
108
  } catch (err) {
@@ -34,6 +34,7 @@ function GenericFormBuilder({ setting, urlParam, userProfile }) {
34
34
  description: '',
35
35
  type: '',
36
36
  options: [],
37
+ rows: [],
37
38
  size: 'quarter',
38
39
  required: 'no',
39
40
  });
@@ -41,6 +42,10 @@ function GenericFormBuilder({ setting, urlParam, userProfile }) {
41
42
  id: '',
42
43
  label: '',
43
44
  });
45
+ const [rowOption, setRowOption] = useState({
46
+ id: '',
47
+ label: '',
48
+ });
44
49
  const [modalShow, setModalShow] = useState(false);
45
50
  const [modalType, setModalType] = useState({
46
51
  type: 'create',
@@ -101,6 +106,59 @@ function GenericFormBuilder({ setting, urlParam, userProfile }) {
101
106
  });
102
107
  };
103
108
 
109
+ /** Row Option Functionalities */
110
+ const handleRowOption = (e) => {
111
+ const { name, value } = e.target;
112
+
113
+ setRowOption((items) => ({
114
+ ...items,
115
+ [name]: value,
116
+ id: `${slugify(value)}-`,
117
+ }));
118
+ };
119
+
120
+ const handleAddRowOption = (e) => {
121
+ e.preventDefault();
122
+
123
+ if (rowOption.label !== '') {
124
+ const isLabelUnique = !dataField.rows.some(
125
+ (option) => option.label === rowOption.label
126
+ );
127
+
128
+ if (isLabelUnique) {
129
+ setDataField((items) => ({
130
+ ...items,
131
+ rows: [...items.rows, rowOption],
132
+ }));
133
+
134
+ setRowOption(() => ({
135
+ id: '',
136
+ label: '',
137
+ }));
138
+ } else {
139
+ toast.warn('Option label must be unique.');
140
+ }
141
+ } else {
142
+ toast.warn('Please enter a label for the option.');
143
+ }
144
+ };
145
+
146
+ const handleDeleteRowOption = (e) => {
147
+ e.preventDefault();
148
+
149
+ const { counter } = e.target.dataset;
150
+
151
+ setDataField((prevState) => {
152
+ const rows = prevState.rows.slice();
153
+ rows.splice(counter, 1);
154
+
155
+ return {
156
+ ...prevState,
157
+ rows: rows,
158
+ };
159
+ });
160
+ };
161
+
104
162
  /** Field Functionalities */
105
163
  const onSortEnd = ({ oldIndex, newIndex }) => {
106
164
  const newData = arrayMoveImmutable(data.detail, oldIndex, newIndex);
@@ -462,7 +520,36 @@ function GenericFormBuilder({ setting, urlParam, userProfile }) {
462
520
  case 'table_radio':
463
521
  return (
464
522
  <label className={styles.fi__label}>
465
- <table className={styles.contentTable}></table>
523
+ <table className={styles.contentTable}>
524
+ <thead>
525
+ <tr>
526
+ <th></th>
527
+ {field.options.map((option, index) => (
528
+ <th
529
+ key={`${field.id}-table-text-option-${index}`}
530
+ >
531
+ {option.label}
532
+ </th>
533
+ ))}
534
+ </tr>
535
+ </thead>
536
+ <tbody>
537
+ {field.rows.map((row, rowKey) => (
538
+ <tr
539
+ key={`${field.id}-table-text-row-data-${rowKey}`}
540
+ >
541
+ <td>{row.label}</td>
542
+ {field.options.map(
543
+ (option, optionKey) => (
544
+ <td
545
+ key={`${field.id}-table-text-data-${optionKey}-${rowKey}`}
546
+ ></td>
547
+ )
548
+ )}
549
+ </tr>
550
+ ))}
551
+ </tbody>
552
+ </table>
466
553
  <span
467
554
  className={`${styles.fi__span} ${styles.prefocus}`}
468
555
  >
@@ -1008,7 +1095,9 @@ function GenericFormBuilder({ setting, urlParam, userProfile }) {
1008
1095
  }}
1009
1096
  >
1010
1097
  {dataField.type ===
1011
- 'table_text'
1098
+ 'table_text' ||
1099
+ dataField.type ===
1100
+ 'table_radio'
1012
1101
  ? 'Column Header'
1013
1102
  : 'Label'}
1014
1103
  </th>
@@ -1131,6 +1220,146 @@ function GenericFormBuilder({ setting, urlParam, userProfile }) {
1131
1220
  </table>
1132
1221
  </div>
1133
1222
  ) : null}
1223
+
1224
+ {['table_radio'].includes(
1225
+ dataField.type
1226
+ ) ? (
1227
+ <div
1228
+ className={`${styles.formItem} ${styles.fwItem}`}
1229
+ >
1230
+ <table
1231
+ className={styles.contentTable}
1232
+ >
1233
+ <thead
1234
+ className={
1235
+ styles.gridHeaders
1236
+ }
1237
+ >
1238
+ <tr>
1239
+ <th
1240
+ style={{
1241
+ width: '450px',
1242
+ }}
1243
+ >
1244
+ Row Label
1245
+ </th>
1246
+ <th></th>
1247
+ </tr>
1248
+ </thead>
1249
+ <tbody>
1250
+ {dataField.rows.length >
1251
+ 0 ? (
1252
+ dataField.rows.map(
1253
+ (row, rowKey) => (
1254
+ <tr
1255
+ key={`row-${rowKey}`}
1256
+ >
1257
+ <td>
1258
+ {
1259
+ row.label
1260
+ }
1261
+ </td>
1262
+ <td
1263
+ style={{
1264
+ textAlign:
1265
+ 'center',
1266
+ }}
1267
+ >
1268
+ <button
1269
+ className={
1270
+ styles.btn
1271
+ }
1272
+ style={{
1273
+ padding:
1274
+ '5px 20px',
1275
+ }}
1276
+ onClick={
1277
+ handleDeleteRowOption
1278
+ }
1279
+ data-counter={
1280
+ rowKey
1281
+ }
1282
+ data-tooltip-id="system-tooltip"
1283
+ data-tooltip-content={
1284
+ 'Delete Option'
1285
+ }
1286
+ >
1287
+ <TrashCan
1288
+ strokeWidth={
1289
+ 2
1290
+ }
1291
+ size={
1292
+ 12
1293
+ }
1294
+ />
1295
+ </button>
1296
+ </td>
1297
+ </tr>
1298
+ )
1299
+ )
1300
+ ) : (
1301
+ <tr>
1302
+ <td colSpan="2">
1303
+ No entry have
1304
+ been added.
1305
+ </td>
1306
+ </tr>
1307
+ )}
1308
+ </tbody>
1309
+ <tfoot>
1310
+ <tr>
1311
+ <td>
1312
+ <input
1313
+ type="text"
1314
+ style={{
1315
+ padding:
1316
+ '5px',
1317
+ }}
1318
+ name="label"
1319
+ onChange={
1320
+ handleRowOption
1321
+ }
1322
+ value={
1323
+ rowOption.label
1324
+ }
1325
+ />
1326
+ </td>
1327
+ <td
1328
+ style={{
1329
+ textAlign:
1330
+ 'center',
1331
+ }}
1332
+ >
1333
+ <button
1334
+ className={
1335
+ styles.btn
1336
+ }
1337
+ style={{
1338
+ padding:
1339
+ '5px 20px',
1340
+ }}
1341
+ onClick={
1342
+ handleAddRowOption
1343
+ }
1344
+ data-tooltip-id="system-tooltip"
1345
+ data-tooltip-content={
1346
+ 'Add Option'
1347
+ }
1348
+ >
1349
+ <CirclePlus
1350
+ strokeWidth={
1351
+ 2
1352
+ }
1353
+ size={12}
1354
+ />
1355
+ </button>
1356
+ </td>
1357
+ </tr>
1358
+ </tfoot>
1359
+ </table>
1360
+ </div>
1361
+ ) : null}
1362
+
1134
1363
  <div
1135
1364
  className={`${styles.formItem} ${styles.fwItem} ${styles.lastItem}`}
1136
1365
  >
@@ -253,7 +253,7 @@ function GenericIndex({ layout = 'full', setting, userProfile }) {
253
253
  </div>
254
254
  ) : (
255
255
  <>
256
- <div className={`grid__full`}>
256
+ <div className={`grid__subnav`}>
257
257
  <TableFilter
258
258
  filters={subnav}
259
259
  setFilters={setSubnav}
@@ -863,15 +863,14 @@ select:not(:placeholder-shown) + .fi__span {
863
863
  }
864
864
 
865
865
  .sortlist li .delete {
866
- width: 50px;
867
- position: relative;
868
- height: 50px;
869
- margin-left: auto;
870
- border-radius: 5px;
871
- overflow: hidden;
866
+ width: 100%;
867
+ max-width: 18px;
868
+ position: absolute;
869
+ left: 5px;
870
+ top: 30px;
872
871
  }
873
872
 
874
- .sortlist li .delete img {
873
+ .sortlist li .sortimg img {
875
874
  display: block;
876
875
  object-fit: cover;
877
876
  height: 100%;
@@ -906,7 +905,7 @@ select:not(:placeholder-shown) + .fi__span {
906
905
  color: var(--paragraph-color);
907
906
  }
908
907
 
909
- .dragitem svg {
908
+ .dragitem svg:first-of-type {
910
909
  width: 100%;
911
910
  max-width: 18px;
912
911
  position: absolute;
@@ -914,8 +913,12 @@ select:not(:placeholder-shown) + .fi__span {
914
913
  top: 5px;
915
914
  }
916
915
 
917
- .dragitem .delete {
918
- display: none;
916
+ .dragitem svg:nth-of-type(2) {
917
+ width: 100%;
918
+ max-width: 18px;
919
+ position: absolute;
920
+ left: 5px;
921
+ top: 30px;
919
922
  }
920
923
 
921
924
  .dragitem .sortimg {
@@ -144,3 +144,79 @@ input[type='file']:hover {
144
144
  background: var(--secondary-color);
145
145
  color: var(--primary-color);
146
146
  }
147
+
148
+ /* Table Styles */
149
+
150
+ .contentTable {
151
+ width: 100%;
152
+ border-collapse: collapse;
153
+ margin: 0 auto;
154
+ font-size: 1em;
155
+ border-radius: var(--br) var(--br) 0 0;
156
+ overflow: hidden;
157
+ border: none;
158
+ border-spacing: 0;
159
+ box-sizing: border-box;
160
+ }
161
+
162
+ .contentTable thead {
163
+ display: table-row-group;
164
+ }
165
+
166
+ .contentTable thead tr {
167
+ background: var(--table-color);
168
+ color: var(--primary-color);
169
+ text-align: left;
170
+ font-weight: 700;
171
+ text-transform: capitalize;
172
+ font-size: 1em;
173
+ }
174
+
175
+ .contentTable .filterRow th {
176
+ padding: 0;
177
+ }
178
+
179
+ .contentTable th,
180
+ .contentTable td {
181
+ font-size: 0.95em;
182
+ padding: 8px 15px;
183
+ color: var(--paragraph-color);
184
+ border-right: 1px solid var(--table-border);
185
+ line-height: 1;
186
+ border-spacing: 0;
187
+ border-collapse: collapse;
188
+ }
189
+
190
+ .contentTable th:last-of-type,
191
+ .contentTable td:last-of-type,
192
+ .contentTable th:last-child,
193
+ .contentTable td:last-child {
194
+ border-right: none;
195
+ }
196
+
197
+ .contentTable td .tdActions {
198
+ width: 100%;
199
+ display: flex;
200
+ flex-wrap: nowrap;
201
+ justify-content: flex-start;
202
+ align-items: center;
203
+ }
204
+
205
+ .contentTable td .tdAction {
206
+ background: #f0f0f0;
207
+ display: block;
208
+ line-height: 1;
209
+ padding: 0.05rem;
210
+ border-radius: var(--br);
211
+ margin: 0 0.25rem;
212
+ }
213
+
214
+ .contentTable tbody tr {
215
+ border-bottom: 1px solid var(--table-border);
216
+ cursor: pointer;
217
+ background: var(--tertiary-color);
218
+ }
219
+
220
+ .contentTable tbody tr:nth-of-type(even) {
221
+ background: darken(var(--secondary-color), 2%);
222
+ }
package/package.json CHANGED
@@ -57,7 +57,7 @@
57
57
  "react-dom": "^17.0.1"
58
58
  },
59
59
  "name": "@visns-studio/visns-components",
60
- "version": "4.0.9",
60
+ "version": "4.1.0",
61
61
  "description": "Various packages to assist in the development of our Custom Applications.",
62
62
  "main": "index.js",
63
63
  "scripts": {