@topconsultnpm/sdkui-react-beta 6.14.28 → 6.14.29

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,4 +1,7 @@
1
1
  import React from 'react';
2
+ export interface ITMPanelRef {
3
+ focusPanel: () => void;
4
+ }
2
5
  export interface ITMPanelProps {
3
6
  allowMaximize?: boolean;
4
7
  color?: string;
@@ -18,5 +21,5 @@ export interface ITMPanelProps {
18
21
  onMaximize?: (isMaximized: boolean) => void;
19
22
  onActiveChanged?: (isActive: boolean) => void;
20
23
  }
21
- declare const TMPanel: React.FC<ITMPanelProps>;
24
+ declare const TMPanel: React.ForwardRefExoticComponent<ITMPanelProps & React.RefAttributes<ITMPanelRef>>;
22
25
  export default TMPanel;
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useCallback, useRef, useState } from 'react';
2
+ import { useCallback, useRef, useState, forwardRef, useImperativeHandle } from 'react';
3
3
  import styled from 'styled-components';
4
4
  import { IconArrowLeft, IconClearButton, IconWindowMaximize, IconWindowMinimize, isPositiveNumber, SDKUI_Globals, SDKUI_Localizator } from '../../helper';
5
5
  import TMButton from './TMButton';
@@ -65,11 +65,18 @@ const StyledPanelContent = styled.div `
65
65
  outline: none;
66
66
  }
67
67
  `;
68
- const TMPanel = ({ allowMaximize = true, color, backgroundColor, backgroundColorContainer, children, showHeader = true, title, totalItems, displayedItemsCount, toolbar, padding = '5px', isVisible = true, onBack, onClose, onHeaderDoubleClick, onMaximize, onActiveChanged }) => {
68
+ const TMPanel = forwardRef(({ allowMaximize = true, color, backgroundColor, backgroundColorContainer, children, showHeader = true, title, totalItems, displayedItemsCount, toolbar, padding = '5px', isVisible = true, onBack, onClose, onHeaderDoubleClick, onMaximize, onActiveChanged }, ref) => {
69
69
  const [isPanelActive, setIsPanelActive] = useState(false);
70
70
  const [isMaximized, setIsMaximized] = useState(false);
71
71
  const panelRef = useRef(null);
72
72
  const pendingFocusCheck = useRef(null); // Per un timer
73
+ // Espone i metodi imperativi tramite useImperativeHandle
74
+ useImperativeHandle(ref, () => ({
75
+ focusPanel: () => {
76
+ // Imposta il focus sul div StyledPanelContent
77
+ panelRef.current?.focus();
78
+ },
79
+ }));
73
80
  const setActiveStatus = useCallback((isActive) => {
74
81
  if (isPanelActive !== isActive) { // Solo se lo stato cambia
75
82
  setIsPanelActive(isActive);
@@ -161,5 +168,5 @@ const TMPanel = ({ allowMaximize = true, color, backgroundColor, backgroundColor
161
168
  }, children: [toolbar, allowMaximize && _jsx(TMButton, { color: 'primaryOutline', caption: isMaximized ? SDKUI_Localizator.Minimize : SDKUI_Localizator.Maximize, icon: isMaximized
162
169
  ? _jsx(IconWindowMinimize, { fontSize: 16 })
163
170
  : _jsx(IconWindowMaximize, { fontSize: 16 }), btnStyle: 'icon', onClick: handleMaximize }), onClose && _jsx(TMButton, { color: 'primaryOutline', caption: SDKUI_Localizator.Close, icon: _jsx(IconClearButton, {}), btnStyle: 'icon', onClick: () => { setIsMaximized(false); onClose?.(); } })] })] }) }), _jsx(StyledPanelContent, { "$height": showHeader ? "calc(100% - 40px)" : "100%", "$padding": padding, "$backgroundColor": backgroundColorContainer ?? `#FFFFFF`, children: children })] }));
164
- };
171
+ });
165
172
  export default TMPanel;
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useEffect, useRef, useState } from 'react';
2
+ import { useCallback, useEffect, useRef, useState } from 'react';
3
3
  import styled from 'styled-components';
