groovinads-ui 1.2.57 → 1.2.58
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/README.md +179 -76
- package/dist/index.es.js +4 -4
- package/dist/index.js +3 -3
- package/package.json +1 -1
- package/src/components/Button/Button.jsx +13 -25
- package/src/components/Dropdowns/DropdownSimpleDatePicker.jsx +135 -137
- package/src/components/Dropdowns/DropdownsDatePicker/DropdownDatePicker.jsx +6 -6
- package/src/components/Inputs/InputChip.jsx +149 -0
- package/src/components/Inputs/index.js +2 -1
- package/src/components/Navigation/Sidebar.jsx +27 -16
- package/src/components/Toasts/Toast/ToastCardComponent.jsx +0 -2
- package/src/stories/Button.stories.jsx +16 -4
- package/src/stories/DropdownDatePicker.stories.jsx +19 -2
- package/src/stories/DropdownSimpleDatePicker.stories.jsx +22 -19
- package/src/stories/InputChip.stories.jsx +46 -0
- package/src/stories/PillComponent.stories.jsx +4 -1
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "groovinads-ui",
|
|
3
3
|
"description": "Groovinads UI is a React component library designed exclusively for Groovinads applications. It provides ready-to-use UI elements styled according to Groovinads design guidelines to facilitate rapid development.",
|
|
4
|
-
"version": "1.2.
|
|
4
|
+
"version": "1.2.58",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"css",
|
|
7
7
|
"sass",
|
|
@@ -14,31 +14,10 @@ const Button = ({
|
|
|
14
14
|
className = '',
|
|
15
15
|
style = 'default',
|
|
16
16
|
processing = false,
|
|
17
|
+
disabled = false,
|
|
17
18
|
}) => {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
// Variant
|
|
21
|
-
if (variant !== 'default') {
|
|
22
|
-
classes += ` btn-${variant}`;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
// Size
|
|
26
|
-
if (size !== 'md') {
|
|
27
|
-
classes += ` btn-${size}`;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// Style
|
|
31
|
-
if (style !== 'default') {
|
|
32
|
-
classes += ` btn-${style}`;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// Processing
|
|
36
|
-
if (processing) {
|
|
37
|
-
classes += ` btn-processing`;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// Icon
|
|
41
|
-
const content = processing ? (
|
|
19
|
+
// Icon
|
|
20
|
+
const content = processing ? (
|
|
42
21
|
<>
|
|
43
22
|
<Spinner scale={1} />
|
|
44
23
|
{children && <span>{children}…</span>}
|
|
@@ -68,7 +47,16 @@ const content = processing ? (
|
|
|
68
47
|
);
|
|
69
48
|
|
|
70
49
|
return (
|
|
71
|
-
<button
|
|
50
|
+
<button
|
|
51
|
+
className={
|
|
52
|
+
`btn ${className}
|
|
53
|
+
btn-${variant}
|
|
54
|
+
btn-${style}
|
|
55
|
+
${processing ? 'btn-processing' : ''}
|
|
56
|
+
${disabled ? 'disabled' : ''}`
|
|
57
|
+
}
|
|
58
|
+
onClick={onClick}
|
|
59
|
+
>
|
|
72
60
|
{content}
|
|
73
61
|
</button>
|
|
74
62
|
);
|
|
@@ -1,150 +1,148 @@
|
|
|
1
1
|
import PropTypes from 'prop-types';
|
|
2
|
-
import React, { useEffect, useRef, useState } from 'react'
|
|
2
|
+
import React, { useEffect, useRef, useState } from 'react';
|
|
3
3
|
import { format } from 'date-fns';
|
|
4
4
|
|
|
5
5
|
// COMPONENTS
|
|
6
|
-
import { Dropdown } from 'react-bootstrap'
|
|
6
|
+
import { Dropdown } from 'react-bootstrap';
|
|
7
7
|
import { Icon } from '../Labels';
|
|
8
8
|
import { Button } from '../Button';
|
|
9
9
|
import DatePicker from 'react-datepicker';
|
|
10
10
|
|
|
11
|
-
|
|
12
11
|
export default function DropdownSimpleDatePicker({
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
12
|
+
className = '',
|
|
13
|
+
show,
|
|
14
|
+
setShow,
|
|
15
|
+
onToggle,
|
|
16
|
+
inputLabel = 'period',
|
|
17
|
+
overflow = false,
|
|
18
|
+
date,
|
|
19
|
+
setDate,
|
|
20
|
+
handleClear,
|
|
21
|
+
minDate,
|
|
22
|
+
maxDate,
|
|
22
23
|
}) {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
</div>
|
|
133
|
-
</Dropdown.Item>
|
|
134
|
-
</Dropdown.Menu>
|
|
135
|
-
</Dropdown>
|
|
136
|
-
)
|
|
24
|
+
const [internalShow, setInternalShow] = useState(!!show);
|
|
25
|
+
const dropdownRef = useRef(null);
|
|
26
|
+
|
|
27
|
+
const internalToggle = () => {
|
|
28
|
+
const newShowState = !internalShow;
|
|
29
|
+
setInternalShow(newShowState);
|
|
30
|
+
|
|
31
|
+
if (newShowState)
|
|
32
|
+
window.dispatchEvent(
|
|
33
|
+
new CustomEvent('dropdownToggle', { detail: inputLabel }),
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
try {
|
|
37
|
+
onToggle();
|
|
38
|
+
} catch (error) {}
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const closeDropdown = () => {
|
|
42
|
+
setInternalShow(false);
|
|
43
|
+
try {
|
|
44
|
+
setShow(false);
|
|
45
|
+
} catch (error) {}
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const updateDateFilters = (newDate) => {
|
|
49
|
+
setDate(newDate?.toString());
|
|
50
|
+
setTimeout(() => {
|
|
51
|
+
closeDropdown();
|
|
52
|
+
}, 200);
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const clearDate = () => {
|
|
56
|
+
closeDropdown();
|
|
57
|
+
|
|
58
|
+
if (handleClear) {
|
|
59
|
+
handleClear();
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
setDate(null);
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
useEffect(() => {
|
|
66
|
+
const handleClickOutside = (event) => {
|
|
67
|
+
if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
|
|
68
|
+
closeDropdown();
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
document.addEventListener('click', handleClickOutside);
|
|
73
|
+
return () => {
|
|
74
|
+
document.removeEventListener('click', handleClickOutside);
|
|
75
|
+
};
|
|
76
|
+
}, []);
|
|
77
|
+
|
|
78
|
+
useEffect(() => {
|
|
79
|
+
setInternalShow(!!show);
|
|
80
|
+
}, [show]);
|
|
81
|
+
|
|
82
|
+
return (
|
|
83
|
+
<Dropdown show={internalShow} className={className} ref={dropdownRef}>
|
|
84
|
+
<Dropdown.Toggle
|
|
85
|
+
variant='toggle-filter'
|
|
86
|
+
onClick={internalToggle}
|
|
87
|
+
className={`btn-input w-100`}
|
|
88
|
+
>
|
|
89
|
+
<span className='dropdown-label'>{inputLabel}</span>
|
|
90
|
+
<span>{date ? format(new Date(date), 'EEE MMM dd yyyy') : ''}</span>
|
|
91
|
+
|
|
92
|
+
<Icon iconName='angle-down' className={'caret'} />
|
|
93
|
+
</Dropdown.Toggle>
|
|
94
|
+
|
|
95
|
+
<Dropdown.Menu
|
|
96
|
+
popperConfig={
|
|
97
|
+
overflow
|
|
98
|
+
? {
|
|
99
|
+
strategy: 'fixed',
|
|
100
|
+
onFirstUpdate: () =>
|
|
101
|
+
window.dispatchEvent(new CustomEvent('scroll')),
|
|
102
|
+
}
|
|
103
|
+
: undefined
|
|
104
|
+
}
|
|
105
|
+
>
|
|
106
|
+
<Dropdown.Item as={'div'}>
|
|
107
|
+
<DatePicker
|
|
108
|
+
className='form-control form-search'
|
|
109
|
+
selected={date || ''}
|
|
110
|
+
onChange={updateDateFilters}
|
|
111
|
+
startDate={date || ''}
|
|
112
|
+
monthsShown={1}
|
|
113
|
+
inline
|
|
114
|
+
minDate={minDate}
|
|
115
|
+
maxDate={maxDate}
|
|
116
|
+
/>
|
|
117
|
+
|
|
118
|
+
<div className='px-2 w-100'>
|
|
119
|
+
<Button
|
|
120
|
+
onClick={clearDate}
|
|
121
|
+
icon='calendar-circle-minus'
|
|
122
|
+
size='xs'
|
|
123
|
+
variant='terciary'
|
|
124
|
+
className='w-100'
|
|
125
|
+
>
|
|
126
|
+
Clear
|
|
127
|
+
</Button>
|
|
128
|
+
</div>
|
|
129
|
+
</Dropdown.Item>
|
|
130
|
+
</Dropdown.Menu>
|
|
131
|
+
</Dropdown>
|
|
132
|
+
);
|
|
137
133
|
}
|
|
138
134
|
|
|
139
135
|
DropdownSimpleDatePicker.propTypes = {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
136
|
+
className: PropTypes.string,
|
|
137
|
+
show: PropTypes.bool,
|
|
138
|
+
setShow: PropTypes.func,
|
|
139
|
+
onToggle: PropTypes.func,
|
|
140
|
+
inputLabel: PropTypes.string,
|
|
141
|
+
overflow: PropTypes.bool,
|
|
142
|
+
date: PropTypes.string,
|
|
143
|
+
setDate: PropTypes.func,
|
|
144
|
+
clearDate: PropTypes.func,
|
|
145
|
+
handleClear: PropTypes.func,
|
|
146
|
+
minDate: PropTypes.object,
|
|
147
|
+
maxDate: PropTypes.object,
|
|
148
|
+
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, {
|
|
1
|
+
import React, { useEffect, useState } from 'react';
|
|
2
2
|
import DatePicker from 'react-datepicker'; // https://reactdatepicker.com
|
|
3
3
|
import PropTypes from 'prop-types';
|
|
4
4
|
import Dropdown from 'react-bootstrap/Dropdown';
|
|
@@ -6,9 +6,6 @@ import Dropdown from 'react-bootstrap/Dropdown';
|
|
|
6
6
|
// COMPONENTS
|
|
7
7
|
import { Icon } from '../../Labels';
|
|
8
8
|
import { Button } from '../../Button';
|
|
9
|
-
import { Switch } from '../../Inputs';
|
|
10
|
-
import { Tabnav } from '../../Navigation';
|
|
11
|
-
// import PeriodAndDetailDropdowns from './PeriodAndDetailDropdowns';
|
|
12
9
|
|
|
13
10
|
// HOOKS
|
|
14
11
|
import { useTextFormatter } from '../../../hooks';
|
|
@@ -31,12 +28,13 @@ const DropdownDatePicker = ({
|
|
|
31
28
|
setDateFrom2,
|
|
32
29
|
dateTo2,
|
|
33
30
|
setDateTo2,
|
|
31
|
+
minDate,
|
|
32
|
+
maxDate,
|
|
34
33
|
}) => {
|
|
35
|
-
//const [activeTab, setActiveTab] = useState(1);
|
|
34
|
+
// const [activeTab, setActiveTab] = useState(1);
|
|
36
35
|
|
|
37
36
|
const [compareDates, setCompareDates] = useState(true);
|
|
38
37
|
|
|
39
|
-
|
|
40
38
|
/* We have a 'local' state for datepickers inside the dropdown, so the user can cancel the dropdown and go back to previous values. */
|
|
41
39
|
/* When user confirms selected values, the 'local' state replaces the values previously stored in the DateFilters component. */
|
|
42
40
|
/* ========== STATE FOR DATEPCIKER 1 ========== */
|
|
@@ -252,6 +250,8 @@ const DropdownDatePicker = ({
|
|
|
252
250
|
monthsShown={isMobile ? 1 : 2}
|
|
253
251
|
selectsRange
|
|
254
252
|
inline
|
|
253
|
+
minDate={minDate}
|
|
254
|
+
maxDate={maxDate}
|
|
255
255
|
/>
|
|
256
256
|
|
|
257
257
|
<div className='datepicker-footer'>
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
|
|
4
|
+
// COMPONENTS
|
|
5
|
+
import { PillComponent } from '../Labels';
|
|
6
|
+
|
|
7
|
+
const InputChip = ({
|
|
8
|
+
className ='',
|
|
9
|
+
placeholder,
|
|
10
|
+
keywordsList = [],
|
|
11
|
+
setKeywordsList,
|
|
12
|
+
counter = false,
|
|
13
|
+
nonRecomendedKeywords = [],
|
|
14
|
+
maxKeywordLength, // max keyword length (each keyword).
|
|
15
|
+
recomendedKeywords, // Num recomendedKeywords.
|
|
16
|
+
maxKeywords, // maxKeywords (total array).
|
|
17
|
+
requiredText, // requiered--> maxKeywordsList.
|
|
18
|
+
|
|
19
|
+
}) => {
|
|
20
|
+
// STATE
|
|
21
|
+
const [inputValue, setInputValue] = useState('');
|
|
22
|
+
const [error, setError] = useState('');
|
|
23
|
+
|
|
24
|
+
// VARIABLES
|
|
25
|
+
const strokeDasharray = 56.55
|
|
26
|
+
|
|
27
|
+
// FUNCTIONS
|
|
28
|
+
// ADD
|
|
29
|
+
const handleKeyDown = (e) => {
|
|
30
|
+
if (
|
|
31
|
+
e.key === 'Enter' &&
|
|
32
|
+
inputValue.trim() !== ''
|
|
33
|
+
&& keywordsList.length < maxKeywords
|
|
34
|
+
) {
|
|
35
|
+
// MAX KEYWORD LENGTH
|
|
36
|
+
if (inputValue.length > maxKeywordLength) {
|
|
37
|
+
setError(`Each keyword must be ${maxKeywordLength} characters or less.`);
|
|
38
|
+
setTimeout(() => setError(''), 2000);
|
|
39
|
+
setInputValue('');
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const newChipsList = [...keywordsList, inputValue.trim()];
|
|
44
|
+
setKeywordsList(newChipsList);
|
|
45
|
+
setInputValue('');
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
// DELETE
|
|
50
|
+
const handleDelete = (chipToDelete) => {
|
|
51
|
+
const newChipsList = keywordsList.filter((chip) => chip !== chipToDelete);
|
|
52
|
+
setKeywordsList(newChipsList);
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
return (
|
|
56
|
+
<>
|
|
57
|
+
<div className={`position-relative ${className}`}>
|
|
58
|
+
<div className={`input-chip ${keywordsList.length === maxKeywords ? 'not-validated' : ''}`} data-error={requiredText}>
|
|
59
|
+
|
|
60
|
+
<div className='wrapper'>
|
|
61
|
+
{/* PILLS */}
|
|
62
|
+
{keywordsList.map((chip, index) => (
|
|
63
|
+
<PillComponent
|
|
64
|
+
key={index}
|
|
65
|
+
closeButton={true}
|
|
66
|
+
color={
|
|
67
|
+
nonRecomendedKeywords.includes(chip) ? 'danger' : 'green'
|
|
68
|
+
}
|
|
69
|
+
onClick={() => handleDelete(chip)}
|
|
70
|
+
>
|
|
71
|
+
{chip}
|
|
72
|
+
</PillComponent>
|
|
73
|
+
))}
|
|
74
|
+
</div>
|
|
75
|
+
|
|
76
|
+
{/* INPUT */}
|
|
77
|
+
<input
|
|
78
|
+
type='text'
|
|
79
|
+
value={inputValue}
|
|
80
|
+
onKeyDown={handleKeyDown}
|
|
81
|
+
onChange={(e) => {
|
|
82
|
+
setInputValue(e.target.value);
|
|
83
|
+
}}
|
|
84
|
+
placeholder={placeholder}
|
|
85
|
+
/>
|
|
86
|
+
|
|
87
|
+
{/* KEYWORDS COUNTER */}
|
|
88
|
+
{counter && keywordsList.length >= recomendedKeywords && (
|
|
89
|
+
<div className={`progress-counter-wrapper ${
|
|
90
|
+
keywordsList.length >= maxKeywords
|
|
91
|
+
? 'progress-value-error'
|
|
92
|
+
: keywordsList.length >= recomendedKeywords
|
|
93
|
+
? 'progress-value-warning'
|
|
94
|
+
: ''
|
|
95
|
+
}`}
|
|
96
|
+
>
|
|
97
|
+
<svg
|
|
98
|
+
width='20'
|
|
99
|
+
height='20'
|
|
100
|
+
viewBox='0 0 20 20'
|
|
101
|
+
xmlns='http://www.w3.org/2000/svg'
|
|
102
|
+
className='progress-counter'
|
|
103
|
+
>
|
|
104
|
+
<circle
|
|
105
|
+
className='progress-bg'
|
|
106
|
+
cx='10'
|
|
107
|
+
cy='10'
|
|
108
|
+
r='9'
|
|
109
|
+
fill='none'
|
|
110
|
+
/>
|
|
111
|
+
|
|
112
|
+
<circle
|
|
113
|
+
className='progress-value'
|
|
114
|
+
cx='10'
|
|
115
|
+
cy='10'
|
|
116
|
+
r='9'
|
|
117
|
+
strokeDasharray={strokeDasharray}
|
|
118
|
+
strokeDashoffset={strokeDasharray * (1 - keywordsList.length / maxKeywords)}
|
|
119
|
+
strokeLinecap='round'
|
|
120
|
+
fill='none'
|
|
121
|
+
/>
|
|
122
|
+
</svg>
|
|
123
|
+
<span className='progress-counter-text'>
|
|
124
|
+
{keywordsList.length}
|
|
125
|
+
</span>
|
|
126
|
+
</div>
|
|
127
|
+
)}
|
|
128
|
+
</div>
|
|
129
|
+
|
|
130
|
+
{/* ERROR MESSAGGE */}
|
|
131
|
+
{error && <small className='form-text text-muted'>{error}</small>}
|
|
132
|
+
</div>
|
|
133
|
+
</>
|
|
134
|
+
);
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
InputChip.propTypes = {
|
|
138
|
+
className: PropTypes.string,
|
|
139
|
+
placeholder: PropTypes.string.isRequired,
|
|
140
|
+
keywordsList: PropTypes.array.isRequired,
|
|
141
|
+
setKeywordsList: PropTypes.func.isRequired,
|
|
142
|
+
maxKeywordLength: PropTypes.number.isRequired,
|
|
143
|
+
nonRecomendedKeywords: PropTypes.array,
|
|
144
|
+
maxKeywords: PropTypes.number.isRequired,
|
|
145
|
+
requiredText: PropTypes.string.isRequired,
|
|
146
|
+
counter: PropTypes.bool,
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
export default InputChip;
|
|
@@ -3,5 +3,6 @@ import Input from './Input';
|
|
|
3
3
|
import Radio from './Radio';
|
|
4
4
|
import Switch from './Switch';
|
|
5
5
|
import Textarea from './Textarea';
|
|
6
|
+
import InputChip from './InputChip';
|
|
6
7
|
|
|
7
|
-
export { Checkbox, Input, Radio, Switch, Textarea }
|
|
8
|
+
export { Checkbox, Input, Radio, Switch, Textarea, InputChip };
|
|
@@ -21,11 +21,13 @@ const Sidebar = ({
|
|
|
21
21
|
onNavigate,
|
|
22
22
|
selectedClient,
|
|
23
23
|
showClients = false,
|
|
24
|
-
setGroovinProfile
|
|
24
|
+
setGroovinProfile,
|
|
25
|
+
inModal = false,
|
|
26
|
+
customUrl,
|
|
25
27
|
}) => {
|
|
26
|
-
const isMobile = useMediaQuery({ query: '(max-width: 992px)' });
|
|
28
|
+
const isMobile = inModal ? true : useMediaQuery({ query: '(max-width: 992px)' });
|
|
27
29
|
|
|
28
|
-
const url = window.location.pathname; // to get current url
|
|
30
|
+
const url = customUrl !== undefined ? customUrl : window.location.pathname; // to get current url
|
|
29
31
|
|
|
30
32
|
const [sidebarLinks, setSidebarLinks] = useState([]);
|
|
31
33
|
const [openIndex, setOpenIndex] = useState(null);
|
|
@@ -52,29 +54,33 @@ const Sidebar = ({
|
|
|
52
54
|
}, [show]);
|
|
53
55
|
|
|
54
56
|
useEffect(() => {
|
|
55
|
-
if (isMobile && setShow) setShow(innerShow);
|
|
56
|
-
setInnerShow(isMobile ? false : firstOpen.current ? defaultOpened : show);
|
|
57
|
+
if (isMobile && setShow && !inModal) setShow(innerShow);
|
|
58
|
+
if (!inModal) setInnerShow(isMobile ? false : firstOpen.current ? defaultOpened : show);
|
|
57
59
|
firstOpen.current = false;
|
|
58
60
|
}, []);
|
|
59
61
|
|
|
60
62
|
return (
|
|
61
63
|
<Collapse in={innerShow} dimension={'width'}>
|
|
62
64
|
<nav id='sidebarMenu' className='sidebar' ref={sidebarRef}>
|
|
63
|
-
|
|
64
|
-
<
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
65
|
+
{!inModal ? (
|
|
66
|
+
<div className='position-relative d-none d-lg-block'>
|
|
67
|
+
<button
|
|
68
|
+
className='collapse-button'
|
|
69
|
+
// Toggle the sidebar
|
|
70
|
+
onClick={() => setInnerShow((prev) => !prev)}
|
|
71
|
+
>
|
|
72
|
+
<Icon className='collapse-icon' iconName='chevron-left' />
|
|
73
|
+
</button>
|
|
74
|
+
</div>
|
|
75
|
+
) : (
|
|
76
|
+
<></>
|
|
77
|
+
)}
|
|
72
78
|
|
|
73
79
|
{/* SECTIONS */}
|
|
74
80
|
<div className='scroll'>
|
|
75
81
|
{customLinks.map((section, i) => (
|
|
76
82
|
<div className='sidebar-section' key={`sectionIndex${i}`}>
|
|
77
|
-
<h4>{section.title}</h4>
|
|
83
|
+
{section.title ? <h4>{section.title}</h4> : <></> }
|
|
78
84
|
|
|
79
85
|
{/* PROPS LINKS */}
|
|
80
86
|
{(section.backData ? sidebarLinks : section.links || []).map(
|
|
@@ -155,7 +161,12 @@ Sidebar.propTypes = {
|
|
|
155
161
|
onNavigate: PropTypes.func.isRequired, // Nueva prop para manejar la navegación
|
|
156
162
|
selectedClient: PropTypes.object,
|
|
157
163
|
showClients:PropTypes.oneOf([true, false, 'single']),
|
|
158
|
-
setGroovinProfile: PropTypes.func
|
|
164
|
+
setGroovinProfile: PropTypes.func,
|
|
165
|
+
inModal: PropTypes.bool,
|
|
166
|
+
customUrl: PropTypes.oneOfType([
|
|
167
|
+
PropTypes.string,
|
|
168
|
+
PropTypes.oneOf([undefined])
|
|
169
|
+
]),
|
|
159
170
|
};
|
|
160
171
|
|
|
161
172
|
export default Sidebar;
|
|
@@ -2,10 +2,22 @@ import React from 'react';
|
|
|
2
2
|
import Button from '../components/Button/Button';
|
|
3
3
|
|
|
4
4
|
export default {
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
title: 'Buttons/Button',
|
|
6
|
+
component: Button,
|
|
7
7
|
};
|
|
8
8
|
|
|
9
|
-
const Template = (args) =>
|
|
9
|
+
const Template = (args) => {
|
|
10
|
+
return (
|
|
11
|
+
<>
|
|
12
|
+
<Button
|
|
13
|
+
variant='primary'
|
|
14
|
+
size='lg'
|
|
15
|
+
onClick={() => console.log('Button clicked')}
|
|
16
|
+
>
|
|
17
|
+
Disabled Button
|
|
18
|
+
</Button>
|
|
19
|
+
</>
|
|
20
|
+
);
|
|
21
|
+
};
|
|
10
22
|
|
|
11
|
-
export const Default = Template.bind({});
|
|
23
|
+
export const Default = Template.bind({});
|