groovinads-ui 1.2.45 → 1.2.47

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/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.45",
4
+ "version": "1.2.47",
5
5
  "keywords": [
6
6
  "css",
7
7
  "sass",
@@ -32,6 +32,7 @@ const DropdownMultiSelect = ({
32
32
  focus = false,
33
33
  buttonVariant = 'input',
34
34
  nowrap = false,
35
+ hasId = true,
35
36
  }) => {
36
37
  const [query, setQuery] = useState('');
37
38
  const [innerShow, setInnerShow] = useState(!!show);
@@ -186,7 +187,9 @@ const DropdownMultiSelect = ({
186
187
  key={'Dropdown.Input.Checkbox' + index}
187
188
  >
188
189
  {highlightText(
189
- object ? `#${value[idKey]} - ${value[nameKey]}` : value,
190
+ object
191
+ ? `${hasId ? `#${value[idKey]} - ` : ''}${value[nameKey]}`
192
+ : value[nameKey] || value,
190
193
  query,
191
194
  )}
192
195
  </Checkbox>
@@ -231,6 +234,7 @@ DropdownMultiSelect.propTypes = {
231
234
  'outline',
232
235
  ]),
233
236
  nowrap: PropTypes.bool,
237
+ hasId: PropTypes.bool,
234
238
  };
235
239
 
236
240
  export default DropdownMultiSelect;
@@ -26,6 +26,8 @@ const Input = ({
26
26
  suffix,
27
27
  type = 'text',
28
28
  value,
29
+ min,
30
+ max,
29
31
  }) => {
30
32
  const { toCamelCase } = useTextFormatter();
31
33
  const inputRef = useRef(null);
@@ -75,6 +77,8 @@ const Input = ({
75
77
  required={!!requiredText}
76
78
  autoFocus={autoFocus}
77
79
  ref={inputRef}
80
+ min={min}
81
+ max={max}
78
82
  />
79
83
  <label htmlFor={id}>{label}</label>
80
84
  </div>
@@ -97,6 +101,8 @@ const Input = ({
97
101
  disabled={disabled}
98
102
  autoFocus={autoFocus}
99
103
  ref={inputRef}
104
+ min={min}
105
+ max={max}
100
106
  />
101
107
  <label htmlFor={id}>{label}</label>
102
108
  </div>
@@ -139,6 +145,8 @@ Input.propTypes = {
139
145
  ]),
140
146
  value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
141
147
  autoFocus: PropTypes.bool,
148
+ min: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
149
+ max: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
142
150
  };
143
151
 
144
152
  export default Input;
@@ -53,9 +53,9 @@ const DeckDropdown = () => {
53
53
  const favApp = async (identification) => {
54
54
  try {
55
55
  const resp = await ComponentsService.favApplication(identification);
56
- console.log('if ---->');
56
+ //console.log('if ---->');
57
57
  setApplications((prev) => {
58
- console.log('setApplications ---->');
58
+ //console.log('setApplications ---->');
59
59
  const index = prev.findIndex(
60
60
  (element) => element?.id_application === identification,
61
61
  );
@@ -0,0 +1,171 @@
1
+ import React, { useEffect, useState } from 'react';
2
+
3
+ // SERVICES
4
+ import { ComponentsService } from '../../../services';
5
+ import { Dropdown } from 'react-bootstrap';
6
+
7
+ // COMPONENTS
8
+ import Input from '../../Inputs/Input';
9
+ import Icon from '../../Labels/Icon';
10
+
11
+ const DropdownClients = ({ profileSelectedClient }) => {
12
+ const [generalSkeleton, setGeneralSkeleton] = useState(false);
13
+
14
+ const [showDropdownSkeleton, setshowDropdownSkeleton] = useState(false);
15
+
16
+ const { id_client, client_name, email } = profileSelectedClient;
17
+ const initial_client = { id_client, client_name, email };
18
+
19
+ const [clientsList, setClientsList] = useState([]);
20
+ const [searchInput, setSearchInput] = useState('');
21
+ const [selectedClient, setSelectedClient] = useState(initial_client);
22
+
23
+ const [dropdownOpen, setDropdownOpen] = useState(false);
24
+
25
+ const clientInitials = selectedClient?.client_name?.slice(0, 2);
26
+ const toggleDropdown = () => setDropdownOpen((prev) => !prev);
27
+
28
+ const fetchClientsData = async () => {
29
+ try {
30
+ setshowDropdownSkeleton(true);
31
+ const clientsList = await ComponentsService.getClientsList();
32
+
33
+ setClientsList(clientsList);
34
+ setshowDropdownSkeleton(false);
35
+ } catch (error) {
36
+ console.error('fetchClientsData error', error);
37
+ }
38
+ };
39
+
40
+ const filterClients = () => {
41
+ return clientsList.filter(
42
+ ({ client_name, id_client, email }) =>
43
+ `${client_name} ${id_client}`
44
+ .toLowerCase()
45
+ .includes(searchInput.toLowerCase()) ||
46
+ email?.toLowerCase()?.includes(searchInput?.toLowerCase()),
47
+ );
48
+ };
49
+
50
+ const changeClient = async (client) => {
51
+ try {
52
+ setGeneralSkeleton(true);
53
+ setshowDropdownSkeleton(true);
54
+
55
+ await ComponentsService.clientsLogin(client.id_client);
56
+
57
+ setSelectedClient(client);
58
+
59
+ // Check if current url ends with '/', if not, add it and redirect to that url
60
+ // If it currently ends with '/', just reload that url
61
+ if (window.location.href.slice(-1) !== '/')
62
+ window.location.replace(window.location.href + '/');
63
+ else window.location.reload();
64
+ } catch (error) {
65
+ console.error(' error en ClientsDropdowns ', error);
66
+ }
67
+ };
68
+
69
+ useEffect(() => {
70
+ fetchClientsData();
71
+ }, []);
72
+
73
+ return (
74
+ <>
75
+ {showDropdownSkeleton || generalSkeleton ? (
76
+ <div className='bottom-list loading'>
77
+ <div className='dropdown-clients'>
78
+ <div className='client-logo load'></div>
79
+ <div className='dropdown-clients-wrapper load-paragraph w-75'>
80
+ <div className='load text small mb-0'></div>
81
+ <div className='load text small mb-0'></div>
82
+ </div>
83
+ </div>
84
+ </div>
85
+ ) : (
86
+ <div className='bottom-list'>
87
+ <Dropdown
88
+ drop='up'
89
+ className='dropdown-clients'
90
+ show={clientsList.length <= 1 ? false : dropdownOpen}
91
+ onToggle={toggleDropdown}
92
+ >
93
+ <Dropdown.Toggle variant='client-selector' onClick={toggleDropdown}>
94
+ {/* Logo cliente. Si no tiene logo, usar el genérico generado. Ver JS en la parte inferior */}
95
+ {selectedClient ? (
96
+ <div className='client-logo'>
97
+ <p>{clientInitials}</p>
98
+ </div>
99
+ ) : (
100
+ <img src='/react.svg' alt='' className='client-logo' />
101
+ )}
102
+
103
+ <div className='dropdown-clients-wrapper'>
104
+ <p className='dropdown-client-name'>
105
+ {selectedClient?.client_name || 'Client name'} [
106
+ {selectedClient?.id_client}]
107
+ </p>
108
+ <p className='dropdown-client-email'>
109
+ {selectedClient?.email || 'Client Email'}
110
+ </p>
111
+ </div>
112
+ {clientsList.length > 1 ? (
113
+ <Icon
114
+ style={'solid'}
115
+ iconName={'chevron-up'}
116
+ scale={1}
117
+ className={'icon caret'}
118
+ />
119
+ ) : (
120
+ <></>
121
+ )}
122
+ </Dropdown.Toggle>
123
+ <Dropdown.Menu>
124
+ <Dropdown.Item as={'div'} onClick={(e) => e.stopPropagation()}>
125
+ <Input
126
+ size={'xs'}
127
+ label={'Search client'}
128
+ icon={'magnifying-glass'}
129
+ className='w-100'
130
+ value={searchInput}
131
+ onChange={(e) => setSearchInput(e.target.value)}
132
+ />
133
+ </Dropdown.Item>
134
+ <Dropdown.Item as={'ul'} className='client-list'>
135
+ {filterClients().length ? (
136
+ filterClients().map((client) => (
137
+ <li
138
+ className='client'
139
+ key={client.id_client}
140
+ onClick={() => changeClient(client)}
141
+ >
142
+ <p className='dropdown-client-name'>
143
+ {client.client_name} [{client.id_client}]
144
+ </p>
145
+ <p className='dropdown-client-email'>{client.email}</p>
146
+ </li>
147
+ ))
148
+ ) : (
149
+ <li>
150
+ <div className='empty-space'>
151
+ <img
152
+ src={'https://ui.groovinads.com/assets/not-found.svg'}
153
+ alt='Sad magnifier on abstract background'
154
+ />
155
+ <div className='empty-space-text-wrapper'>
156
+ <h5 className='mb-1'>Client not found</h5>
157
+ <p>It looks like this client does not exist.</p>
158
+ </div>
159
+ </div>
160
+ </li>
161
+ )}
162
+ </Dropdown.Item>
163
+ </Dropdown.Menu>
164
+ </Dropdown>
165
+ </div>
166
+ )}
167
+ </>
168
+ );
169
+ };
170
+
171
+ export default DropdownClients;
@@ -1,4 +1,5 @@
1
1
  import DeckDropdown from './DeckDropdown';
2
2
  import UserDropdown from './UserDropdown';
3
+ import DropdownClients from './DropdownClient';
3
4
 
4
- export { DeckDropdown, UserDropdown }
5
+ export { DeckDropdown, UserDropdown, DropdownClients }
@@ -10,6 +10,7 @@ import PropTypes from 'prop-types';
10
10
 
11
11
  // COMPONENTES
12
12
  import { Icon } from '../Labels';
13
+ import { DropdownClients } from './Dropdowns';
13
14
 
14
15
  const Sidebar = ({
15
16
  api,
@@ -18,6 +19,9 @@ const Sidebar = ({
18
19
  show,
19
20
  setShow,
20
21
  onNavigate,
22
+ selectedClient,
23
+ showClients = false,
24
+ setGroovinProfile
21
25
  }) => {
22
26
  const isMobile = useMediaQuery({ query: '(max-width: 992px)' });
23
27
 
@@ -128,6 +132,15 @@ const Sidebar = ({
128
132
  </div>
129
133
  ))}
130
134
  </div>
135
+ {showClients ? (
136
+ <DropdownClients
137
+ profileSelectedClient={selectedClient}
138
+ showClients={showClients}
139
+ setGroovinProfile={setGroovinProfile}
140
+ />
141
+ ) : (
142
+ <></>
143
+ )}
131
144
  </nav>
132
145
  </Collapse>
133
146
  );
@@ -140,6 +153,9 @@ Sidebar.propTypes = {
140
153
  show: PropTypes.bool, // Add show prop for controlling visibility
141
154
  setShow: PropTypes.func, // Add setShow prop for controlling visibility
142
155
  onNavigate: PropTypes.func.isRequired, // Nueva prop para manejar la navegación
156
+ selectedClient: PropTypes.object,
157
+ showClients:PropTypes.oneOf([true, false, 'single']),
158
+ setGroovinProfile: PropTypes.func
143
159
  };
144
160
 
145
161
  export default Sidebar;
package/src/index.js CHANGED
@@ -6,7 +6,6 @@ import DropdownComponent from './components/Dropdowns/DropdownComponent';
6
6
  import DropdownFilter from './components/Dropdowns/DropdownFilter';
7
7
  import DropdownMultiSelect from './components/Dropdowns/DropdownMultiSelect';
8
8
  import DropdownDatePicker from './components/Dropdowns/DropdownsDatePicker/DropdownDatePicker';
9
-
10
9
  // Inputs
11
10
  import Checkbox from './components/Inputs/Checkbox';
12
11
  import Input from './components/Inputs/Input';
@@ -11,6 +11,10 @@ export const favApplication = async (appToFav) => await POST({url: `${urlPath.fa
11
11
 
12
12
  export const unfavApplication = async (appToUnfav) => await DELETE({url: `${urlPath.favApps}/${appToUnfav}`});
13
13
 
14
+ export const getClientsList = async () => await GET({ url: urlPath.clients });
15
+
16
+ export const clientsLogin = async (clientId) => await POST({ url: urlPath.clientsLogin, data:{ id_client: clientId }});
17
+
14
18
  export const getSidebarInfo = async (api) => await GET({ url: basePath + api});
15
19
 
16
20
  export const getCustomReportsList = async () => await GET(`${urlPath.customReports}/?sort=id_report.desc&offset=0&limit=100`);
@@ -14,7 +14,8 @@ export default {
14
14
  /* APPS FOR DROPDOWN */
15
15
  applications: basePath + 'v2/applications',
16
16
  favApps: basePath + 'v2/applications/favorite',
17
-
17
+ clients: basePath + 'v2/auth/clients',
18
+ clientsLogin: basePath + 'v2/auth/clients/login',
18
19
 
19
20
  headers: {
20
21
  headers: {
@@ -1,45 +1,75 @@
1
- import React, { useState } from "react";
2
- import DropdownMultiSelect from "../components/Dropdowns/DropdownMultiSelect";
1
+ import React, { useState } from 'react';
2
+ import DropdownMultiSelect from '../components/Dropdowns/DropdownMultiSelect';
3
3
 
4
4
  export default {
5
- title: "Dropdown/DropdownMultiSelect",
6
- component: DropdownMultiSelect,
5
+ title: 'Dropdown/DropdownMultiSelect',
6
+ component: DropdownMultiSelect,
7
7
  };
8
8
 
9
9
  const Template = (args) => {
10
10
  const [show, setShow] = useState(false);
11
- const handleToggle = () => setShow(prevShow => !prevShow);
11
+ const handleToggle = () => setShow((prevShow) => !prevShow);
12
12
 
13
+ /* ========== */
14
+ /* OPCION 1 - Opciones y valores seleccionados son array de objetos */
15
+ const filters = [
16
+ { id: 1, name: 'Filter 1', showStatus: '1' },
17
+ { id: 2, name: 'Filter 2', showStatus: '0' },
18
+ { id: 3, name: 'Filter 3', showStatus: '1' },
19
+ { id: 4, name: 'Filter 4', showStatus: '0' },
20
+ { id: 5, name: 'Filter 5', showStatus: '0' },
21
+ { id: 6, name: 'Filter 6', showStatus: '2' },
22
+ ];
13
23
  const [selectedValues, setSelectedValues] = useState([]);
14
- const [filters, setFilters] = useState([
15
- { id: 1, name: "Filter 1", showStatus:'1'},
16
- { id: 2, name: "Filter 2", showStatus:'0'},
17
- { id: 3, name: "Filter 3", showStatus:'1'},
18
- { id: 4, name: "Filter 4", showStatus:'0'},
19
- { id: 5, name: "Filter 5", showStatus:'0'},
20
- { id: 6, name: "Filter 6", showStatus:'2'},
21
- ]);
24
+ /* ========== */
25
+
26
+ /* ========== */
27
+ /* OPCION 2 - Opciones y valores seleccionados son array de strings */
28
+ const stringFilters = [
29
+ 'Filter 1',
30
+ 'Filter 2',
31
+ 'Filter 3',
32
+ 'Filter 4',
33
+ 'Filter 5',
34
+ ];
35
+ const [selectedStringValues, setSelectedStringValues] = useState([]);
36
+ /* =========== */
22
37
 
23
38
  return (
24
39
  <>
25
- {/* <button onClick={() => setShow(false)}>Close</button>
26
- <button onClick={() => setShow(true)}>Open</button> */}
40
+ {/* OPCION 1 */}
27
41
  <DropdownMultiSelect
28
- {...args}
42
+ {...args}
43
+ values={filters}
29
44
  valuesSelected={selectedValues}
30
45
  setValuesSelected={setSelectedValues}
31
- values={filters}
32
46
  show={show}
33
47
  onToggle={handleToggle}
34
48
  object={true}
35
- nameKey="name"
36
- idKey={"id"}
37
- inputLabel={'Filters'}
49
+ nameKey='name'
50
+ idKey={'id'}
51
+ inputLabel={'Filters (array de objetos)'}
52
+ focus={show}
53
+ hasId={true}
54
+ />
55
+
56
+ {/* OPCION 2 */}
57
+ <DropdownMultiSelect
58
+ {...args}
59
+ values={stringFilters}
60
+ valuesSelected={selectedStringValues}
61
+ setValuesSelected={setSelectedStringValues}
62
+ show={show}
63
+ onToggle={handleToggle}
64
+ object={false}
65
+ nameKey='name'
66
+ idKey={'id'}
67
+ inputLabel={'Filters (array de strings)'}
38
68
  focus={show}
39
-
40
- ></DropdownMultiSelect>
69
+ hasId={true}
70
+ />
41
71
  </>
42
- )
72
+ );
43
73
  };
44
74
 
45
- export const Default = Template.bind({});
75
+ export const Default = Template.bind({});
@@ -80,13 +80,54 @@ const Template = (args) => {
80
80
  backData: true,
81
81
  },
82
82
  ];
83
+
84
+ const selectedClients = {
85
+ email: 'lancome@groovinads.com',
86
+ id_client: 3661,
87
+ id_alias: null,
88
+ id_shop: null,
89
+ fgAdmin: 0,
90
+ fgMaster: 1,
91
+ fgClientsAdmin: 0,
92
+ country: 'MX',
93
+ time_zone: '(GMT-06:00)-GUADALAJARA, MEXICO CITY, MONTERREY ',
94
+ time_zone_db: '-6:00',
95
+ auth_data: {
96
+ login_level: 'USER',
97
+ login_id: 308,
98
+ email: 'tobias.matarasso@groovinads.com',
99
+ scopes: [
100
+ 'master',
101
+ 'lalala',
102
+ 'NewName',
103
+ 'user_admin',
104
+ 'digital_signage_deals_manager',
105
+ 'dashboard_screens',
106
+ ],
107
+ google_name: 'Tobias Matarasso',
108
+ google_picture:
109
+ 'https://lh3.googleusercontent.com/a/ACg8ocIYedPDyRN_HV8egw-h3YV_Lv2ZVQa9YSw_g7o7vXBqhMTqEI4=s96-c',
110
+ oauth_name: 'Google',
111
+ oauth_username: 'Tobias Matarasso',
112
+ oauth_picture:
113
+ 'https://lh3.googleusercontent.com/a/ACg8ocIYedPDyRN_HV8egw-h3YV_Lv2ZVQa9YSw_g7o7vXBqhMTqEI4=s96-c',
114
+ id_api_key: 0,
115
+ },
116
+ client_name: 'Lancome',
117
+ php_session_id: 'u7o2br84i92jmfkdrqen10ngp1',
118
+ is_api2_login: true,
119
+ };
120
+
83
121
  return (
84
122
  <div className='container-fluid'>
85
123
  <Sidebar
86
124
  {...args}
87
125
  api={'v2/reports/'}
88
126
  customLinks={customLinks}
89
- defaultOpened={false}
127
+ defaultOpened={true}
128
+ selectedClient={selectedClients}
129
+ showClients={true}
130
+ onNavigate={(url) => console.log('Navigate to:', url)}
90
131
  />
91
132
  <div className='main'>
92
133
  Lorem ipsum dolor sit amet, consectetur adipisicing elit. Magni quasi