4
4
  import { IconFolderOpen, SDKUI_Localizator, formatBytes, IconClear, extensionHandler, IconCloseOutline } from '../../../helper';
5
5
  import usePreventFileDrop from '../../../hooks/usePreventFileDrop';
@@ -17,6 +17,8 @@ const TMFileUploader = ({ deviceType = DeviceType.DESKTOP, onClose, onFileUpload
17
17
  const [fileSize, setFileSize] = useState(undefined);
18
18
  const [fileExt, setFileExt] = useState(undefined);
19
19
  const uploaderRef = useRef(null);
20
+ // Ref al TMPanel per chiamare focusPanel()
21
+ const fileUploaderPanelRef = useRef(null);
20
22
  usePreventFileDrop([uploaderRef]);
21
23
  useEffect(() => {
22
24
  if (!defaultBlob) {
@@ -50,12 +52,18 @@ const TMFileUploader = ({ deviceType = DeviceType.DESKTOP, onClose, onFileUpload
50
52
  if (file)
51
53
  handleFile(file);
52
54
  };
53
- const handleInputChange = (e) => {
54
- const file = e.target.files?.[0];
55
+ // Funzione per rifocalizzare il pannello dopo la selezione del file
56
+ const refocusAfterFileInput = useCallback(() => {
57
+ fileUploaderPanelRef.current?.focusPanel();
58
+ }, []);
59
+ const handleInputChange = useCallback((event) => {
60
+ const file = event.target.files?.[0] || null;
55
61
  if (file)
56
62
  handleFile(file);
57
- };
58
- const clearFile = () => {
63
+ // Important: Rifocalizza dopo che il file input ha finito
64
+ refocusAfterFileInput();
65
+ }, [onFileUpload, refocusAfterFileInput]);
66
+ const clearFile = useCallback(() => {
59
67
  setUploadedFile(null);
60
68
  setFileName('');
61
69
  setFileSize(undefined);
@@ -65,15 +73,17 @@ const TMFileUploader = ({ deviceType = DeviceType.DESKTOP, onClose, onFileUpload
65
73
  if (fileInput) {
66
74
  fileInput.value = '';
67
75
  }
68
- };
69
- const browseHandler = () => {
76
+ // Rifocalizza dopo la cancellazione del file
77
+ refocusAfterFileInput();
78
+ }, [onFileUpload, refocusAfterFileInput]);
79
+ const browseHandler = useCallback(() => {
70
80
  document.getElementById('fileInput')?.click();
71
- };
81
+ }, []);
72
82
  let content = !uploadedFile ?
73
- _jsx("div", { style: { display: 'flex', gap: 10, width: '100%', height: '100%' }, children: _jsxs(UploadContainer, { ref: uploaderRef, onDragOver: handleDragOver, onDragLeave: handleDragLeave, onDrop: handleDrop, style: { backgroundColor: dragOver ? '#76b1e6' : 'white' }, onDoubleClick: browseHandler, "$isRequired": isRequired, children: [_jsx("div", { style: { display: 'flex', gap: '10px', flexDirection: 'column', position: 'absolute', right: 5, top: 5 }, children: _jsx(TMButton, { btnStyle: 'icon', caption: 'Sfoglia', color: isRequired && !uploadedFile ? 'error' : 'primary', onClick: browseHandler, icon: _jsx(IconFolderOpen, { fontSize: 22 }) }) }), _jsx("p", { style: { fontSize: '1.2rem', fontWeight: 'bold' }, children: deviceType === DeviceType.MOBILE ? 'Clicca per sfogliare il tuo file' : 'Trascina il tuo file qui o fai doppio click per sfogliarlo' }), isRequired && _jsxs("p", { style: { fontWeight: 'bold' }, children: [" ", SDKUI_Localizator.RequiredField, " "] })] }) }) :
83
+ _jsx("div", { style: { display: 'flex', gap: 10, width: '100%', height: '100%' }, children: _jsxs(UploadContainer, { ref: uploaderRef, tabIndex: 0, onDragOver: handleDragOver, onDragLeave: handleDragLeave, onDrop: handleDrop, style: { backgroundColor: dragOver ? '#76b1e6' : 'white' }, onDoubleClick: browseHandler, "$isRequired": isRequired, children: [_jsx("div", { style: { display: 'flex', gap: '10px', flexDirection: 'column', position: 'absolute', right: 5, top: 5 }, children: _jsx(TMButton, { btnStyle: 'icon', caption: 'Sfoglia', color: isRequired && !uploadedFile ? 'error' : 'primary', onClick: browseHandler, icon: _jsx(IconFolderOpen, { fontSize: 22 }) }) }), _jsx("p", { style: { fontSize: '1.2rem', fontWeight: 'bold' }, children: deviceType === DeviceType.MOBILE ? 'Clicca per sfogliare il tuo file' : 'Trascina il tuo file qui o fai doppio click per sfogliarlo' }), isRequired && _jsxs("p", { style: { fontWeight: 'bold' }, children: [" ", SDKUI_Localizator.RequiredField, " "] })] }) }) :
74
84
  _jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: 10, width: '100%', height: '100%' }, children: [_jsxs("div", { style: { backgroundColor: 'white', padding: '5px 10px', borderRadius: 8, display: 'flex', alignItems: 'center', justifyContent: 'space-between', color: TMColors.primaryColor }, children: [_jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: 5 }, children: [_jsx("p", { children: "File name:" }), _jsxs("div", { style: { fontWeight: 'bold' }, children: [fileName, " ", _jsxs("span", { children: [" ", ` (${formatBytes(fileSize)})`, " "] })] })] }), uploadedFile && _jsx(TMButton, { btnStyle: 'icon', color: 'error', caption: 'Pulisci', onClick: clearFile, icon: _jsx(IconClear, { fontSize: 22 }) })] }), extensionHandler(fileExt) === FileExtensionHandler.READY_TO_SHOW ? _jsx(TMFileViewer, { fileBlob: uploadedFile, isResizingActive: isResizingActive }) :
75
85
  _jsx("div", { style: { backgroundColor: '#f6dbdb', padding: '5px 10px', borderRadius: 8, display: 'flex', alignItems: 'center', justifyContent: 'space-between', color: TMColors.error }, children: _jsxs("div", { children: [" ", 'Anteprima non disponibile.', fileExt && _jsx("b", { children: ` (*.${fileExt})` })] }) })] });
76
- return (_jsx(TMPanel, { title: SDKUI_Localizator.FileUpload, onBack: deviceType === DeviceType.MOBILE ? () => onClose?.() : undefined, toolbar: deviceType !== DeviceType.MOBILE ? _jsx(StyledHeaderIcon, { onClick: onClose, "$color": 'white', children: _jsx(TMTooltip, { content: SDKUI_Localizator.Close, children: _jsx(IconCloseOutline, {}) }) }) : undefined, children: _jsxs("div", { style: { width: '100%', height: '100%', padding: '2px', display: 'flex', flexDirection: 'column', gap: 10 }, children: [_jsx(HiddenInput, { id: "fileInput", type: "file", onChange: handleInputChange }), content] }) }));
86
+ return (_jsx(TMPanel, { ref: fileUploaderPanelRef, title: SDKUI_Localizator.FileUpload, onBack: deviceType === DeviceType.MOBILE ? () => onClose?.() : undefined, toolbar: deviceType !== DeviceType.MOBILE ? _jsx(StyledHeaderIcon, { onClick: onClose, "$color": 'white', children: _jsx(TMTooltip, { content: SDKUI_Localizator.Close, children: _jsx(IconCloseOutline, {}) }) }) : undefined, children: _jsxs("div", { style: { width: '100%', height: '100%', padding: '2px', display: 'flex', flexDirection: 'column', gap: 10 }, children: [_jsx(HiddenInput, { id: "fileInput", type: "file", onChange: handleInputChange }), content] }) }));
77
87
  };
78
88
  const UploadContainer = styled.div `
79
89
  position: relative;
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useEffect, useState } from "react";
3
- import { SDK_Globals } from '@topconsultnpm/sdk-ts-beta';
3
+ import { SDK_Globals, UserListCacheService } from '@topconsultnpm/sdk-ts-beta';
4
4
  import styled from "styled-components";
5
5
  import { SDKUI_Localizator, IconApply, IconCloseOutline, IconUser, IconInfo } from "../../../helper";
6
6
  import { TMColors } from "../../../utils/theme";
@@ -92,12 +92,16 @@ export const WorkFlowReAssignPopUp = ({ DID = 0, TID = 0, deviceType = DeviceTyp
92
92
  TMSpinner.hide();
93
93
  }
94
94
  };
95
- // useEffect(() => {
96
- // SDK_Globals.tmSession?.NewWorkflowEngine().RetrieveAllAsync().then((o) => console.log('WFs', o));
97
- // SDK_Globals.tmSession?.NewWorkflowEngine().RetrieveAsync(11283).then((o) => console.log('WF', o));
98
- // }, [])
99
- useEffect(() => { }, []);
100
- return (_jsx(TMModal, { toolbar: _jsx(TMButton, { btnStyle: 'advanced', showTooltip: false, icon: _jsx(IconUser, { fontSize: 16 }), caption: 'Riassegna', disabled: disable, onClick: () => !disable && reAssignWorkFlowAsync(), advancedColor: TMColors.tertiary }), onClose: onClose, width: deviceType === DeviceType.MOBILE ? '95%' : '60%', height: '60%', isModal: true, title: 'Riassegna workflow ' + (selectedItems.length > 0 ? '(' + count() + ')' : ''), children: _jsxs("div", { style: { width: '100%', height: '100%', padding: '10px', display: 'flex', flexDirection: 'column', gap: 5 }, children: [_jsx(TMUserChooser, { values: selectedUserID, onValueChanged: (IDs) => {
95
+ useEffect(() => {
96
+ const items = selectedItems.length > 0
97
+ ? selectedItems.map(({ TID, DID }) => ({ TID, DID }))
98
+ : [{ TID, DID }];
99
+ SDK_Globals.tmSession?.NewWorkflowEngine().WFApprGetWFInfoAsync(items?.[0].TID).then(async (w) => {
100
+ let users = await UserListCacheService.GetAllAsync();
101
+ setParticipants(users.filter((u) => w?.participants?.some((p) => p.userID === u.id)));
102
+ }).catch(err => TMExceptionBoxManager.show({ exception: err }));
103
+ }, [selectedItems]);
104
+ return (_jsx(TMModal, { toolbar: _jsx(TMButton, { btnStyle: 'advanced', showTooltip: false, icon: _jsx(IconUser, { fontSize: 16 }), caption: 'Riassegna', disabled: disable, onClick: () => !disable && reAssignWorkFlowAsync(), advancedColor: TMColors.tertiary }), onClose: onClose, width: deviceType === DeviceType.MOBILE ? '95%' : '60%', height: '60%', isModal: true, title: 'Riassegna workflow ' + (selectedItems.length > 0 ? '(' + count() + ')' : ''), children: _jsxs("div", { style: { width: '100%', height: '100%', padding: '10px', display: 'flex', flexDirection: 'column', gap: 5 }, children: [_jsx(TMUserChooser, { dataSource: participants, values: selectedUserID, onValueChanged: (IDs) => {
101
105
  setSelectedUserID(IDs ?? []);
102
106
  } }), _jsxs("p", { style: { color: commentValue.length === 0 ? TMColors.error : 'black' }, children: ["Commento ", commentValue.length === 0 && _jsx("span", { children: ' (Campo obbligatorio)' }), " "] }), _jsx(StyledTextArea, { "$isValid": commentValue.length !== 0, value: commentValue, onChange: (e) => setCommentValue(e.target.value) })] }) }));
103
107
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@topconsultnpm/sdkui-react-beta",
3
- "version": "6.14.28",
3
+ "version": "6.14.29",
4
4
  "description": "",
5
5
  "scripts": {
6
6
  "test": "echo \"Error: no test specified\" && exit 1",
@@ -42,7 +42,7 @@
42
42
  "lib"
43
43
  ],
44
44
  "dependencies": {
45
- "@topconsultnpm/sdk-ts-beta": "6.14.4",
45
+ "@topconsultnpm/sdk-ts-beta": "6.14.5",
46
46
  "buffer": "^6.0.3",
47
47
  "devextreme": "24.2.6",
48
48
  "devextreme-react": "24.2.6",