groovinads-ui 1.2.45 → 1.2.46

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.46",
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;
@@ -0,0 +1,172 @@
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
+ console.log('clientsList', clientsList);
33
+
34
+ setClientsList(clientsList);
35
+ setshowDropdownSkeleton(false);
36
+ } catch (error) {
37
+ console.error('fetchClientsData error', error);
38
+ }
39
+ };
40
+
41
+ const filterClients = () => {
42
+ return clientsList.filter(
43
+ ({ client_name, id_client, email }) =>
44
+ `${client_name} ${id_client}`
45
+ .toLowerCase()
46
+ .includes(searchInput.toLowerCase()) ||
47
+ email?.toLowerCase()?.includes(searchInput?.toLowerCase()),
48
+ );
49
+ };
50
+
51
+ const changeClient = async (client) => {
52
+ try {
53
+ setGeneralSkeleton(true);
54
+ setshowDropdownSkeleton(true);
55
+
56
+ await ComponentsService.clientsLogin(client.id_client);
57
+
58
+ setSelectedClient(client);
59
+
60
+ // Check if current url ends with '/', if not, add it and redirect to that url
61
+ // If it currently ends with '/', just reload that url
62
+ if (window.location.href.slice(-1) !== '/')
63
+ window.location.replace(window.location.href + '/');
64
+ else window.location.reload();
65
+ } catch (error) {
66
+ console.error(' error en ClientsDropdowns ', error);
67
+ }
68
+ };
69
+
70
+ useEffect(() => {
71
+ fetchClientsData();
72
+ }, []);
73
+
74
+ return (
75
+ <>
76
+ {showDropdownSkeleton || generalSkeleton ? (
77
+ <div className='bottom-list loading'>
78
+ <div className='dropdown-clients'>
79
+ <div className='client-logo load'></div>
80
+ <div className='dropdown-clients-wrapper load-paragraph w-75'>
81
+ <div className='load text small mb-0'></div>
82
+ <div className='load text small mb-0'></div>
83
+ </div>
84
+ </div>
85
+ </div>
86
+ ) : (
87
+ <div className='bottom-list'>
88
+ <Dropdown
89
+ drop='up'
90
+ className='dropdown-clients'
91
+ show={clientsList.length <= 1 ? false : dropdownOpen}
92
+ onToggle={toggleDropdown}
93
+ >
94
+ <Dropdown.Toggle variant='client-selector' onClick={toggleDropdown}>
95
+ {/* Logo cliente. Si no tiene logo, usar el genérico generado. Ver JS en la parte inferior */}
96
+ {selectedClient ? (
97
+ <div className='client-logo'>
98
+ <p>{clientInitials}</p>
99
+ </div>
100
+ ) : (
101
+ <img src='/react.svg' alt='' className='client-logo' />
102
+ )}
103
+
104
+ <div className='dropdown-clients-wrapper'>
105
+ <p className='dropdown-client-name'>
106
+ {selectedClient?.client_name || 'Client name'} [
107
+ {selectedClient?.id_client}]
108
+ </p>
109
+ <p className='dropdown-client-email'>
110
+ {selectedClient?.email || 'Client Email'}
111
+ </p>
112
+ </div>
113
+ {clientsList.length > 1 ? (
114
+ <Icon
115
+ style={'solid'}
116
+ iconName={'chevron-up'}
117
+ scale={1}
118
+ className={'icon caret'}
119
+ />
120
+ ) : (
121
+ <></>
122
+ )}
123
+ </Dropdown.Toggle>
124
+ <Dropdown.Menu>
125
+ <Dropdown.Item as={'div'} onClick={(e) => e.stopPropagation()}>
126
+ <Input
127
+ size={'xs'}
128
+ label={'Search client'}
129
+ icon={'magnifying-glass'}
130
+ className='w-100'
131
+ value={searchInput}
132
+ onChange={(e) => setSearchInput(e.target.value)}
133
+ />
134
+ </Dropdown.Item>
135
+ <Dropdown.Item as={'ul'} className='client-list'>
136
+ {filterClients().length ? (
137
+ filterClients().map((client) => (
138
+ <li
139
+ className='client'
140
+ key={client.id_client}
141
+ onClick={() => changeClient(client)}
142
+ >
143
+ <p className='dropdown-client-name'>
144
+ {client.client_name} [{client.id_client}]
145
+ </p>
146
+ <p className='dropdown-client-email'>{client.email}</p>
147
+ </li>
148
+ ))
149
+ ) : (
150
+ <li>
151
+ <div className='empty-space'>
152
+ <img
153
+ src={'https://ui.groovinads.com/assets/not-found.svg'}
154
+ alt='Sad magnifier on abstract background'
155
+ />
156
+ <div className='empty-space-text-wrapper'>
157
+ <h5 className='mb-1'>Client not found</h5>
158
+ <p>It looks like this client does not exist.</p>
159
+ </div>
160
+ </div>
161
+ </li>
162
+ )}
163
+ </Dropdown.Item>
164
+ </Dropdown.Menu>
165
+ </Dropdown>
166
+ </div>
167
+ )}
168
+ </>
169
+ );
170
+ };
171
+
172
+ 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