@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.
@@ -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":"AAAA,iCAAiC;AACjC,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AACzD,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACjD,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAC/B,OAAO,OAAO,MAAM,kBAAkB,CAAC,CAAC,0CAA0C;AAElF,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,EAAE,gBAAgB,EAAE,KAAK,EAAE,EAAE,EAAE;IACnE,gBAAgB;IAChB,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAClD,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;IACnD,MAAM,CAAC,YAAY,EAAE,eAAe,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IACvD,kEAAkE;IAClE,iDAAiD;IACjD,MAAM,EAAE,gBAAgB,EAAE,GAAG,OAAO,EAAE,CAAC;IAEvC,wEAAwE;IACxE,MAAM,SAAS,GAAG,WAAW,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;QAC5C,IAAI,gBAAgB,EAAE,SAAS,EAAE,CAAC;YAChC,OAAO,gBAAgB,CAAC,SAAS,CAAC,KAAK,EAAE,gBAAgB,CAAC,CAAC;QAC7D,CAAC;QACD,OAAO,EAAE,CAAC;IACZ,CAAC,EAAE,CAAC,gBAAgB,EAAE,gBAAgB,CAAC,CAAC,CAAC;IAEzC,MAAM,SAAS,GAAG,WAAW,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE;QACzC,IAAI,gBAAgB,EAAE,SAAS,EAAE,CAAC;YAChC,OAAO,gBAAgB,CAAC,SAAS,CAAC,EAAE,EAAE,gBAAgB,CAAC,CAAC;QAC1D,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC,EAAE,CAAC,gBAAgB,EAAE,gBAAgB,CAAC,CAAC,CAAC;IAEzC,8CAA8C;IAC9C,MAAM,eAAe,GAAG,QAAQ,CAAC;QAC/B,QAAQ,EAAE,CAAC,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,WAAW,CAAC;QAC5D,OAAO,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,WAAW,CAAC;QACrC,OAAO,EAAE,CAAC,CAAC,gBAAgB,IAAI,SAAS;QACxC,SAAS,EAAE,IAAI,GAAG,EAAE,GAAG,CAAC,EAAE,UAAU;QACpC,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;YACjB,OAAO,CAAC,KAAK,CAAC,2BAA2B,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QAC5D,CAAC;KACF,CAAC,CAAC;IAEH,2DAA2D;IAC3D,MAAM,iBAAiB,GAAG,QAAQ,CAAC;QACjC,QAAQ,EAAE,CAAC,gBAAgB,CAAC,UAAU,EAAE,QAAQ,EAAE,KAAK,CAAC;QACxD,OAAO,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC;QAC/B,mFAAmF;QACnF,OAAO,EAAE,CAAC,CAAC,gBAAgB,IAAI,CAAC,CAAC,KAAK,IAAI,KAAK,KAAK,EAAE;QACtD,SAAS,EAAE,IAAI,GAAG,EAAE,GAAG,CAAC,EAAE,UAAU;QACpC,SAAS,EAAE,CAAC,IAAI,EAAE,EAAE;YAClB,IAAI,IAAI;gBAAE,eAAe,CAAC,IAAI,CAAC,CAAC;QAClC,CAAC;QACD,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;YACjB,OAAO,CAAC,KAAK,CAAC,+BAA+B,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QAChE,CAAC;KACF,CAAC,CAAC;IAEH,qCAAqC;IACrC,MAAM,SAAS,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;IAE3C,oCAAoC;IACpC,MAAM,UAAU,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;IAE7C,wCAAwC;IACxC,MAAM,kBAAkB,GAAG,CAAC,KAAK,EAAE,EAAE,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;IAE5D,2BAA2B;IAC3B,MAAM,gBAAgB,GAAG,CAAC,IAAI,EAAE,EAAE;QAChC,IAAI,IAAI,EAAE,CAAC;YACT,eAAe,CAAC,IAAI,CAAC,CAAC;YACtB,UAAU,EAAE,CAAC;YACb,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC,CAAC;IAEF,6BAA6B;IAC7B,MAAM,cAAc,GAAG,GAAG,EAAE;QAC1B,eAAe,CAAC,IAAI,CAAC,CAAC;IACxB,CAAC,CAAC;IAEF,mDAAmD;IACnD,MAAM,eAAe,GAAG,GAAG,EAAE;QAC3B,IAAI,CAAC,KAAK,IAAI,CAAC,gBAAgB;YAAE,OAAO,EAAE,CAAC;QAE3C,4CAA4C;QAC5C,IAAI,YAAY,IAAI,YAAY,CAAC,gBAAgB,CAAC,UAAU,CAAC,KAAK,KAAK,EAAE,CAAC;YACxE,OAAO,gBAAgB,CAAC,eAAe,CAAC,YAAY,CAAC,CAAC;QACxD,CAAC;QAED,yEAAyE;QACzE,IAAI,iBAAiB,CAAC,IAAI,EAAE,CAAC;YAC3B,OAAO,gBAAgB,CAAC,eAAe,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;QAClE,CAAC;QAED,yBAAyB;QACzB,IAAI,iBAAiB,CAAC,SAAS,EAAE,CAAC;YAChC,OAAO,aAAa,CAAC;QACvB,CAAC;QAED,gDAAgD;QAChD,OAAO,GAAG,KAAK,cAAc,CAAC;IAChC,CAAC,CAAC;IAEF,8CAA8C;IAC9C,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,KAAK,KAAK,YAAY,EAAE,CAAC,gBAAgB,EAAE,UAAU,CAAC,EAAE,CAAC;YAC3D,gEAAgE;YAChE,eAAe,CAAC,IAAI,CAAC,CAAC;QACxB,CAAC;IACH,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,EAAE,gBAAgB,CAAC,CAAC,CAAC;IAE5C,wDAAwD;IACxD,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,SAAS,IAAI,gBAAgB,EAAE,CAAC;YAClC,eAAe,CAAC,OAAO,EAAE,CAAC;QAC5B,CAAC;IACH,CAAC,EAAE,CAAC,SAAS,EAAE,WAAW,EAAE,gBAAgB,EAAE,eAAe,CAAC,CAAC,CAAC;IAEhE,0CAA0C;IAC1C,OAAO;QACL,QAAQ;QACR,gBAAgB;QAChB,SAAS;QACT,WAAW;QACX,YAAY;QACZ,OAAO,EAAE,eAAe,CAAC,IAAI,IAAI,EAAE;QACnC,SAAS,EAAE,eAAe,CAAC,SAAS;QACpC,eAAe,EAAE,iBAAiB,CAAC,SAAS;QAE5C,SAAS;QACT,SAAS;QACT,UAAU;QACV,kBAAkB;QAClB,gBAAgB;QAChB,cAAc;QACd,eAAe;QAEf,sCAAsC;QACtC,eAAe;QACf,iBAAiB;KAClB,CAAC;AACJ,CAAC,CAAC"}
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
+ });
@@ -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
+ }
@@ -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
+ }