tycho-components 0.0.9 → 0.0.10-SNAPSHOT-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.
@@ -1,9 +1,13 @@
1
1
  import AppEditableField from './AppEditableField';
2
2
  import FormField from './FormField';
3
3
  import './style.scss';
4
+ type Item = {
5
+ uid: string;
6
+ [key: string]: unknown;
7
+ };
4
8
  type Props = {
5
9
  translation: string;
6
- item: Record<string, unknown>;
10
+ item: Item;
7
11
  fields: FormField[];
8
12
  save?: (field: AppEditableField) => void;
9
13
  group?: string;
@@ -2,79 +2,94 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
2
2
  import { faQuestionCircle } from '@fortawesome/free-solid-svg-icons';
3
3
  import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
4
4
  import { format } from 'date-fns-tz';
5
+ import { useCallback } from 'react';
5
6
  import EasyEdit from 'react-easy-edit';
6
7
  import { useTranslation } from 'react-i18next';
7
8
  import Switch from 'react-switch';
8
9
  import AppColorpicker from '../AppColorpicker';
9
10
  import './style.scss';
11
+ // Utility to safely get nested values via a dotted path
12
+ const getNestedValue = (obj, path) => path.split('.').reduce((o, key) => (o && key in o ? o[key] : undefined), obj);
13
+ // Pure function — no need to inline this in the component
14
+ const formatDate = (date, fmt) => {
15
+ if (!date)
16
+ return '';
17
+ return format(date, fmt);
18
+ };
10
19
  export default function AppEditable({ translation, fields, item, save, group, className, reference, }) {
11
20
  const { t } = useTranslation([translation, 'common']);
12
- const formatDate = (date, fmt) => {
13
- if (!date)
14
- return '';
15
- return format(date, fmt);
16
- };
17
- const handleSave = (value, field) => {
18
- save &&
19
- save({
20
- uid: item.uid,
21
- name: field.name,
22
- type: field.type,
23
- value,
24
- ref: reference ? item[reference] : undefined,
25
- });
21
+ const handleSave = useCallback((value, field) => {
22
+ if (!save)
23
+ return;
24
+ save({
25
+ uid: item.uid,
26
+ name: field.name,
27
+ type: field.type,
28
+ value,
29
+ ref: reference ? item[reference] : undefined,
30
+ });
31
+ }, [save, item, reference]);
32
+ const getValue = (field) => {
33
+ const value = getNestedValue(item, field.name);
34
+ return value !== undefined && value !== ''
35
+ ? value
36
+ : (field.default ?? null);
26
37
  };
27
38
  const getDateValue = (field) => {
28
39
  const v = getValue(field);
29
40
  return !v ? null : formatDate(new Date(v), 'yyyy-MM-dd');
30
41
  };
31
- const getValue = (field) => {
32
- if (field.name.indexOf('.') === -1) {
33
- if (!isEmptyValue(item, field.name))
34
- return item[field.name];
35
- return field.default !== undefined ? field.default : null;
36
- }
37
- const splits = field.name.split('.');
38
- let val = item;
39
- for (const split of splits) {
40
- if (typeof val === 'object' && val !== null && split in val) {
41
- val = val[split];
42
- }
43
- else {
44
- val = undefined;
45
- break;
46
- }
47
- }
48
- if (val !== undefined && val !== '')
49
- return val;
50
- return field.default !== undefined ? field.default : null;
51
- };
52
- const isEmptyValue = (thisItem, thisName) => thisItem[thisName] === undefined || thisItem[thisName] === '';
53
42
  const getValueToDisplay = (field) => {
54
43
  const value = getValue(field);
55
- if (field.options && field.options.length > 0) {
44
+ if (field.options?.length) {
56
45
  const option = field.options.find((op) => op.value === value);
57
46
  if (option)
58
47
  return option.label;
59
48
  }
60
- // Fallback — if value is a string, number, or boolean, display it.
61
49
  if (typeof value === 'string' ||
62
50
  typeof value === 'number' ||
63
- typeof value === 'boolean') {
51
+ typeof value === 'boolean')
64
52
  return value;
65
- }
66
53
  return null;
67
54
  };
68
- const getLabelValueForList = (options) => {
69
- return options.map((op) => ({
70
- label: t(op.label),
71
- value: op.value,
72
- }));
55
+ const getLabelValueForList = (options) => options.map((op) => ({ label: t(op.label), value: op.value }));
56
+ const sharedEditProps = {
57
+ saveButtonLabel: t('common:button.confirm'),
58
+ cancelButtonLabel: t('common:button.cancel'),
59
+ placeholder: t('common:placeholder.input'),
60
+ };
61
+ const renderField = (field) => {
62
+ const value = getValue(field);
63
+ switch (field.type) {
64
+ case 'display':
65
+ return _jsx("span", { children: getValueToDisplay(field) ?? '--' });
66
+ case 'code':
67
+ return (_jsx("div", { className: "textarea-code", children: _jsx(EasyEdit, { type: "textarea", onSave: (v) => handleSave(JSON.parse(v), field), value: JSON.stringify(value || {}, null, 2), ...sharedEditProps }) }));
68
+ case 'text':
69
+ case 'number':
70
+ case 'locale':
71
+ case 'year':
72
+ return (_jsx(EasyEdit, { type: "text", onSave: (v) => handleSave(v, field), value: value, ...sharedEditProps }));
73
+ case 'textarea':
74
+ return (_jsx(EasyEdit, { type: "textarea", onSave: (v) => handleSave(v, field), value: value, ...sharedEditProps }));
75
+ case 'select':
76
+ case 'list':
77
+ return (_jsx(EasyEdit, { type: "select", options: getLabelValueForList(field.options || []), onSave: (v) => handleSave(v, field), value: value, ...sharedEditProps }));
78
+ case 'range':
79
+ return (_jsx(EasyEdit, { type: "range", onSave: (v) => handleSave(v, field), attributes: { name: 'awesome-range', min: 0, max: 100, step: 1 }, value: value, ...sharedEditProps }));
80
+ case 'switch':
81
+ return (_jsx(Switch, { onChange: (checked) => handleSave(checked, field), checked: value || false }));
82
+ case 'date':
83
+ return (_jsx(EasyEdit, { type: "date", onSave: (v) => handleSave(new Date(v), field), value: getDateValue(field), ...sharedEditProps }));
84
+ case 'password':
85
+ return (_jsx(EasyEdit, { type: "password", onSave: (v) => handleSave(v, field), value: value, ...sharedEditProps }));
86
+ case 'color':
87
+ return (_jsx(AppColorpicker, { item: item, field: field, handleSave: handleSave }));
88
+ default:
89
+ return null;
90
+ }
73
91
  };
74
92
  return (_jsx(_Fragment, { children: fields.map((field, idx) => (_jsxs("div", { className: `editable-container ${className || ''}`, children: [_jsxs("div", { className: "title", children: [_jsxs("h6", { children: [field.title
75
93
  ? field.title
76
- : t(`${translation}:${group || ''}.field.${field.name}`), field.required && _jsx("span", { children: "*" })] }), field.tooltip && (_jsx(FontAwesomeIcon, { icon: faQuestionCircle, className: "info", title: field.tooltip }))] }), field.type === 'display' ? (_jsx("span", { children: getValueToDisplay(field) ?? '--' })) : null, field.type === 'code' ? (_jsx("div", { className: "textarea-code", children: _jsx(EasyEdit, { type: "textarea", onSave: (value) => handleSave(JSON.parse(value), field), saveButtonLabel: t('common:button.confirm'), cancelButtonLabel: t('common:button.cancel'), value: JSON.stringify(getValue(field) || {}), placeholder: t('common:placeholder.input') }) })) : null, (field.type === 'text' ||
77
- field.type === 'number' ||
78
- field.type === 'locale' ||
79
- field.type === 'year') && (_jsx(EasyEdit, { type: "text", onSave: (value) => handleSave(value, field), saveButtonLabel: t('common:button.confirm'), cancelButtonLabel: t('common:button.cancel'), value: getValue(field), placeholder: t('common:placeholder.input') })), field.type === 'textarea' ? (_jsx(EasyEdit, { type: "textarea", onSave: (value) => handleSave(value, field), saveButtonLabel: t('common:button.confirm'), cancelButtonLabel: t('common:button.cancel'), value: getValue(field), placeholder: t('common:placeholder.input') })) : null, field.type === 'select' || field.type === 'list' ? (_jsx(EasyEdit, { type: "select", options: getLabelValueForList(field.options || []), onSave: (value) => handleSave(value, field), saveButtonLabel: t('common:button.confirm'), cancelButtonLabel: t('common:button.cancel'), placeholder: t('common:placeholder.input'), value: getValue(field) })) : null, field.type === 'range' ? (_jsx(EasyEdit, { type: "range", onSave: (value) => handleSave(value, field), attributes: { name: 'awesome-range', min: 0, max: 100, step: 1 }, placeholder: t('common:placeholder.input'), value: getValue(field), saveButtonLabel: t('common:button.confirm'), cancelButtonLabel: t('common:button.cancel') })) : null, field.type === 'switch' ? (_jsx(Switch, { onChange: (checked) => handleSave(checked, field), checked: getValue(field) || false })) : null, field.type === 'date' && (_jsx(EasyEdit, { type: "date", onSave: (value) => handleSave(new Date(value), field), placeholder: t('common:placeholder.input'), value: getDateValue(field), saveButtonLabel: t('common:button.confirm'), cancelButtonLabel: t('common:button.cancel') })), field.type === 'password' && (_jsx(EasyEdit, { type: "password", onSave: (value) => handleSave(value, field), saveButtonLabel: t('common:button.confirm'), cancelButtonLabel: t('common:button.cancel'), value: getValue(field), placeholder: t('common:placeholder.input') })), field.type === 'color' ? (_jsx(AppColorpicker, { item: item, field: field, handleSave: handleSave })) : null] }, idx.valueOf()))) }));
94
+ : t(`${translation}:${group || ''}.field.${field.name}`), field.required && _jsx("span", { children: "*" })] }), field.tooltip && (_jsx(FontAwesomeIcon, { icon: faQuestionCircle, className: "info", title: field.tooltip }))] }), renderField(field)] }, idx))) }));
80
95
  }
