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)} /> - +
+ + + {resumeFile && ( + + )} +

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