Skip to content

Commit d07e163

Browse files
Merge pull request #4150 from OneCommunityGlobal/julia-create-special-filter
Julia - Create Special Filter for Extra Members in Weekly Summaries Report
2 parents 0366e43 + d9a6add commit d07e163

17 files changed

Lines changed: 4125 additions & 2638 deletions

package-lock.json

Lines changed: 1479 additions & 1838 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@
106106
"react-toastify": "^5.3.1",
107107
"react-tooltip": "^4.5.1",
108108
"react-use-websocket": "^3.0.0",
109+
"react-window": "^1.8.11",
109110
"reactjs-popup": "^2.0.5",
110111
"reactstrap": "^8.10.1",
111112
"read-excel-file": "^5.5.3",

src/components/BMDashboard/WeeklyProjectSummary/PaidLaborCost/PaidLaborCost.module.css

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -90,16 +90,22 @@
9090
}
9191

9292
.paid-labor-cost-date-range-input {
93-
display: flex;
94-
justify-content: space-between;
95-
align-items: center;
93+
/* display: flex; */
94+
/* justify-content: space-between; */
9695
margin-top: 3px;
97-
padding: 2px 4px;
98-
border: 1px solid #ddd;
96+
/* padding: 2px 4px; */
97+
/* border: 1px solid #ddd; */
98+
transition: border-color 0.2s;
99+
flex: 1;
100+
padding: 0.2rem 2.5rem 0.2rem 0.2rem;
101+
border: 1px solid #ccc;
99102
border-radius: 4px;
100-
background-color: white;
103+
background-color: #fff;
104+
display: flex;
105+
align-items: center;
106+
justify-content: center;
101107
cursor: pointer;
102-
transition: border-color 0.2s;
108+
font-size: 0 ninerem;
103109
}
104110

105111
.paid-labor-cost-date-range-input:hover {
@@ -386,7 +392,7 @@
386392
align-items: center;
387393
}
388394