@@ -6,4 +6,15 @@ type Props = {
6
6
  onConfirm: () => void;
7
7
  };
8
8
  export default function AppModalRemove({ title, subtitle, onClose, onConfirm, }: Props): import("react/jsx-runtime").JSX.Element;
9
+ export declare const modalRemoveStyle: {
10
+ position: string;
11
+ top: string;
12
+ left: string;
13
+ transform: string;
14
+ width: string;
15
+ maxWidth: string;
16
+ borderRadius: string;
17
+ boxShadow: number;
18
+ bgcolor: string;
19
+ };
9
20
  export {};
@@ -5,9 +5,9 @@ import { Button, Icon } from 'tycho-storybook';
5
5
  import './style.scss';
6
6
  export default function AppModalRemove({ title, subtitle, onClose, onConfirm, }) {
7
7
  const { t } = useTranslation('common');
8
- return (_jsx(Modal, { open: true, children: _jsxs(Box, { className: "modal-container modal-remove", sx: style, children: [_jsxs("div", { className: "body", children: [_jsx(Icon, { name: "warning", size: "large", filled: true }), _jsxs("div", { className: "texts", children: [_jsx("span", { className: "title", children: title }), _jsx("span", { className: "subtitle", children: subtitle })] })] }), _jsxs("div", { className: "footer", children: [_jsx(Button, { onClick: onClose, text: t('button.cancel'), mode: "tonal" }), _jsx(Button, { onClick: onConfirm, text: t('button.confirm') })] })] }) }));
8
+ return (_jsx(Modal, { open: true, children: _jsxs(Box, { className: "modal-container modal-remove", sx: modalRemoveStyle, children: [_jsx("div", { className: "body", children: _jsxs("div", { className: "line", children: [_jsx(Icon, { name: "warning", size: "large", filled: true }), _jsxs("div", { className: "texts", children: [_jsx("span", { className: "title", children: title }), _jsx("span", { className: "subtitle", children: subtitle })] })] }) }), _jsxs("div", { className: "footer", children: [_jsx(Button, { onClick: onClose, text: t('button.cancel'), mode: "tonal" }), _jsx(Button, { onClick: onConfirm, text: t('button.confirm') })] })] }) }));
9
9
  }
