Skip to content

Commit 3f39933

Browse files
authored
Merge branch 'development' into Amalesh-UserTeamsTable-tests
2 parents fff4691 + 16704d8 commit 3f39933

110 files changed

Lines changed: 7765 additions & 2543 deletions

File tree

Some content is hidden

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

.github/workflows/deploy.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,4 +62,4 @@ jobs:
6262
domain: ${{ vars.SURGE_DOMAIN }}
6363
project: './build'
6464
login: ${{ secrets.SURGE_LOGIN }}
65-
token: ${{ secrets.SURGE_TOKEN }}
65+
token: ${{ secrets.SURGE_TOKEN }}

.github/workflows/pull_request_test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,4 +55,4 @@ jobs:
5555
- name: Run Unit Tests for Changed Files Only
5656
run: yarn run test:changed
5757
- name: Run Lint
58-
run: yarn run lint
58+
run: yarn run lint

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,5 @@ yarn-error.log*
3232

3333
**\ **
3434

35-
/public/tinymce/
35+
/public/tinymce/
36+
package-lock.json

.husky/pre-commit

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
#!/bin/sh
22
# Load nvm if available
3+
# Try to load nvm (non-blocking)
34
export NVM_DIR="$HOME/.nvm"
4-
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
5-
# Use Node 20 if available (or install if needed)
6-
if [ -f .nvmrc ]; then
7-
nvm use 20 2>/dev/null || nvm install 20 && nvm use 20
8-
fi
95

10-
. "$(dirname "$0")/_/husky.sh"
6+
if [ -s "$NVM_DIR/nvm.sh" ]; then
7+
. "$NVM_DIR/nvm.sh"
8+
nvm use >/dev/null 2>&1
9+
echo "Using Node via nvm"
10+
else
11+
echo "nvm not available, using system Node"
12+
fi
1113

1214
echo ""
1315
echo "🛡️ Husky pre-commit hook triggered"

index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<!DOCTYPE html>
22
<html lang="en">
33
<head>
4+
<base href="/" />
45
<meta charset="utf-8" />
56
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
67
<meta name="theme-color" content="#000000" />

public/service-worker.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Service Worker for HGN Skills Overview Page
2+
const CACHE_NAME = 'hgn-skills-cache-v1';
3+
4+
globalThis.addEventListener('install', () => {
5+
globalThis.skipWaiting();
6+
});
7+
8+
globalThis.addEventListener('activate', event => {
9+
event.waitUntil(globalThis.clients.claim());
10+
});
11+
12+
globalThis.addEventListener('fetch', event => {
13+
event.respondWith(fetch(event.request));
14+
});

src/actions/kiCalendarAction.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
2+
import { ENDPOINTS } from '~/utils/URL';
3+
import axios from 'axios';
4+
5+
export const kiCalendarApi = createApi({
6+
reducerPath: "kiCalendarApi",
7+
baseQuery: fetchBaseQuery({
8+
prepareHeaders: (headers) => {
9+
const token = axios.defaults.headers.common.Authorization;
10+
if (token) headers.set("Authorization", token);
11+
return headers;
12+
},
13+
}),
14+
endpoints: (builder) => ({
15+
getKICalendarEvents: builder.query({
16+
query: ({ month, year }) =>
17+
ENDPOINTS.KI_CALENDAR_EVENTS(month, year),
18+
// `kitchenandinventory/calendar?month=${month}&year=${year}`,
19+
}),
20+
}),
21+
});
22+
23+
export const { useGetKICalendarEventsQuery } = kiCalendarApi;

src/components/ApplicantVolunteerRatio/ApplicantVolunteerRatio.jsx

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,15 @@ function ApplicantVolunteerRatio() {
2525
const fetchAllRoles = async () => {
2626
try {
2727
const response = await getAllApplicantVolunteerRatios({});
28-
const apiData = response.data;
29-
28+
const apiData = response?.data ?? [];
3029
const uniqueRoles = [...new Set(apiData.map(item => item.role))];
3130
const roleOptions = uniqueRoles.map(role => ({ label: role, value: role }));
32-
3331
setAllRoles(roleOptions);
3432
setSelectedRoles(roleOptions);
3533
} catch (err) {
3634
setError('Failed to load roles. Please try again.');
3735
}
3836
};
39-
4037
fetchAllRoles();
4138
}, []);
4239

