diff --git a/src/components/Collaboration/JobApplicationForm/JobApplicationForm.jsx b/src/components/Collaboration/JobApplicationForm/JobApplicationForm.jsx
index 92bb9090b8..4a64084799 100644
--- a/src/components/Collaboration/JobApplicationForm/JobApplicationForm.jsx
+++ b/src/components/Collaboration/JobApplicationForm/JobApplicationForm.jsx
@@ -22,6 +22,9 @@ function JobApplicationForm() {
const [companyPosition, setCompanyPosition] = useState('');
const [websiteSocial, setWebsiteSocial] = useState('');
const [resumeFile, setResumeFile] = useState(null);
+ const [resumeStatus, setResumeStatus] = useState('idle');
+ // idle | uploading | success | error
+ const [resumeError, setResumeError] = useState('');
const resumeInputRef = useRef(null);
const darkMode = useSelector(state => state.theme?.darkMode);
@@ -94,7 +97,40 @@ function JobApplicationForm() {
const handleResumeChange = e => {
const f = e.target.files?.[0] || null;
+
+ if (!f) {
+ setResumeFile(null);
+ setResumeStatus('idle');
+ return;
+ }
+
+ // Basic validation (optional but recommended)
+ const allowedTypes = [
+ 'application/pdf',
+ 'application/msword',
+ 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
+ ];
+
+ if (!allowedTypes.includes(f.type)) {
+ setResumeStatus('error');
+ setResumeError('Only PDF or Word documents are allowed.');
+ setResumeFile(null);
+ toast.error('Invalid file type. Please upload PDF or DOC/DOCX.');
+ return;
+ }
+
setResumeFile(f);
+ setResumeStatus('success');
+ setResumeError('');
+
+ toast.success(`Resume selected: ${f.name}`);
+ };
+
+ const handleRemoveResume = () => {
+ setResumeFile(null);
+ setResumeStatus('idle');
+ setResumeError('');
+ if (resumeInputRef.current) resumeInputRef.current.value = '';
};
const validateBeforeSubmit = () => {
@@ -132,6 +168,8 @@ function JobApplicationForm() {
setCompanyPosition('');
setWebsiteSocial('');
setResumeFile(null);
+ setResumeStatus('idle');
+ setResumeError('');
if (resumeInputRef.current) resumeInputRef.current.value = '';
setAnswers(new Array((filteredForm?.questions ?? []).length).fill(''));
};
@@ -244,15 +282,40 @@ function JobApplicationForm() {
value={websiteSocial}
onChange={e => setWebsiteSocial(e.target.value)}
/>
-
+
1. How did you hear about One Community?
diff --git a/src/components/Collaboration/JobApplicationForm/JobApplicationForm.module.css b/src/components/Collaboration/JobApplicationForm/JobApplicationForm.module.css
index 39bdde72f9..67fbc63b62 100644
--- a/src/components/Collaboration/JobApplicationForm/JobApplicationForm.module.css
+++ b/src/components/Collaboration/JobApplicationForm/JobApplicationForm.module.css
@@ -28,11 +28,14 @@
width: 75%;
padding: 2%;
justify-content: space-between;
+ align-items: center;
+ margin: 0 auto;
}
.headerLeft {
display: flex;
gap: 10px;
+ align-items: center;
}
.headerRight {
@@ -40,32 +43,31 @@
align-items: center;
}
-.jobTitleInput {
- padding: 5px;
- border: 1px solid #ccc;
- border-radius: 5px;
-}
-
+.jobTitleInput,
.jobSelect {
- padding: 5px;
+ padding: 10px;
border: 1px solid #ccc;
border-radius: 5px;
+ height: 40px;
+ box-sizing: border-box;
}
.goButton {
background-color: #4caf50;
- color: white;
+ color: #fff;
border: none;
- padding: 5px 10px;
+ padding: 10px 14px;
border-radius: 5px;
cursor: pointer;
+ height: 40px;
}
.formContainer {
background-color: #f9f9f9;
padding: 2%;
width: 75%;
- box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
+ box-shadow: 0 0 10px rgb(0 0 0 / 10%);
+ margin: 0 auto;
}
.formTitle {
@@ -90,7 +92,7 @@
gap: 15px;
background-color: #d9d9d9;
padding: 2%;
- border-radius: 1%;
+ border-radius: 5px;
}
.formContentGroup {
@@ -109,33 +111,37 @@
display: flex;
flex-wrap: wrap;
gap: 10px;
+ align-items: stretch;
+}
+
+.formProfileDetailGroup input,
+.resumeWrapper {
+ height: 40px;
+ display: flex;
}
-.formProfileDetailGroup input {
+.formProfileDetailGroup input,
+.formGroup input {
flex: 1;
min-width: 200px;
padding: 10px;
border: 1px solid #ccc;
border-radius: 5px;
+ height: 40px;
+ box-sizing: border-box;
}
.formGroup h2 {
margin-bottom: 5px;
font-weight: bold;
text-align: left;
- color: black;
+ color: #000;
font-size: medium;
}
-.formGroup input {
- padding: 10px;
- border: 1px solid #ccc;
- border-radius: 5px;
-}
-
.submitButton {
background-color: #4caf50;
- color: white;
+ color: #fff;
border: none;
padding: 10px;
border-radius: 5px;
@@ -143,13 +149,11 @@
align-self: center;
}
+/* POPUP */
.popupOverlay {
position: fixed;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- background: rgba(30, 41, 65, 0.7);
+ inset: 0;
+ background: rgb(30 41 65 / 70%);
display: flex;
align-items: center;
justify-content: center;
@@ -164,7 +168,7 @@
border-radius: 16px;
max-width: 420px;
min-width: 320px;
- box-shadow: 0 8px 32px rgba(0, 0, 0, 0.32);
+ box-shadow: 0 8px 32px rgb(0 0 0 / 32%);
display: flex;
flex-direction: column;
align-items: flex-start;
@@ -173,19 +177,16 @@
.popupCloseBtn {
position: absolute;
- top: 12px;
- right: 16px;
+ inset: 12px 16px auto auto;
background: transparent;
border: none;
font-size: 1.5rem;
color: #333;
cursor: pointer;
- transition: color 0.2s;
}
.popupCloseBtn:hover {
color: #98cb03;
- background-color: transparent;
}
.popupContent h2 {
@@ -202,162 +203,128 @@
line-height: 1.5;
}
+/* RESUME UPLOAD */
+.resumeWrapper {
+ display: flex;
+ align-items: stretch;
+ gap: 6px;
+ flex: 1;
+ min-width: 200px;
+ height: 40px;
+}
+
.resumeLabel {
- display: inline-flex;
- margin-bottom: 0;
+ display: flex;
align-items: center;
- gap: 10px;
- cursor: pointer;
- padding: 8px 12px;
- border-radius: 8px;
- background: #ffffff;
- border: 1px solid #cfcfcf;
+ justify-content: space-between;
+ flex: 1;
+ min-width: 200px;
+ height: 40px;
+ padding: 0 10px;
+ border-radius: 5px;
+ background: #fff;
+ border: 1px solid #ccc;
color: #222;
font-size: 14px;
- line-height: 1;
+ cursor: pointer;
user-select: none;
- transition: background 150ms ease, box-shadow 150ms ease, transform 120ms ease;
+ box-sizing: border-box;
+ transition: background 150ms ease, box-shadow 150ms ease;
}
.resumeLabel:hover {
background: #f6f6f6;
- box-shadow: 0 6px 18px rgba(0, 0, 0, 0.04);
- transform: translateY(-1px);
}
.resumeLabel input[type='file'] {
display: none;
}
-.resumeLabel .fileName {
- font-size: 13px;
- color: #555;
- background: #f2f6f9;
- padding: 4px 8px;
- border-radius: 6px;
- border: 1px solid #e6eef6;
+.fileName {
+ flex: 1;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
}
+/* REMOVE BUTTON */
+.removeResumeBtn {
+ width: 40px;
+ height: 40px;
+ flex-shrink: 0;
+ border-radius: 5px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background: transparent;
+ border: 1px solid #ccc;
+ color: #c62828;
+ cursor: pointer;
+}
+
+.removeResumeBtn:hover {
+ background: rgb(198 40 40 / 10%);
+}
+
+.resumeLabel.success {
+ border-color: #4caf50;
+}
+
+.resumeLabel.error {
+ border-color: #c62828;
+}
+
+/* DARK MODE */
.darkMode {
background: #1b2a41;
color: #e0e0e0;
- transition: background 0.3s, color 0.3s;
}
.darkMode .formContainer {
background: #1c2541;
color: #e0e0e0;
- box-shadow: 0 8px 24px rgba(0, 0, 0, 0.7);
- transition: background 0.3s, color 0.3s;
+ box-shadow: 0 8px 24px rgb(0 0 0 / 70%);
}
.darkMode .headerContent {
background: #1c2541;
- transition: background 0.3s;
- z-index: 1;
}
-.darkMode .jobTitleInput,
-.darkMode .jobSelect,
.darkMode input,
.darkMode select,
.darkMode textarea {
background: #181a1b;
color: #f1f1f1;
border: 1px solid #444;
- transition: background 0.3s, color 0.3s, box-shadow 0.3s;
-}
-
-.darkMode .jobSelect {
- background-image: url("data:image/svg+xml;utf8,
");
- background-repeat: no-repeat;
- background-position: right 12px center;
- background-size: 18px 18px;
- padding-right: 36px;
-}
-
-.darkMode .jobSelect:focus,
-.darkMode .jobSelect:active {
- background-image: url("data:image/svg+xml;utf8,
");
-}
-
-.darkMode .submitButton,
-.darkMode .goButton,
-.darkMode .btn {
- background: #225163;
- color: #f1f1f1;
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.18);
- transition: background 0.3s, color 0.3s;
}
.darkMode .form {
background: #23272a;
- border-radius: 8px;
- transition: background 0.3s;
}
.darkMode .formTitle {
color: #d9d9d9;
- transition: color 0.3s;
-}
-
-.darkMode .popupOverlay {
- background: rgba(30, 41, 65, 0.85);
-}
-
-.darkMode .popupContent {
- background: #225163;
- color: #f1f1f1;
- box-shadow: 0 8px 32px rgba(0, 0, 0, 0.7);
-}
-
-.darkMode .popupCloseBtn {
- color: #f1f1f1;
- background-color: transparent;
-}
-
-.darkMode .popupCloseBtn:hover {
- color: #9c0;
-}
-
-.darkMode .popupContent h2 {
- color: #9c0;
-}
-
-.darkMode .popupContent p {
- color: #e0e0e0;
-}
-
-.darkMode a {
- color: #9c0;
- text-decoration: underline;
- transition: color 0.3s;
-}
-
-.darkMode label {
- color: #e0e0e0;
- transition: color 0.3s;
-}
-
-.darkMode .formGroup h2 {
- color: #9c0;
- transition: color 0.3s;
}
.darkMode .resumeLabel {
background: #1c2541;
- border-color: #2b3f57;
+ border: 1px solid #444;
color: #e6eef6;
- box-shadow: none;
}
.darkMode .resumeLabel:hover {
background: #22364e;
- box-shadow: 0 6px 18px rgba(0, 0, 0, 0.35);
}
-.darkMode .resumeLabel .fileName {
- background: rgba(255, 255, 255, 0.04);
+.darkMode .fileName {
color: #cfe7ff;
- border-color: rgba(255, 255, 255, 0.05);
}
+
+.darkMode .removeResumeBtn {
+ border: 1px solid #444;
+ color: #ff6b6b;
+}
+
+.darkMode .removeResumeBtn:hover {
+ background: rgb(255 107 107 / 10%);
+}
\ No newline at end of file
diff --git a/src/components/JobCCDashboard/JobAnalytics/JobAnalytics.jsx b/src/components/JobCCDashboard/JobAnalytics/JobAnalytics.jsx
index aa94ac6187..36241f52e0 100644
--- a/src/components/JobCCDashboard/JobAnalytics/JobAnalytics.jsx
+++ b/src/components/JobCCDashboard/JobAnalytics/JobAnalytics.jsx
@@ -66,6 +66,30 @@ const CONFIG = {
},
};
+// ======================== SHARED CONSTANTS ========================
+const AXIS_TICK = { fontSize: 12 };
+
+const CHART_MARGIN = { top: 10, right: 10, left: 0, bottom: 10 };
+
+const GRID_PROPS = {
+ strokeDasharray: '3 3',
+};
+
+const getTooltipStyles = darkMode => ({
+ contentStyle: {
+ backgroundColor: darkMode ? '#1f2937' : '#ffffff',
+ borderColor: darkMode ? '#374151' : '#e5e7eb',
+ color: darkMode ? '#f9fafb' : '#111827',
+ },
+ itemStyle: {
+ color: darkMode ? '#f9fafb' : '#111827',
+ },
+});
+
+const getCursorStyle = darkMode => ({
+ fill: darkMode ? 'rgba(255,255,255,0.05)' : 'rgba(0,0,0,0.05)',
+});
+
// ======================== UTILITIES ========================
const calculatePercentageChange = (current, previous) => {
if (previous === 0) return { value: 100, isPositive: true, formatted: '+100%' };
@@ -417,8 +441,24 @@ function DateRangeSelector({ dateRange, setDateRange, comparisonPeriod, setCompa
// ======================== MAIN ========================
function JobAnalytics({ darkMode, role, hasPermission: hasPerm }) {
// Theme attribute for global CSS
+ // Sync with Global App Theme (body classes) and Local Component Theme (data-theme)
useEffect(() => {
- document.documentElement.setAttribute('data-theme', darkMode ? 'dark' : 'light');
+ const root = document.documentElement;
+ const body = document.body;
+
+ if (darkMode) {
+ // 1. Set the attribute for your JobAnalytics.module.css
+ root.setAttribute('data-theme', 'dark');
+
+ // 2. Add the classes required by the global CSS you found
+ body.classList.add('dark-mode');
+ body.classList.add('bm-dashboard-dark');
+ } else {
+ // 3. Clean up when switching back to light mode
+ root.setAttribute('data-theme', 'light');
+ body.classList.remove('dark-mode');
+ body.classList.remove('bm-dashboard-dark');
+ }
}, [darkMode]);
const canViewAnalytics = hasPerm('getJobReports');
@@ -526,11 +566,11 @@ function JobAnalytics({ darkMode, role, hasPermission: hasPerm }) {
-
-
-
-
-
+
+
+
+
+
-
+
-
+
))}
-
+
@@ -666,7 +712,15 @@ function JobAnalytics({ darkMode, role, hasPermission: hasPerm }) {
tick={{ fontSize: 12 }}
domain={[0, 100]}
/>
-
+
= 641px) and (width <= 1199px) {
.chartsGrid {
grid-template-columns: repeat(2, 1fr);
}
}
/* Desktop + Large Screens */
-@media (min-width: 1200px) {
+@media (width >= 1200px) {
.chartsGrid {
display: grid;
grid-template-columns: repeat(3, 1fr);
@@ -324,6 +364,7 @@
box-shadow: var(--shadow);
transition: transform 0.15s ease;
}
+
.chartCard:hover {
transform: translateY(-3px);
}
@@ -334,21 +375,26 @@
gap: 12px;
margin-bottom: 16px;
}
+
.chartIconWrap {
- background: rgba(0, 0, 0, 0.05);
+ background: rgb(0 0 0 / 5%);
padding: 8px;
border-radius: 10px;
}
+
[data-theme='dark'] .chartIconWrap {
- background: rgba(255, 255, 255, 0.06);
+ background: rgb(255 255 255 / 6%);
}
+
.chartIcon {
color: var(--muted);
}
+
.chartTitle {
margin: 0;
font-weight: 700;
}
+
.chartBody {
margin: 0 -4px;
}
@@ -361,4 +407,4 @@
/******** Charts Grid Stroke ********/
.gridStroke line {
stroke: var(--grid-stroke) !important;
-}
+}
\ No newline at end of file