10
- const style = {
10
+ export const modalRemoveStyle = {
11
11
  position: 'absolute',
12
12
  top: '40%',
13
13
  left: '50%',
@@ -40,24 +40,29 @@
40
40
  &.modal-remove {
41
41
  .body {
42
42
  display: flex;
43
- gap: 16px;
43
+ flex-direction: column;
44
44
 
45
- > .ds-icon {
46
- color: var(--icon-warning);
47
- }
48
-
49
- .texts {
45
+ > .line {
50
46
  display: flex;
51
- flex-direction: column;
47
+ gap: 16px;
52
48
 
53
- > .title {
54
- @include subtitle-medium-2;
55
- color: var(--text-primary);
49
+ > .ds-icon {
50
+ color: var(--icon-warning);
56
51
  }
57
52
 
58
- > .subtitle {
59
- @include body-medium-1;
60
- color: var(--text-secondary);
53
+ .texts {
54
+ display: flex;
55
+ flex-direction: column;
56
+
57
+ > .title {
58
+ @include subtitle-medium-2;
59
+ color: var(--text-primary);
60
+ }
61
+
62
+ > .subtitle {
63
+ @include body-medium-1;
64
+ color: var(--text-secondary);
65
+ }
61
66
  }
62
67
  }
63
68
  }
@@ -1,20 +1,26 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Box, Modal } from '@mui/material';
2
3
  import { useContext } from 'react';
3
4
  import { useTranslation } from 'react-i18next';
4
- import AppModalRemove from '../../AppModal/AppModalRemove';
5
+ import { Button, Icon, SelectField } from 'tycho-storybook';
6
+ import { modalRemoveStyle } from '../../AppModal/AppModalRemove';
5
7
  import CommonContext from '../../configs/CommonContext';
6
8
  import { useMessageUtils } from '../../configs/useMessageUtils';
7
9
  import ParticipantService from '../types/ParticipantService';
10
+ import { useForm } from 'react-hook-form';
8
11
  import './style.scss';
9
12
  export default function ParticipantRemove({ participant, participants, document, onClose, onChange, }) {
10
13
  const { t } = useTranslation('participants');
11
14
  const { state } = useContext(CommonContext);
12
- const { dispatchLoading, dispatchError } = useMessageUtils();
15
+ const { dispatchLoading } = useMessageUtils();
16
+ const createdForm = useForm({
17
+ mode: 'onChange',
18
+ });
13
19
  const handleRemove = () => {
14
20
  if (state.toastLoading || !participant)
15
21
  return;
16
22
  dispatchLoading(true);
17
- ParticipantService.remove(document, participant.code)
23
+ ParticipantService.remove(document, participant.code, createdForm.getValues().code)
18
24
  .then(() => {
19
25
  const list = participants?.filter((p) => p.code !== participant.code) || [];
20
26
  onChange(list);
@@ -23,5 +29,11 @@ export default function ParticipantRemove({ participant, participants, document,
23
29
  dispatchLoading(false);
24
30
  });
25
31
  };
26
- return (_jsx(AppModalRemove, { title: t('modal.remove.title'), subtitle: t('modal.remove.description'), onClose: onClose, onConfirm: handleRemove }));
32
+ let subtitle = t('modal.remove.description');
33
+ return (_jsx(Modal, { open: true, children: _jsxs(Box, { className: "modal-container modal-remove", sx: modalRemoveStyle, children: [_jsxs("div", { className: "body", children: [_jsxs("div", { className: "line", children: [_jsx(Icon, { name: "warning", size: "large", filled: true }), _jsxs("div", { className: "texts", children: [_jsx("span", { className: "title", children: t('modal.remove.title') }), _jsx("span", { className: "subtitle", children: subtitle })] })] }), participants.length !== 1 && (_jsxs("div", { className: "select-participant", children: [_jsxs("b", { children: [t('modal.remove.participant'), " ", participant.name, " (", participant.code, ")"] }), _jsx(SelectField, { label: t('modal.select.transfer'), attr: "code", createdForm: createdForm, options: participants
34
+ .filter((p) => p.code !== participant.code)
35
+ .map((p) => ({
36
+ value: p.code,
37
+ label: `${p.code} - ${p.name}`,
38
+ })), showEndAdornment: false })] }))] }), _jsxs("div", { className: "footer", children: [_jsx(Button, { onClick: onClose, text: t('common:button.cancel'), mode: "tonal" }), _jsx(Button, { onClick: handleRemove, text: t('common:button.confirm') })] })] }) }));
27
39
  }
@@ -1,32 +1,15 @@
1
- .participants-container {
2
- .header {
3
- display: flex;
4
- background-color: var(--color-secondary);
5
- padding: 8px 16px;
6
-
7
- .actions {
8
- margin-left: auto;
9
- margin-top: auto;
10
- margin-bottom: auto;
11
-
12
- .action {
13
- border: var(--border-default);
14
- padding: 0px 16px;
1
+ .modal-container {
2
+ &.modal-remove {
3
+ .body {
4
+ .select-participant {
5
+ border-top: 1px solid var(--border-subtle-1);
6
+ padding-top: 16px;
7
+ margin-top: 16px;
8
+
9
+ > .ds-select-text {
10
+ margin-top: 16px;
11
+ }
15
12
  }
16
13
  }
17
14
  }
18
-
19
- .body {
20
- height: 90vh;
21
- overflow-y: auto;
22
- padding: var(--spacing-small);
23
- }
24
-
25
- .footer {
26
- margin-top: 16px;
27
- padding-top: 16px;
28
- display: flex;
29
- justify-content: right;
30
- border-top: var(--border-default);
31
- }
32
15
  }
@@ -2,7 +2,7 @@ import AppEditableField from '../../AppEditable/AppEditableField';
2
2
  import Participant, { ParticipantCreateRequest } from './Participant';
3
3
  declare function add(uid: string, request: ParticipantCreateRequest): Promise<import("axios").AxiosResponse<Participant, any>>;
4
4
  declare function update(field: AppEditableField): Promise<import("axios").AxiosResponse<any, any>>;
5
- declare function remove(document: string, code: string): Promise<import("axios").AxiosResponse<any, any>>;
5
+ declare function remove(document: string, code: string, transfer?: string): Promise<import("axios").AxiosResponse<any, any>>;
6
6
  declare const ParticipantService: {
7
7
  add: typeof add;
8
8
  update: typeof update;
@@ -5,8 +5,12 @@ function add(uid, request) {
5
5
  function update(field) {
6
6
  return api.patch(`${import.meta.env.VITE_APP_CATALOG_API}/participant/update`, field);
7
7
  }
8
- function remove(document, code) {
9
- return api.delete(`${import.meta.env.VITE_APP_CATALOG_API}/participant/${document}/${code}`);
8
+ function remove(document, code, transfer) {
9
+ const request = {
10
+ code,
11
+ transfer,
12
+ };
13
+ return api.delete(`${import.meta.env.VITE_APP_CATALOG_API}/participant/${document}`, { data: request });
10
14
  }
11
15
  const ParticipantService = { add, update, remove };
12
16
  export default ParticipantService;
@@ -36,6 +36,7 @@ export declare const commonResources: {
36
36
  'modal.add.title': string;
37
37
  'modal.input.code': string;
38
38
  'modal.input.name': string;
39
+ 'modal.select.transfer': string;
39
40
  'participant.code.exists': string;
40
41
  };
41
42
  };
@@ -22,6 +22,7 @@ export declare const ParticipantsTexts: {
22
22
  'modal.add.title': string;
23
23
  'modal.input.code': string;
24
24
  'modal.input.name': string;
25
+ 'modal.select.transfer': string;
25
26
  'participant.code.exists': string;
26
27
  };
27
28
  'pt-BR': {
@@ -22,6 +22,7 @@ export const ParticipantsTexts = {
22
22
  'modal.add.title': 'Add new participant',
23
23
  'modal.input.code': 'ID',
24
24
  'modal.input.name': 'Name',
25
+ 'modal.select.transfer': 'Participant',
25
26
  'participant.code.exists': 'The participant code provided is already in use.',
26
27
  },
27
28
  'pt-BR': {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "tycho-components",
3
3
  "private": false,
4
- "version": "0.0.9",
4
+ "version": "0.0.10-SNAPSHOT-1",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "exports": {