@@ -56,10 +53,8 @@ function ApplicantVolunteerRatio() {
5653
setData([]);
5754
return;
5855
}
59-
6056
try {
6157
setLoading(true);
62-
6358
const filters = {};
6459
if (startDate) filters.startDate = startDate.toISOString().split('T')[0];
6560
if (endDate) filters.endDate = endDate.toISOString().split('T')[0];
@@ -68,8 +63,7 @@ function ApplicantVolunteerRatio() {
6863
}
6964

7065
const response = await getAllApplicantVolunteerRatios(filters);
71-
const apiData = response.data;
72-
66+
const apiData = response?.data ?? [];
7367
const transformedData = apiData.map(item => ({
7468
role: item.role,
7569
applicants: item.totalApplicants,
@@ -83,7 +77,6 @@ function ApplicantVolunteerRatio() {
8377
setLoading(false);
8478
}
8579
};
86-
8780
fetchFilteredData();
8881
}, [startDate, endDate, selectedRoles]);
8982

src/components/ApplicationAnalytics/jobAnalytics.jsx

Lines changed: 56 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { useState, useMemo } from 'react';
22
import { v4 as uuidv4 } from 'uuid';
3+
import { useSelector } from 'react-redux';
34
import getJobAnalyticsData from './api';
45
import styles from './jobAnalytics.module.css';
5-
import { useSelector } from 'react-redux';
66

77
function JobAnalytics() {
88
const [dateFilter, setDateFilter] = useState('all');
@@ -20,9 +20,7 @@ function JobAnalytics() {
2020

2121
switch (dateFilter) {
2222
case 'weekly':
23-
if (daysAgo <= 7) {
24-
return true;
25-
}
23+
if (daysAgo <= 7) return true;
2624
return false;
2725
case 'monthly':
2826
return daysAgo <= 30;
@@ -59,53 +57,75 @@ function JobAnalytics() {
5957

6058
const maxApplications = Math.max(...processedData.map(item => item.applications), 10);
6159

60+
const xAxisTicks = useMemo(() => {
61+
const ticks = [0];
62+
let value = 5;
63+
while (value < maxApplications) {
64+
ticks.push(value);
65+
value += 5;
66+
}
67+
if (maxApplications > 0 && ticks[ticks.length - 1] !== maxApplications) {
68+
ticks.push(maxApplications);
69+
}
70+
return ticks;
71+
}, [maxApplications]);
72+
6273
return (
63-
<div className={`${darkMode ? styles.jobAnalyticsContainerDarkMode : ''}`}>
64-
<div className={`${styles.jobAnalyticsContainer}`}>
65-
<div className={`${styles.chartContainer}`}>
66-
<h2 className={`${styles.chartTitle}`}>Least Popular Roles</h2>
67-
<div className={`${styles.chartArea}`}>
74+
<div className={darkMode ? styles.jobAnalyticsContainerDarkMode : ''}>
75+
<div className={styles.jobAnalyticsContainer}>
76+
<div className={styles.chartContainer}>
77+
<h2 className={styles.chartTitle}>Least Popular Roles</h2>
78+
<div
79+
className={styles.chartArea}
80+
style={
81+
processedData.length > 0
82+
? { '--x-grid-divisions': String(Math.max(1, xAxisTicks.length - 1)) }
83+
: undefined
84+
}
85+
>
6886
{processedData.length > 0 ? (
6987
<>
70-
<div className={`${styles.gridLines}`} />
71-
<div className={`${styles.yAxis}`}>
88+
<div className={styles.gridLines} />
89+
<div className={styles.yAxis}>
7290
{processedData.map(item => (
73-
<div key={uuidv4()} className={`${styles.yAxisLabel}`}>
91+
<div key={uuidv4()} className={styles.yAxisLabel}>
7492
{item.role}
7593
</div>
7694
))}
7795
</div>
78-
<div className={`${styles.xAxis}`}>
79-
{[0, 5, 10, 15, 20, 25].map(tick => (
96+
<div className={styles.xAxis}>
97+
{xAxisTicks.map(tick => (
8098
<div
8199
key={tick}
82-
className={`{${styles.xAxisTick}`}
83-
style={{ left: `${(tick / maxApplications) * 100}%` }}
100+
className={styles.xAxisTick}
101+
style={{
102+
left: `${(tick / maxApplications) * 100}%`,
103+
transform: 'translateX(-50%)',
104+
}}
84105
>
85-
{tick <= maxApplications ? tick : ''}
106+
{tick}
86107
</div>
87108
))}
88109
</div>
89-
<div className={`${styles.barsContainer}`}>
110+
<div className={styles.barsContainer}>
90111
{processedData.map((item, index) => (
91112
<div
92113
key={uuidv4()}
93-
className={`${styles.barRow}`}
114+
className={styles.barRow}
94115
onMouseEnter={() => setHoveredBar(index)}
95116
onMouseLeave={() => setHoveredBar(null)}
96117
>
97118
<div
98-
className={`${styles.bar}`}
119+
className={styles.bar}
99120
style={{
100121
width: `${(item.applications / maxApplications) * 100}%`,
101122
}}
102123
>
103-
<div className={`${styles.dataLabel}`}>{item.applications}</div>
124+
<div className={styles.dataLabel}>{item.applications}</div>
104125
</div>
105-
106126
{hoveredBar === index && (
107-
<div className={`${styles.tooltip}`}>
108-
<div className={`${styles.tooltipTitle}`}>
127+
<div className={styles.tooltip}>
128+
<div className={styles.tooltipTitle}>
109129
<strong>{item.role}</strong>
110130
</div>
111131
<div>Applications: {item.applications}</div>
@@ -114,15 +134,15 @@ function JobAnalytics() {
114134
)}
115135
</div>
116136
))}
117-
<div className={`${styles.xAxisLabel}`}>Applications</div>
118137
</div>
138+
<div className={styles.xAxisLabel}>Applications</div>
119139
</>
120140
) : (
121-
<div className={`${styles.noData}`}>No data available for the selected filters</div>
141+
<div className={styles.noData}>No data available for the selected filters</div>
122142
)}
123143
</div>
124144
{processedData.length > 0 && (
125-
<div className={`${styles.summaryInfo}`}>
145+
<div className={styles.summaryInfo}>
126146
<div>
127147
<strong>Showing:</strong> {processedData.length} role(s)
128148
</div>
@@ -137,30 +157,26 @@ function JobAnalytics() {
137157
</div>
138158
)}
139159
</div>
140-
<div className={`${styles.filtersPanel}`}>
141-
<div className={`${styles.filterGroup}`}>
142-
<div className={`${styles.filterLabel}`}>Dates</div>
160+
<div className={styles.filtersPanel}>
161+
<div className={styles.filterGroup}>
162+
<div className={styles.filterLabel}>Dates</div>
143163
<select
144164
value={dateFilter}
145-
onChange={e => {
146-
setDateFilter(e.target.value);
147-
}}
148-
className={`${styles.filterSelectJobAnalytics}`}
165+
onChange={e => setDateFilter(e.target.value)}
166+
className={styles.filterSelectJobAnalytics}
149167
>
150168
<option value="all">ALL</option>
151169
<option value="weekly">Last 7 Days</option>
152170
<option value="monthly">Last 30 Days</option>
153171
<option value="yearly">Last Year</option>
154172
</select>
155173
</div>
156-
<div className={`${styles.filterGroup}`}>
157-
<div className={`${styles.filterLabel}`}>Role</div>
174+
<div className={styles.filterGroup}>
175+
<div className={styles.filterLabel}>Role</div>
158176
<select
159177
value={selectedRole}
160-
onChange={e => {
161-
setSelectedRole(e.target.value);
162-
}}
163-
className={`${styles.filterSelectJobAnalytics}`}
178+
onChange={e => setSelectedRole(e.target.value)}
179+
className={styles.filterSelectJobAnalytics}
164180
>
165181
{roles.map(role => (
166182
<option key={role} value={role}>

src/components/ApplicationAnalytics/jobAnalytics.module.css

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@
6060
bottom: 60px;
6161
background-image: linear-gradient(to right, #e0e0e0 1px, transparent 1px),
6262
linear-gradient(to bottom, #e0e0e0 1px, transparent 1px);
63-
background-size: 10% 25%;
63+
background-size: calc(100% / var(--x-grid-divisions, 10)) 25%;
6464
opacity: 0.5;
6565
}
6666

@@ -95,17 +95,14 @@
9595
right: 40px;
9696
bottom: 40px;
9797
height: 30px;
98-
display: flex;
99-
justify-content: space-between;
100-
align-items: flex-start;
10198
border-top: 1px solid #9aa0a6;
10299
padding-top: 5px;
103100
}
104101

105102
.xAxisTick {
103+
position: absolute;
106104
font-size: 12px;
107105
color: #5f6368;
108-
position: relative;
109106
text-align: center;
110107
min-width: 20px;
111108
}
@@ -188,6 +185,10 @@
188185
border: 2px solid #1a73e8;
189186
}
190187

188+
.tooltipTitle {
189+
margin-bottom: 4px;
190+
}
191+
191192
.tooltip strong {
192193
font-weight: 600;
193194
}
@@ -292,6 +293,7 @@
292293
.jobAnalyticsContainerDarkMode .xAxisTick {
293294
color: #e8eaed;
294295
}
296+
295297
.jobAnalyticsContainerDarkMode .xAxisLabel {
296298
color: #e8eaed;
297299
}
@@ -301,9 +303,11 @@
301303
color: #ffffff;
302304
border-color: #5f6368;
303305
}
306+
304307
.jobAnalyticsContainerDarkMode .filterGroup {
305308
background-color: #333;
306309
}
310+
307311
.jobAnalyticsContainerDarkMode .chartTitle {
308312
color: #e8eaed;
309313
}
@@ -322,6 +326,7 @@
322326
.jobAnalyticsContainerDarkMode .tooltip {
323327
background-color: #333;
324328
}
329+
325330
.jobAnalyticsContainerDarkMode .tooltip strong {
326331
color: #ffffff;
327332
}
@@ -359,6 +364,10 @@
359364
width: 110px;
360365
}
361366

367+
.yAxisLabel {
368+
font-size: 11px;
369+
}
370+
362371
.barsContainer {
363372
left: 120px;
364373
right: 20px;

0 commit comments

Comments
 (0)