389-
.paid-labor-cost-date-range-input {
395+
/* .paid-labor-cost-date-range-input {
390396
flex: 1;
391397
padding: 0.2rem 2.5rem 0.2rem 0.2rem;
392398
border: 1px solid #ccc;
@@ -397,7 +403,7 @@
397403
justify-content: center;
398404
cursor: pointer;
399405
font-size: 0 ninerem;
400-
}
406+
} */
401407

402408
.paid-labor-cost-info-wrapper {
403409
position: absolute;
@@ -518,6 +524,9 @@
518524
width: 100%;
519525
overflow-x: auto;
520526
background-color: var(--bg-color);
527+
scrollbar-width: thin;
528+
scrollbar-color: var(--button-bg) var(--card-shadow);
529+
521530
}
522531

523532
.paidLaborCostChartScrollWrapper::-webkit-scrollbar {
@@ -533,7 +542,7 @@
533542
border-radius: 3px;
534543
}
535544

536-
.paidLaborCostChartScrollWrapper {
545+
/* .paidLaborCostChartScrollWrapper {
537546
scrollbar-width: thin;
538547
scrollbar-color: var(--button-bg) var(--card-shadow);
539-
}
548+
} */

src/components/ExperienceDonutChart/ExperienceDonutChart.module.css

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -219,11 +219,13 @@
219219
width: 100%;
220220
max-width: none; /* fill grid column, don't cap */
221221
padding: 0.6rem 0.75rem;
222-
text-align: left;
222+
/* text-align: left; */
223223

224224
/* prevent overflow on long role names / unbroken strings */
225225
overflow-wrap: anywhere;
226226
word-break: break-word;
227+
text-align: center;
228+
justify-content: center;
227229
}
228230

229231
.detail-item:hover,
@@ -244,15 +246,15 @@
244246
.detail-sub { display: none; } /* optional: hide to keep cards compact; show if you prefer */
245247
.detail-pct { grid-column: 4; margin-left: 0; font-weight: 800; color: #2563eb; }
246248

247-
.detail-item:hover,
249+
/* .detail-item:hover,
248250
.detail-item.active {
249251
background: #111827;
250252
border-color: #0b1220;
251253
box-shadow: 0 8px 18px rgba(2,6,23,.12);
252254
transform: translateY(-1px);
253-
}
254-
.detail-item:hover span,
255-
.detail-item.active span { color: #ffffff !important; }
255+
} */
256+
/* .detail-item:hover span,
257+
.detail-item.active span { color: #ffffff !important; } */
256258
.detail-item:hover .detail-pct,
257259
.detail-item.active .detail-pct { color: #93c5fd !important; } /* keep contrast on hover */
258260

@@ -312,7 +314,7 @@
312314
.pie-cell { transition: opacity .15s ease, filter .15s ease, transform .15s ease; cursor: pointer; }
313315
.pie-cell:hover { opacity: .9; filter: brightness(1.05); }
314316

315-
.detail-item { text-align: center; justify-content: center; }
317+
/* .detail-item { text-align: center; justify-content: center; } */
316318

317319

318320
/* ===================== Responsive tweaks ===================== */
@@ -357,6 +359,7 @@
357359
border-radius: 10px;
358360
box-shadow: 0 2px 8px rgba(2,6,23,0.06);
359361
background-clip: padding-box;
362+
transition: background-color .15s ease, border-color .15s ease, box-shadow .2s ease, transform .15s ease;
360363
}
361364

362365
/* Keep dark hover/active but ensure contrast is clear */
@@ -393,9 +396,9 @@
393396
}
394397

395398
/* Optional: smooth the state change */
396-
.chart-details .detail-item {
399+
/* .chart-details .detail-item {
397400
transition: background-color .15s ease, border-color .15s ease, box-shadow .2s ease, transform .15s ease;
398-
}
401+
} */
399402
/* ===================== DARK MODE (scoped to wrapper) ===================== */
400403

401404
/* Ensure every surface flips dark */

src/components/PermissionsManagement/PermissionsConst.jsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,12 @@ export const permissionLabels = [
101101
description:
102102
'Gives the user permission to edit 4-digit team codes on profile page and weekly summaries report page.',
103103
},
104+
{
105+
label: 'Create, Edit and Delete Weekly Summaries Filter',
106+
key: 'manageSummariesFilters',
107+
description:
108+
'Gives the user permission to create, edit and delete the filter in weekly summaries report page.',
109+
},
104110
{
105111
label: 'See Job Analytics Reports',
106112
key: 'getJobReports',
Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
import { useState, useEffect } from 'react';
2+
import { toast } from 'react-toastify';
3+
import axios from 'axios';
4+
import {
5+
Modal,
6+
ModalHeader,
7+
ModalBody,
8+
ModalFooter,
9+
Button,
10+
Label,
11+
Input,
12+
Form,
13+
FormGroup,
14+
} from 'reactstrap';
15+
16+
import { ENDPOINTS } from '~/utils/URL';
17+
import Select from 'react-select';
18+
import mainStyles from './WeeklySummariesReport.module.css';
19+
import { setField } from '~/utils/stateHelper';
20+
import FilterEditForm from './FilterEditForm';
21+
22+
const defaultState = {
23+
filterName: '',
24+
selectedCodes: [],
25+
selectedColors: [],
26+
selectedExtraMembers: [],
27+
selectedTrophies: false,
28+
selectedSpecialColors: {
29+
purple: false,
30+
green: false,
31+
navy: false,
32+
},
33+
selectedBioStatus: false,
34+
selectedOverTime: false,
35+
};
36+
37+
function CreateFilterModal({
38+
isOpen,
39+
toggle,
40+
initialState,
41+
darkMode,
42+
hasPermissionToFilter,
43+
canSeeBioHighlight,
44+
filters,
45+
refetchFilters,
46+
teamCodes,
47+
colorOptions,
48+
tableData,
49+
summaries,
50+
teamCodeWarningUsers,
51+
}) {
52+
const [state, setState] = useState(() => initialState ?? defaultState);
53+
const [mode, setMode] = useState('create');
54+
const [selectedFilter, setSelectedFilter] = useState(null);
55+
56+
useEffect(() => {
57+
setState(initialState);
58+
}, [initialState]);
59+
60+
const handleSubmit = async e => {
61+
e.preventDefault();
62+
if (state.filterName !== '' && state.filterName.length <= 7) {
63+
if (mode === 'create' || (mode === 'update' && state.selectedFilter !== null)) {
64+
// No errors -> submit form
65+
const data = {
66+
filterName: state.filterName,
67+
selectedCodes: state.selectedCodes.map(code => code.value),
68+
selectedColors: state.selectedColors.map(color => color.value),
69+
selectedExtraMembers: state.selectedExtraMembers.map(member => member.value),
70+
selectedTrophies: state.selectedTrophies,
71+
selectedSpecialColors: state.selectedSpecialColors,
72+
selectedBioStatus: state.selectedBioStatus,
73+
selectedOverTime: state.selectedOverTime,
74+
};
75+
if (mode === 'create') {
76+
try {
77+
const res = await axios.post(ENDPOINTS.WEEKLY_SUMMARIES_FILTERS, data);
78+
if (res.status < 200 || res.status >= 300) {
79+
toast.error(`Failed to save new filter. Status ${res.status}`);
80+
} else {
81+
toast.success(`Successfully created filter ${state.filterName}`);
82+
}
83+
refetchFilters();
84+
} catch (error) {
85+
toast.error(`Failed to save new filter. Error ${error}`);
86+
}
87+
} else {
88+
try {
89+
const res = await axios.patch(
90+
ENDPOINTS.WEEKLY_SUMMARIES_FILTER_BY_ID(selectedFilter.value),
91+
data,
92+
);
93+
if (res.status < 200 || res.status >= 300) {
94+
toast.error(`Failed to save new filter. Status ${res.status}`);
95+
} else {
96+
toast.success(`Successfully update filter ${selectedFilter.label}`);
97+
}
98+
await refetchFilters();
99+
} catch (error) {
100+
toast.error(`Failed to save new filter. Error ${error}`);
101+
}
102+
}
103+
104+
toggle();
105+
}
106+
}
107+
};
108+
109+
return (
110+
<Modal
111+
size="lg"
112+
isOpen={isOpen}
113+
toggle={toggle}
114+
className={`${darkMode ? mainStyles.darkModal : ''}`}
115+
>
116+
<ModalHeader toggle={toggle}>Create A New Filter or Override Existing Filter</ModalHeader>
117+
<ModalBody>
118+
<Form>
119+
<Input
120+
type="select"
121+
id="mode"
122+
className="mb-3"
123+
value={mode}
124+
onChange={e => setMode(e.target.value)}
125+
required
126+
>
127+
<option value="create">Create New</option>
128+
<option value="update">Override Existing Filter</option>
129+
</Input>
130+
{mode === 'update' && (
131+
<FormGroup>
132+
<Label for="filterOverride" className={`${darkMode ? mainStyles.textWhite : ''}`}>
133+
Choose a Filter to Override *
134+
</Label>
135+
136+
<Select
137+
id="filterOverride"
138+
options={filters}
139+
value={selectedFilter}
140+
onChange={setSelectedFilter}
141+
className={`${mainStyles.textDark} ${
142+
!selectedFilter ? `${mainStyles.errorSelect}` : ''
143+
}`}
144+
/>
145+
{!selectedFilter && (
146+
<div className={`${darkMode ? mainStyles.errorTextDark : mainStyles.errorText}`}>
147+
Please select a filter
148+
</div>
149+
)}
150+
</FormGroup>
151+
)}
152+
<FormGroup>
153+
<Label for="filterName" className={`${darkMode ? mainStyles.textWhite : ''}`}>
154+
{mode === 'create'
155+
? 'Filter Name (up to 7 characters) *'
156+
: 'New Filter Name (up to 7 characters) *'}
157+
</Label>
158+
<Input
159+
id="filterName"
160+
value={state.filterName}
161+
onChange={e => setField(setState, 'filterName', e.target.value)}
162+
placeholder="Enter filter name"
163+
required
164+
invalid={!state.filterName}
165+
maxLength={7}
166+
/>
167+
{state.filterName === '' && (
168+
<div className={`${darkMode ? mainStyles.errorTextDark : mainStyles.errorText}`}>
169+
Filter name is required
170+
</div>
171+
)}
172+
</FormGroup>
173+
<FilterEditForm
174+
state={state}
175+
setState={setState}
176+
darkMode={darkMode}
177+
hasPermissionToFilter={hasPermissionToFilter}
178+
canSeeBioHighlight={canSeeBioHighlight}
179+
teamCodes={teamCodes}
180+
colorOptions={colorOptions}
181+
tableData={tableData}
182+
summaries={summaries}
183+
teamCodeWarningUsers={teamCodeWarningUsers}
184+
/>
185+
</Form>
186+
</ModalBody>
187+
<ModalFooter>
188+
<Button color="primary" onClick={handleSubmit}>
189+
Save
190+
</Button>
191+
<Button color="secondary" onClick={toggle}>
192+
Cancel
193+
</Button>
194+
</ModalFooter>
195+
</Modal>
196+
);
197+
}
198+
export default CreateFilterModal;

0 commit comments

Comments
 (0)