Skip to content

Commit 53ca23a

Browse files
Merge pull request #3425 from OneCommunityGlobal/development
Frontend Release to Main [4.12]
2 parents 9ac285a + 57ee7db commit 53ca23a

45 files changed

Lines changed: 1761 additions & 454 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/assets/images/masterMap.png

936 KB
Loading

src/assets/images/pin-point.png

6.15 KB
Loading

src/assets/images/routeMarker.png

389 KB
Loading

src/components/BMDashboard/WeeklyProjectSummary/WeeklyProjectSummary.css

Lines changed: 86 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -297,4 +297,89 @@
297297
.weekly-project-summary-dashboard-grid {
298298
grid-template-columns: 1fr;
299299
}
300-
}
300+
}
301+
302+
/* ---------------- STATUS CARD ---------------- */
303+
.status-card {
304+
display: flex;
305+
flex-direction: column;
306+
align-items: center;
307+
justify-content: center;
308+
border-radius: 25px;
309+
width: 100%;
310+
max-width: 284px;
311+
height: 190px;
312+
text-align: center;
313+
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
314+
padding: 20px;
315+
border: 1px solid rgba(0, 0, 0, 0.1);
316+
position: relative;
317+
}
318+
319+
/* ---------------- RESPONSIVE GRID LAYOUT ---------------- */
320+
.project-status-grid {
321+
display: grid;
322+
grid-template-columns: repeat(5, 1fr);
323+
gap: 20px;
324+
justify-content: center;
325+
align-items: center;
326+
width: 100%;
327+
max-width: 1600px;
328+
margin: auto;
329+
}
330+
331+
/* ---------------- OVAL STATUS BUTTON ---------------- */
332+
.weekly-status-button {
333+
width: 130px;
334+
height: 65px;
335+
border-radius: 50px / 32px;
336+
display: flex;
337+
align-items: center;
338+
justify-content: center;
339+
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.15);
340+
margin: 12px 0;
341+
}
342+
343+
.weekly-card-title {
344+
color: #000;
345+
font-size: 24px;
346+
font-weight: 600;
347+
}
348+
349+
.weekly-status-value {
350+
color: #000;
351+
font-size: 40px;
352+
font-weight: 600;
353+
}
354+
355+
356+
/* ---------------- RESPONSIVE BREAKPOINTS ---------------- */
357+
@media (min-width: 1600px) {
358+
.project-status-grid {
359+
grid-template-columns: repeat(6, 1fr);
360+
}
361+
}
362+
363+
@media (max-width: 1400px) {
364+
.project-status-grid {
365+
grid-template-columns: repeat(4, 1fr);
366+
}
367+
}
368+
369+
@media (max-width: 1024px) {
370+
.project-status-grid {
371+
grid-template-columns: repeat(3, 1fr);
372+
}
373+
}
374+
375+
@media (max-width: 768px) {
376+
.project-status-grid {
377+
grid-template-columns: repeat(2, 1fr);
378+
}
379+
}
380+
381+
@media (max-width: 576px) {
382+
.project-status-grid {
383+
grid-template-columns: repeat(1, 1fr);
384+
}
385+
}

src/components/BMDashboard/WeeklyProjectSummary/WeeklyProjectSummary.jsx

Lines changed: 118 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,105 @@ import { useSelector } from 'react-redux';
44
import { v4 as uuidv4 } from 'uuid';
55
import WeeklyProjectSummaryHeader from './WeeklyProjectSummaryHeader';
66

