@bit.rhplus/ui2.module-dropdown-list 0.0.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.
- package/ModuleInput.css +232 -0
- package/dist/ModuleInput.css +232 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +116 -0
- package/dist/index.js.map +1 -0
- package/dist/preview-1747484073029.js +7 -0
- package/dist/store/recentItemsStore.d.ts +11 -0
- package/dist/store/recentItemsStore.js +29 -0
- package/dist/store/recentItemsStore.js.map +1 -0
- package/dist/useModuleDropdownList.d.ts +20 -0
- package/dist/useModuleDropdownList.js +125 -0
- package/dist/useModuleDropdownList.js.map +1 -0
- package/index.jsx +312 -0
- package/package.json +34 -0
- package/store/recentItemsStore.js +37 -0
- package/types/asset.d.ts +43 -0
- package/types/style.d.ts +42 -0
- package/useModuleDropdownList.js +142 -0
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
// shared/hooks/useModuleInput.js
|
|
2
|
+
import { useState, useEffect, useCallback } from 'react';
|
|
3
|
+
import { useQuery } from '@tanstack/react-query';
|
|
4
|
+
import { message } from 'antd';
|
|
5
|
+
import useData from '@bit.rhplus/data'; // Upravte cestu podle skutečného umístění
|
|
6
|
+
export const useModuleDropdownList = ({ moduleDefinition, value }) => {
|
|
7
|
+
// Základní stav
|
|
8
|
+
const [modalOpen, setModalOpen] = useState(false);
|
|
9
|
+
const [searchQuery, setSearchQuery] = useState('');
|
|
10
|
+
const [selectedItem, setSelectedItem] = useState(null);
|
|
11
|
+
// const [moduleDefinition, setModuleDefinition] = useState(null);
|
|
12
|
+
// Získání fetchDataUIAsync z vašeho custom hooku
|
|
13
|
+
const { fetchDataUIAsync } = useData();
|
|
14
|
+
// Vytvoření stabilních verzí funkcí pro načítání dat pomocí useCallback
|
|
15
|
+
const fetchData = useCallback(async (query) => {
|
|
16
|
+
if (moduleDefinition?.fetchData) {
|
|
17
|
+
return moduleDefinition.fetchData(query, fetchDataUIAsync);
|
|
18
|
+
}
|
|
19
|
+
return [];
|
|
20
|
+
}, [moduleDefinition, fetchDataUIAsync]);
|
|
21
|
+
const fetchById = useCallback(async (id) => {
|
|
22
|
+
if (moduleDefinition?.fetchById) {
|
|
23
|
+
return moduleDefinition.fetchById(id, fetchDataUIAsync);
|
|
24
|
+
}
|
|
25
|
+
return null;
|
|
26
|
+
}, [moduleDefinition, fetchDataUIAsync]);
|
|
27
|
+
// Použití React Query pro načtení dat seznamu
|
|
28
|
+
const moduleListQuery = useQuery({
|
|
29
|
+
queryKey: [moduleDefinition.moduleName, 'list', searchQuery],
|
|
30
|
+
queryFn: () => fetchData(searchQuery),
|
|
31
|
+
enabled: !!moduleDefinition && modalOpen,
|
|
32
|
+
staleTime: 1000 * 60 * 5, // 5 minut
|
|
33
|
+
onError: (error) => {
|
|
34
|
+
message.error(`Chyba při načítání dat: ${error.message}`);
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
// Použití React Query pro načtení jednoho záznamu podle ID
|
|
38
|
+
const moduleDetailQuery = useQuery({
|
|
39
|
+
queryKey: [moduleDefinition.moduleName, 'detail', value],
|
|
40
|
+
queryFn: () => fetchById(value),
|
|
41
|
+
// Opraveno: načítat jen když máme ID a definici modulu, bez ohledu na selectedItem
|
|
42
|
+
enabled: !!moduleDefinition && !!value && value !== '',
|
|
43
|
+
staleTime: 1000 * 60 * 5, // 5 minut
|
|
44
|
+
onSuccess: (data) => {
|
|
45
|
+
if (data)
|
|
46
|
+
setSelectedItem(data);
|
|
47
|
+
},
|
|
48
|
+
onError: (error) => {
|
|
49
|
+
message.error(`Chyba při načítání detailu: ${error.message}`);
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
// Funkce pro otevření modálního okna
|
|
53
|
+
const openModal = () => setModalOpen(true);
|
|
54
|
+
// Funkce pro zavření modálního okna
|
|
55
|
+
const closeModal = () => setModalOpen(false);
|
|
56
|
+
// Funkce pro změnu vyhledávacího dotazu
|
|
57
|
+
const handleSearchChange = (query) => setSearchQuery(query);
|
|
58
|
+
// Funkce pro výběr položky
|
|
59
|
+
const handleItemSelect = (item) => {
|
|
60
|
+
if (item) {
|
|
61
|
+
setSelectedItem(item);
|
|
62
|
+
closeModal();
|
|
63
|
+
return item;
|
|
64
|
+
}
|
|
65
|
+
return null;
|
|
66
|
+
};
|
|
67
|
+
// Funkce pro vymazání výběru
|
|
68
|
+
const clearSelection = () => {
|
|
69
|
+
setSelectedItem(null);
|
|
70
|
+
};
|
|
71
|
+
// Vylepšená funkce pro získání zobrazované hodnoty
|
|
72
|
+
const getDisplayValue = () => {
|
|
73
|
+
if (!value || !moduleDefinition)
|
|
74
|
+
return '';
|
|
75
|
+
// Pokud máme vybranou položku, použijeme ji
|
|
76
|
+
if (selectedItem && selectedItem[moduleDefinition.valueField] === value) {
|
|
77
|
+
return moduleDefinition.getDisplayValue(selectedItem);
|
|
78
|
+
}
|
|
79
|
+
// Pokud nemáme vybranou položku, ale máme načtenou položku z React Query
|
|
80
|
+
if (moduleDetailQuery.data) {
|
|
81
|
+
return moduleDefinition.getDisplayValue(moduleDetailQuery.data);
|
|
82
|
+
}
|
|
83
|
+
// Pokud se data načítají
|
|
84
|
+
if (moduleDetailQuery.isLoading) {
|
|
85
|
+
return "Načítání...";
|
|
86
|
+
}
|
|
87
|
+
// Pokud došlo k chybě nebo data nejsou dostupná
|
|
88
|
+
return `${value} (nenačteno)`;
|
|
89
|
+
};
|
|
90
|
+
// Reset selectedItem když se změní value prop
|
|
91
|
+
useEffect(() => {
|
|
92
|
+
if (value !== selectedItem?.[moduleDefinition?.valueField]) {
|
|
93
|
+
// Pokud selectedItem neodpovídá aktuálnímu value, resetujeme ho
|
|
94
|
+
setSelectedItem(null);
|
|
95
|
+
}
|
|
96
|
+
}, [value, selectedItem, moduleDefinition]);
|
|
97
|
+
// Při otevření modálního okna zajistíme načerstvení dat
|
|
98
|
+
useEffect(() => {
|
|
99
|
+
if (modalOpen && moduleDefinition) {
|
|
100
|
+
moduleListQuery.refetch();
|
|
101
|
+
}
|
|
102
|
+
}, [modalOpen, searchQuery, moduleDefinition, moduleListQuery]);
|
|
103
|
+
// Vrácení všech potřebných stavů a funkcí
|
|
104
|
+
return {
|
|
105
|
+
// Stavy
|
|
106
|
+
moduleDefinition,
|
|
107
|
+
modalOpen,
|
|
108
|
+
searchQuery,
|
|
109
|
+
selectedItem,
|
|
110
|
+
rowData: moduleListQuery.data || [],
|
|
111
|
+
isLoading: moduleListQuery.isLoading,
|
|
112
|
+
isDetailLoading: moduleDetailQuery.isLoading,
|
|
113
|
+
// Funkce
|
|
114
|
+
openModal,
|
|
115
|
+
closeModal,
|
|
116
|
+
handleSearchChange,
|
|
117
|
+
handleItemSelect,
|
|
118
|
+
clearSelection,
|
|
119
|
+
getDisplayValue,
|
|
120
|
+
// Query objekty pro pokročilé použití
|
|
121
|
+
moduleListQuery,
|
|
122
|
+
moduleDetailQuery
|
|
123
|
+
};
|
|
124
|
+
};
|
|
125
|
+
//# sourceMappingURL=useModuleDropdownList.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useModuleDropdownList.js","sourceRoot":"","sources":["../useModuleDropdownList.js"],"names":[],"mappings":"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"}
|
package/index.jsx
ADDED
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
import React, { useEffect, useRef } from 'react';
|
|
2
|
+
import { Input, Select, Button } from 'antd';
|
|
3
|
+
import { SearchOutlined } from '@ant-design/icons';
|
|
4
|
+
import { AgGridReact } from 'ag-grid-react';
|
|
5
|
+
import 'ag-grid-community/styles/ag-grid.css';
|
|
6
|
+
import 'ag-grid-community/styles/ag-theme-alpine.css';
|
|
7
|
+
import { useAtom } from 'jotai';
|
|
8
|
+
import DraggableModal from '@bit.rhplus/draggable-modal';
|
|
9
|
+
import { recentItemsAtomFamily } from './store/recentItemsStore';
|
|
10
|
+
import { useModuleDropdownList } from './useModuleDropdownList';
|
|
11
|
+
import './ModuleInput.css';
|
|
12
|
+
|
|
13
|
+
const { Option } = Select;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* ModuleDropdownList komponenta pro výběr položek z různých modulů
|
|
17
|
+
*/
|
|
18
|
+
const ModuleDropdownList = (props) => {
|
|
19
|
+
const {
|
|
20
|
+
value,
|
|
21
|
+
onChange,
|
|
22
|
+
placeholder = 'Vyberte...',
|
|
23
|
+
disabled = false,
|
|
24
|
+
readOnly = false,
|
|
25
|
+
style = {},
|
|
26
|
+
width,
|
|
27
|
+
maxRecentItems = 5,
|
|
28
|
+
moduleDefinition,
|
|
29
|
+
} = props;
|
|
30
|
+
|
|
31
|
+
// Interní stavy pro Select
|
|
32
|
+
const containerRef = useRef(null);
|
|
33
|
+
|
|
34
|
+
const processedStyle =
|
|
35
|
+
typeof style === 'string' ? { width: style } : { ...style };
|
|
36
|
+
|
|
37
|
+
// Priorita nastavení šířky: 1. prop width, 2. style.width, 3. defaultní 100%
|
|
38
|
+
if (width) {
|
|
39
|
+
processedStyle.width = width;
|
|
40
|
+
} else if (!processedStyle.width) {
|
|
41
|
+
processedStyle.width = '100%';
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Použití Jotai atom pro poslední vybrané položky daného typu modulu
|
|
45
|
+
const [recentItems, setRecentItems] = useAtom(
|
|
46
|
+
recentItemsAtomFamily(moduleDefinition?.moduleName || '')
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
// Přidání položky do seznamu nedávných položek
|
|
50
|
+
const addToRecentItems = (item) => {
|
|
51
|
+
if (!item || !moduleDefinition) return;
|
|
52
|
+
|
|
53
|
+
// Vytvoření nového seznamu bez aktuální položky (pokud existuje)
|
|
54
|
+
const filteredItems = recentItems.filter(
|
|
55
|
+
(existingItem) =>
|
|
56
|
+
existingItem[moduleDefinition.valueField || 'id'] !==
|
|
57
|
+
item[moduleDefinition.valueField || 'id']
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
// Přidání nové položky na začátek a omezení počtu položek
|
|
61
|
+
const updatedItems = [item, ...filteredItems].slice(0, maxRecentItems);
|
|
62
|
+
setRecentItems(updatedItems);
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
// Použití custom hooku pro veškerou logiku ModuleInput
|
|
66
|
+
const {
|
|
67
|
+
modalOpen,
|
|
68
|
+
searchQuery,
|
|
69
|
+
rowData,
|
|
70
|
+
isLoading,
|
|
71
|
+
selectedItem,
|
|
72
|
+
isDetailLoading,
|
|
73
|
+
moduleDetailQuery,
|
|
74
|
+
openModal,
|
|
75
|
+
closeModal,
|
|
76
|
+
handleSearchChange,
|
|
77
|
+
handleItemSelect,
|
|
78
|
+
clearSelection,
|
|
79
|
+
getDisplayValue,
|
|
80
|
+
} = useModuleDropdownList({ moduleDefinition, value });
|
|
81
|
+
|
|
82
|
+
const selectItem = (item) => {
|
|
83
|
+
const selectedItemData = handleItemSelect(item);
|
|
84
|
+
|
|
85
|
+
// Uložení vybrané položky do nedávných položek
|
|
86
|
+
if (selectedItemData) {
|
|
87
|
+
addToRecentItems(selectedItemData);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Přímé volání onChange s novou hodnotou
|
|
91
|
+
if (typeof onChange === 'function' && moduleDefinition) {
|
|
92
|
+
onChange(selectedItemData[moduleDefinition.valueField || 'id']);
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
// Přidání vybrané položky do nedávných položek při načtení
|
|
97
|
+
useEffect(() => {
|
|
98
|
+
if (selectedItem && moduleDefinition) {
|
|
99
|
+
addToRecentItems(selectedItem);
|
|
100
|
+
}
|
|
101
|
+
}, [selectedItem, moduleDefinition, addToRecentItems]);
|
|
102
|
+
|
|
103
|
+
// Výběr položky přímo ze Select dropdown
|
|
104
|
+
const handleSelectChange = (selectedId) => {
|
|
105
|
+
// Přímé volání onChange
|
|
106
|
+
if (typeof onChange === 'function') {
|
|
107
|
+
onChange(selectedId);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (!selectedId) {
|
|
111
|
+
clearSelection();
|
|
112
|
+
} else {
|
|
113
|
+
// Pokud je v nedávných položkách, nastavte ji jako vybranou
|
|
114
|
+
const selectedRecentItem = recentItems.find(
|
|
115
|
+
(item) => item[moduleDefinition?.valueField || 'id'] === selectedId
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
if (selectedRecentItem) {
|
|
119
|
+
handleItemSelect(selectedRecentItem);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
// Formátování nedávných položek pro zobrazení v Select
|
|
125
|
+
const recentItemsOptions = recentItems.map((item) => ({
|
|
126
|
+
id: item[moduleDefinition.valueField || 'id'],
|
|
127
|
+
name: moduleDefinition?.getDisplayValue?.(item) || item.name || item.id,
|
|
128
|
+
fullItem: item, // Uchování celé položky pro snadné získání později
|
|
129
|
+
}));
|
|
130
|
+
|
|
131
|
+
// Pokud nemáme definici modulu, zobrazíme prázdné pole
|
|
132
|
+
if (!moduleDefinition) return <div />;
|
|
133
|
+
|
|
134
|
+
// Funkce pro výběr položky a zavření modálu
|
|
135
|
+
const handleModalItemSelect = (event) => {
|
|
136
|
+
selectItem(event.data);
|
|
137
|
+
closeModal();
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
// Získání aktuální zobrazované hodnoty pro Select
|
|
141
|
+
const displayValueText = getDisplayValue();
|
|
142
|
+
|
|
143
|
+
return (
|
|
144
|
+
<div
|
|
145
|
+
className="module-input-container"
|
|
146
|
+
style={processedStyle}
|
|
147
|
+
ref={containerRef}
|
|
148
|
+
>
|
|
149
|
+
<div className="simple-select-container">
|
|
150
|
+
<Select
|
|
151
|
+
value={value}
|
|
152
|
+
onChange={handleSelectChange}
|
|
153
|
+
className="simple-select"
|
|
154
|
+
placeholder={placeholder}
|
|
155
|
+
disabled={disabled || readOnly}
|
|
156
|
+
dropdownMatchSelectWidth
|
|
157
|
+
getPopupContainer={() => containerRef.current}
|
|
158
|
+
// Vlastní tučná šipka s rotací
|
|
159
|
+
suffixIcon={
|
|
160
|
+
<svg
|
|
161
|
+
className="select-arrow-icon"
|
|
162
|
+
width="12"
|
|
163
|
+
height="12"
|
|
164
|
+
viewBox="0 0 12 12"
|
|
165
|
+
fill="none"
|
|
166
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
167
|
+
>
|
|
168
|
+
<path
|
|
169
|
+
d="M2 4L6 8L10 4"
|
|
170
|
+
stroke="#bfbfbf"
|
|
171
|
+
strokeWidth="2.5"
|
|
172
|
+
strokeLinecap="round"
|
|
173
|
+
strokeLinejoin="round"
|
|
174
|
+
/>
|
|
175
|
+
</svg>
|
|
176
|
+
}
|
|
177
|
+
// Zde definujeme, jak bude vypadat vybraná hodnota v selectu (pouze název)
|
|
178
|
+
optionLabelProp="label"
|
|
179
|
+
style={{ fontSize: '13px' }}
|
|
180
|
+
listItemHeight={32} // Upravená výška položek v seznamu
|
|
181
|
+
listHeight={256} // Upravená celková výška seznamu
|
|
182
|
+
dropdownRender={(menu) => (
|
|
183
|
+
<div className="select-dropdown-container">
|
|
184
|
+
<div className="search-box">
|
|
185
|
+
<Input
|
|
186
|
+
placeholder="Search"
|
|
187
|
+
prefix={<SearchOutlined />}
|
|
188
|
+
className="dropdown-search-input"
|
|
189
|
+
/>
|
|
190
|
+
</div>
|
|
191
|
+
{menu}
|
|
192
|
+
<div className="new-customer-item">
|
|
193
|
+
<div className="plus-icon">+</div>
|
|
194
|
+
<span>New Customer</span>
|
|
195
|
+
</div>
|
|
196
|
+
</div>
|
|
197
|
+
)}
|
|
198
|
+
>
|
|
199
|
+
{/* Seznam nedávných položek */}
|
|
200
|
+
{recentItemsOptions.map((option) => (
|
|
201
|
+
<Option
|
|
202
|
+
key={option.id}
|
|
203
|
+
value={option.id}
|
|
204
|
+
// Zde přidáváme label pro zobrazení jen názvu při vybrání položky
|
|
205
|
+
label={option.name}
|
|
206
|
+
>
|
|
207
|
+
<div className="option-item">
|
|
208
|
+
<div className="option-avatar">{option.name.charAt(0)}</div>
|
|
209
|
+
<div className="option-content">
|
|
210
|
+
<div className="option-name">{option.name}</div>
|
|
211
|
+
<div className="option-email">
|
|
212
|
+
{option.fullItem.email || '-'}
|
|
213
|
+
</div>
|
|
214
|
+
</div>
|
|
215
|
+
</div>
|
|
216
|
+
</Option>
|
|
217
|
+
))}
|
|
218
|
+
|
|
219
|
+
{/* Pokud máme vybranou hodnotu, která není v nedávných položkách */}
|
|
220
|
+
{value &&
|
|
221
|
+
!recentItemsOptions.some((option) => option.id === value) && (
|
|
222
|
+
<Option key={value} value={value} label={displayValueText}>
|
|
223
|
+
{isDetailLoading
|
|
224
|
+
? 'Načítání...'
|
|
225
|
+
: moduleDetailQuery?.data
|
|
226
|
+
? (
|
|
227
|
+
<div className="option-item">
|
|
228
|
+
<div className="option-avatar">
|
|
229
|
+
{displayValueText.charAt(0)}
|
|
230
|
+
</div>
|
|
231
|
+
<div className="option-content">
|
|
232
|
+
<div className="option-name">{displayValueText}</div>
|
|
233
|
+
<div className="option-email">
|
|
234
|
+
{moduleDetailQuery.data.email || '-'}
|
|
235
|
+
</div>
|
|
236
|
+
</div>
|
|
237
|
+
</div>
|
|
238
|
+
) : (
|
|
239
|
+
`${value} (nenačteno)`
|
|
240
|
+
)}
|
|
241
|
+
</Option>
|
|
242
|
+
)}
|
|
243
|
+
</Select>
|
|
244
|
+
|
|
245
|
+
<Button
|
|
246
|
+
icon={<SearchOutlined />}
|
|
247
|
+
className="search-button"
|
|
248
|
+
onClick={openModal}
|
|
249
|
+
type="primary"
|
|
250
|
+
/>
|
|
251
|
+
</div>
|
|
252
|
+
|
|
253
|
+
{/* DraggableModal pro zobrazení tabulky */}
|
|
254
|
+
<div id="modal-root" />
|
|
255
|
+
<DraggableModal
|
|
256
|
+
width={moduleDefinition.modalWidth || 800}
|
|
257
|
+
open={modalOpen}
|
|
258
|
+
getContainer={() => document.getElementById('modal-root')}
|
|
259
|
+
onCancel={closeModal}
|
|
260
|
+
maskClosable={false}
|
|
261
|
+
title={
|
|
262
|
+
moduleDefinition.modalTitle ||
|
|
263
|
+
`Vybrat z modulu: ${moduleDefinition.moduleName}`
|
|
264
|
+
}
|
|
265
|
+
footer={() => {
|
|
266
|
+
return [
|
|
267
|
+
<Button
|
|
268
|
+
key="cancel"
|
|
269
|
+
onClick={closeModal}
|
|
270
|
+
style={{ marginRight: '10px', width: 'auto' }}
|
|
271
|
+
>
|
|
272
|
+
Zavřít
|
|
273
|
+
</Button>,
|
|
274
|
+
];
|
|
275
|
+
}}
|
|
276
|
+
>
|
|
277
|
+
<Input
|
|
278
|
+
placeholder="Vyhledat..."
|
|
279
|
+
value={searchQuery}
|
|
280
|
+
onChange={(e) => handleSearchChange(e.target.value)}
|
|
281
|
+
prefix={<SearchOutlined />}
|
|
282
|
+
allowClear
|
|
283
|
+
/>
|
|
284
|
+
|
|
285
|
+
{isLoading ? (
|
|
286
|
+
<div className="text-align-center padding">Načítání...</div>
|
|
287
|
+
) : (
|
|
288
|
+
<div
|
|
289
|
+
className="ag-theme-alpine"
|
|
290
|
+
style={{ height: 400, width: '100%' }}
|
|
291
|
+
>
|
|
292
|
+
<AgGridReact
|
|
293
|
+
rowData={rowData}
|
|
294
|
+
columnDefs={moduleDefinition.columnDefs}
|
|
295
|
+
defaultColDef={{
|
|
296
|
+
sortable: true,
|
|
297
|
+
filter: true,
|
|
298
|
+
resizable: true,
|
|
299
|
+
}}
|
|
300
|
+
pagination
|
|
301
|
+
paginationPageSize={10}
|
|
302
|
+
onRowClicked={handleModalItemSelect}
|
|
303
|
+
rowSelection="single"
|
|
304
|
+
/>
|
|
305
|
+
</div>
|
|
306
|
+
)}
|
|
307
|
+
</DraggableModal>
|
|
308
|
+
</div>
|
|
309
|
+
);
|
|
310
|
+
};
|
|
311
|
+
|
|
312
|
+
export default ModuleDropdownList;
|
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@bit.rhplus/ui2.module-dropdown-list",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"main": "dist/index.js",
|
|
5
|
+
"componentId": {
|
|
6
|
+
"name": "ui2/module-dropdown-list",
|
|
7
|
+
"version": "0.0.1",
|
|
8
|
+
"scope": "remote-scope"
|
|
9
|
+
},
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"@ant-design/icons": "^5.4.0",
|
|
12
|
+
"ag-grid-community": "^31.3.4",
|
|
13
|
+
"ag-grid-react": "^31.3.4",
|
|
14
|
+
"antd": "^5.20.6",
|
|
15
|
+
"jotai": "^2.11.1",
|
|
16
|
+
"@tanstack/react-query": "^5.66.9",
|
|
17
|
+
"@bit.rhplus/draggable-modal": "0.0.4",
|
|
18
|
+
"@bit.rhplus/data": "0.0.9"
|
|
19
|
+
},
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"@teambit/react.react-env": "1.0.129"
|
|
22
|
+
},
|
|
23
|
+
"peerDependencies": {
|
|
24
|
+
"react": "^17.0.0 || ^18.0.0"
|
|
25
|
+
},
|
|
26
|
+
"license": "SEE LICENSE IN UNLICENSED",
|
|
27
|
+
"optionalDependencies": {},
|
|
28
|
+
"peerDependenciesMeta": {},
|
|
29
|
+
"private": false,
|
|
30
|
+
"publishConfig": {
|
|
31
|
+
"scope": "@bit.rhplus",
|
|
32
|
+
"registry": "https://registry.npmjs.org/"
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { atom } from 'jotai';
|
|
2
|
+
import { atomFamily, atomWithStorage } from 'jotai/utils';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Atom family pro uchovávání posledních vybraných položek pro každý typ modulu
|
|
6
|
+
* Používá localStorage pro persistenci dat mezi reloady stránky
|
|
7
|
+
*/
|
|
8
|
+
export const recentItemsAtomFamily = atomFamily(
|
|
9
|
+
(moduleType) => atomWithStorage(`recent-items-${moduleType}`, []),
|
|
10
|
+
(a, b) => a === b
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Helper funkce pro vymazání všech uložených posledních položek
|
|
15
|
+
* pro konkrétní modul
|
|
16
|
+
*
|
|
17
|
+
* @param {string} moduleType - Typ modulu
|
|
18
|
+
* @param {Function} setAtom - Setter funkce pro daný atom
|
|
19
|
+
*/
|
|
20
|
+
export const clearRecentItems = (moduleType, setAtom) => {
|
|
21
|
+
setAtom(recentItemsAtomFamily(moduleType), []);
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Helper atom pro vývojářské účely - seznam všech typů modulů,
|
|
26
|
+
* které mají uložené nedávné položky
|
|
27
|
+
*/
|
|
28
|
+
export const moduleTypesWithRecentItemsAtom = atom((get) => {
|
|
29
|
+
// Tato funkce by v produkční verzi potřebovala skutečný seznam
|
|
30
|
+
// všech modulů, což by bylo potřeba implementovat dle
|
|
31
|
+
// konkrétních požadavků aplikace
|
|
32
|
+
const moduleTypes = ['products', 'contracts'];
|
|
33
|
+
|
|
34
|
+
return moduleTypes.filter(moduleType =>
|
|
35
|
+
get(recentItemsAtomFamily(moduleType)).length > 0
|
|
36
|
+
);
|
|
37
|
+
});
|
package/types/asset.d.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
declare module '*.png' {
|
|
2
|
+
const value: any;
|
|
3
|
+
export = value;
|
|
4
|
+
}
|
|
5
|
+
declare module '*.svg' {
|
|
6
|
+
import type { FunctionComponent, SVGProps } from 'react';
|
|
7
|
+
|
|
8
|
+
export const ReactComponent: FunctionComponent<
|
|
9
|
+
SVGProps<SVGSVGElement> & { title?: string }
|
|
10
|
+
>;
|
|
11
|
+
const src: string;
|
|
12
|
+
export default src;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// @TODO Gilad
|
|
16
|
+
declare module '*.jpg' {
|
|
17
|
+
const value: any;
|
|
18
|
+
export = value;
|
|
19
|
+
}
|
|
20
|
+
declare module '*.jpeg' {
|
|
21
|
+
const value: any;
|
|
22
|
+
export = value;
|
|
23
|
+
}
|
|
24
|
+
declare module '*.gif' {
|
|
25
|
+
const value: any;
|
|
26
|
+
export = value;
|
|
27
|
+
}
|
|
28
|
+
declare module '*.bmp' {
|
|
29
|
+
const value: any;
|
|
30
|
+
export = value;
|
|
31
|
+
}
|
|
32
|
+
declare module '*.otf' {
|
|
33
|
+
const value: any;
|
|
34
|
+
export = value;
|
|
35
|
+
}
|
|
36
|
+
declare module '*.woff' {
|
|
37
|
+
const value: any;
|
|
38
|
+
export = value;
|
|
39
|
+
}
|
|
40
|
+
declare module '*.woff2' {
|
|
41
|
+
const value: any;
|
|
42
|
+
export = value;
|
|
43
|
+
}
|
package/types/style.d.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
declare module '*.module.css' {
|
|
2
|
+
const classes: { readonly [key: string]: string };
|
|
3
|
+
export default classes;
|
|
4
|
+
}
|
|
5
|
+
declare module '*.module.scss' {
|
|
6
|
+
const classes: { readonly [key: string]: string };
|
|
7
|
+
export default classes;
|
|
8
|
+
}
|
|
9
|
+
declare module '*.module.sass' {
|
|
10
|
+
const classes: { readonly [key: string]: string };
|
|
11
|
+
export default classes;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
declare module '*.module.less' {
|
|
15
|
+
const classes: { readonly [key: string]: string };
|
|
16
|
+
export default classes;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
declare module '*.less' {
|
|
20
|
+
const classes: { readonly [key: string]: string };
|
|
21
|
+
export default classes;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
declare module '*.css' {
|
|
25
|
+
const classes: { readonly [key: string]: string };
|
|
26
|
+
export default classes;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
declare module '*.sass' {
|
|
30
|
+
const classes: { readonly [key: string]: string };
|
|
31
|
+
export default classes;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
declare module '*.scss' {
|
|
35
|
+
const classes: { readonly [key: string]: string };
|
|
36
|
+
export default classes;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
declare module '*.mdx' {
|
|
40
|
+
const component: any;
|
|
41
|
+
export default component;
|
|
42
|
+
}
|