7+
const projectStatusButtons = [
8+
{
9+
title: 'Total Projects',
10+
value: 426,
11+
change: '+16% week over week',
12+
bgColor: '#F0FFEE',
13+
buttonColor: '#BAF0B6',
14+
textColor: '#328D1B',
15+
},
16+
{
17+
title: 'Completed Projects',
18+
value: 127,
19+
change: '+14% week over week',
20+
bgColor: '#F3FCFF',
21+
buttonColor: '#C1EFFB',
22+
textColor: '#328D1B',
23+
},
24+
{
25+
title: 'Delayed Projects',
26+
value: 34,
27+
change: '-18% week over week',
28+
bgColor: '#FFE9FA',
29+
buttonColor: '#FECFF3',
30+
textColor: '#C82F2F',
31+
},
32+
{
33+
title: 'Active Projects',
34+
value: 265,
35+
change: '+3% week over week',
36+
bgColor: '#E8E8FF',
37+
buttonColor: '#CBCBFE',
38+
textColor: '#328D1B',
39+
},
40+
{
41+
title: 'Avg Project Duration',
42+
value: '17 hrs',
43+
change: '+13% week over week',
44+
bgColor: '#FFF6EE',
45+
buttonColor: '#FFD8A5',
46+
textColor: '#FFD8A5',
47+
},
48+
{
49+
title: 'Total Material Cost',
50+
value: '$27.6K',
51+
change: '+9% week over week',
52+
bgColor: '#FFF3F3',
53+
buttonColor: '#FBC1C2',
54+
textColor: '#328D1B',
55+
},
56+
{
57+
title: 'Total Material Used',
58+
value: '2714',
59+
change: '+11% week over week',
60+
bgColor: '#DAC8FF',
61+
buttonColor: '#B28ECC',
62+
textColor: '#328D1B',
63+
},
64+
{
65+
title: 'Active Projects',
66+
value: '265',
67+
change: '+3% week over week',
68+
bgColor: '#E8E8FF',
69+
buttonColor: '#CBCBFE',
70+
textColor: '#328D1B',
71+
},
72+
{
73+
title: 'Total Labor Hours Invested',
74+
value: '12.8K',
75+
change: '+17% week over week',
76+
bgColor: '#E5C1FC',
77+
buttonColor: '#F6E1FB',
78+
textColor: '#328D1B',
79+
},
80+
{
81+
title: 'Total Labor Cost',
82+
value: '$18.4K',
83+
change: '+14% week over week',
84+
bgColor: '#FFFDF3',
85+
buttonColor: '#FBF9C1',
86+
textColor: '#328D1B',
87+
},
88+
{
89+
title: 'Material Available',
90+
value: 693,
91+
change: '-8% week over week',
92+
bgColor: '#B4D9C5',
93+
buttonColor: '#31BD41',
94+
textColor: '#C82F2F',
95+
},
96+
{
97+
title: 'Material Wasted',
98+
value: 879,
99+
change: '+14% week over week',
100+
bgColor: '#EFBABB',
101+
buttonColor: '#F79395',
102+
textColor: '#328D1B',
103+
},
104+
];
105+
7106
export default function WeeklyProjectSummary() {
8107
const [openSections, setOpenSections] = useState({});
9108

@@ -23,11 +122,27 @@ export default function WeeklyProjectSummary() {
23122
className: 'full',
24123
content: (
25124
<div className="project-status-grid">
26-
{Array.from({ length: 12 }).map(() => {
125+
{projectStatusButtons.map(button => {
27126
const uniqueId = uuidv4();
28127
return (
29-
<div key={uniqueId} className="weekly-project-summary-card small-card">
30-
📊 Card
128+
<div
129+
key={uniqueId}
130+
className="weekly-project-summary-card status-card"
131+
style={{ backgroundColor: button.bgColor }} // Dynamic Background
132+
>
133+
<div className="weekly-card-title">{button.title}</div>
134+
<div
135+
className="weekly-status-button"
136+
style={{ backgroundColor: button.buttonColor }} // Dynamic Oval Color
137+
>
138+
<span className="weekly-status-value">{button.value}</span>
139+
</div>
140+
<div
141+
className="weekly-status-change"
142+
style={{ color: button.textColor }} // Dynamic Change Color
143+
>
144+
{button.change}
145+
</div>
31146
</div>
32147
);
33148
})}

src/components/Badge/AssignBadge.jsx

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -214,12 +214,7 @@ function AssignBadge(props) {
214214
>
215215
Assign Badge
216216
</Button>
217-
<Modal
218-
isOpen={isOpen}
219-
toggle={toggle}
220-
backdrop="static"
221-
className={darkMode ? 'text-light dark-mode' : ''}
222-
>
217+
<Modal isOpen={isOpen} toggle={toggle} className={darkMode ? 'text-light dark-mode' : ''}>
223218
<ModalHeader className={darkMode ? 'bg-space-cadet' : ''} toggle={toggle}>
224219
Assign Badge
225220
</ModalHeader>

src/components/Badge/BadgeReport.jsx

Lines changed: 61 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -84,54 +84,68 @@ function BadgeReport(props) {
8484
};
8585
}
8686

87-
const FormatReportForPdf = (badges, callback) => {
88-
const bgReport = [];
89-
bgReport[0] = `<h3>Badge Report (Page 1 of ${Math.ceil(badges.length / 4)})</h3>
90-
<div style="margin-bottom: 20px; color: orange;"><h4>For ${props.firstName} ${
91-
props.lastName
92-
}</h4></div>
93-
<div style="color:#DEE2E6; margin:10px 0px 20px 0px; text-align:center;">_______________________________________________________________________________________________</div>`;
94-
95-
for (let i = 0; i < badges.length; i += 1) {
96-
imageToUri(badges[i].badge.imageUrl, function(uri) {
97-
bgReport[i + 1] = `
98-
<table>
99-
<thead>
100-
<tr>
101-
<th>Badge Image</th>
102-
<th>Badge Name, Count Awarded & Badge Description</th>
103-
</tr>
104-
</thead>
105-
<tbody>
106-
<tr>
107-
<td style="width:160px">
108-
<div><img height="150" width="150" src=${uri}/></div>
109-
</td>
110-
<td style="width:500px">
111-
<div><b>Name:</b> <span class="name">${badges[i].badge.badgeName}</span></div>
112-
<div><b>Count:</b> ${badges[i].count}</div>
113-
<div><b>Description:</b> ${badges[i].badge.description}</div>
114-
</td>
115-
</tr>
116-
</tbody>
117-
</table>
118-
${
119-
(i + 1) % 4 === 0 && i + 1 !== badges.length
120-
? `</br></br></br>
121-
<h3>Badge Report (Page ${1 + Math.ceil((i + 1) / 4)} of ${Math.ceil(badges.length / 4)})</h3>
122-
<div style="margin-bottom: 20px; color: orange;"><h4>For ${props.firstName} ${
123-
props.lastName
124-
}</h4></div>
125-
<div style="color:#DEE2E6; margin:10px 0px 20px 0px; text-align:center;">_______________________________________________________________________________________________</div>
126-
`
127-
: ''
128-
}`;
129-
if (i === badges.length - 1) {
130-
setTimeout(() => {
131-
callback(bgReport.join('\n'));
132-
}, 100);
133-
}
87+
const FormatReportForPdf = async (badges, callback) => {
88+
try {
89+
const bgReport = [];
90+
bgReport[0] = `<h3>Badge Report (Page 1 of ${Math.ceil(badges.length / 4)})</h3>
91+
<div style="margin-bottom: 20px; color: orange;"><h4>For ${props.firstName} ${
92+
props.lastName
93+
}</h4></div>
94+
<div style="color:#DEE2E6; margin:10px 0px 20px 0px; text-align:center;">_______________________________________________________________________________________________</div>`;
95+
96+
const badgePromises = badges.map((badge, i) => {
97+
const imageUrl = badge.badge?.imageUrl || ''; // Fallback to empty string if imageUrl is missing
98+
const badgeName = badge.badge?.badgeName || 'Unknown Badge'; // Fallback for missing badgeName
99+
const description = badge.badge?.description || 'No description available'; // Fallback for missing description
100+
101+
return new Promise((resolve) => {
102+
imageToUri(imageUrl, (uri) => {
103+
const badgeHtml = `
104+
<table>
105+
<thead>
106+
<tr>
107+
<th>Badge Image</th>
108+
<th>Badge Name, Count Awarded & Badge Description</th>
109+
</tr>
110+
</thead>
111+
<tbody>
112+
<tr>
113+
<td style="width:160px">
114+
<div><img height="150" width="150" src="${uri}" /></div>
115+
</td>
116+
<td style="width:500px">
117+
<div><b>Name:</b> <span class="name">${badgeName}</span></div>
118+
<div><b>Count:</b> ${badge.count}</div>
119+
<div><b>Description:</b> ${description}</div>
120+
</td>
121+
</tr>
122+
</tbody>
123+
</table>
124+
${
125+
(i + 1) % 4 === 0 && i + 1 !== badges.length
126+
? `</br></br></br>
127+
<h3>Badge Report (Page ${1 + Math.ceil((i + 1) / 4)} of ${Math.ceil(
128+
badges.length / 4
129+
)})</h3>
130+
<div style="margin-bottom: 20px; color: orange;"><h4>For ${props.firstName} ${
131+
props.lastName
132+
}</h4></div>
133+
<div style="color:#DEE2E6; margin:10px 0px 20px 0px; text-align:center;">_______________________________________________________________________________________________</div>
134+
`
135+
: ''
136+
}`;
137+
resolve(badgeHtml);
138+
});
139+
});
134140
});
141+
142+
const badgeHtmlArray = await Promise.all(badgePromises);
143+
bgReport.push(...badgeHtmlArray);
144+
145+
callback(bgReport.join('\n'));
146+
} catch (error) {
147+
console.error('Error generating badge report:', error);
148+
callback('<p>Error generating badge report. Please try again later.</p>');
135149
}
136150
};
137151

0 commit comments

Comments
 (0)