Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 1 addition & 6 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

# Run Prettier formatting only on staged files (using lint-staged)
# Run checks only on staged files.
npx lint-staged || exit 1

# Run lint, if it fails, the commit will be aborted
npm run lint || exit 1

git add .
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,7 @@
"lint-staged": {
"*.{js,jsx}": [
"prettier --write",
"eslint --fix",
"git add"
"eslint --fix"
]
}
}
9 changes: 9 additions & 0 deletions src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import InactivityHandler from "./helper/inactivityhandler";
import Examination from "./Modules/Examination/examination";
import Database from "./Modules/Database/database";
import ProgrammeCurriculumRoutes from "./Modules/Program_curriculum/programmCurriculum";
import ComplaintManagementModule from "./Modules/ComplaintManagement";
import NotFoundPage from "./components/NotFoundPage";

const theme = createTheme({
Expand Down Expand Up @@ -82,6 +83,14 @@ export default function App() {
<Route path="/reset-password" element={<ForgotPassword />} />
<Route path="/examination/*" element={<Examination />} />
<Route path="/database/*" element={<Database />} />
<Route
path="/complaint/*"
element={
<Layout>
<ComplaintManagementModule />
</Layout>
}
/>
<Route path="*" element={<NotFoundPage />} />
</Routes>
</MantineProvider>
Expand Down
Binary file added src/Modules/ComplaintManagement.zip
Binary file not shown.
6 changes: 6 additions & 0 deletions src/Modules/ComplaintManagement/ComplaintCreate.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import ComplaintManager from "./components/ComplaintManager";

// Thin view that composes micro-components through ComplaintManager.
export default function ComplaintCreate() {
return <ComplaintManager defaultMode="create" />;
}
5 changes: 5 additions & 0 deletions src/Modules/ComplaintManagement/ComplaintList.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import ComplaintManager from "./components/ComplaintManager";

export default function ComplaintList() {
return <ComplaintManager defaultMode="list" />;
}
254 changes: 254 additions & 0 deletions src/Modules/ComplaintManagement/ComplaintManagement.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,254 @@
/* ──────────────────────────────────────────────────────────
Complaint Management – Module Styles
Aligned with the Fusion design system (#15abff accent, #F5F7F8 canvas)
────────────────────────────────────────────────────────── */

.page {
background: #ffffff;
border: 1px solid #e8eef3;
border-radius: 8px;
padding: 1.25rem 1.5rem;
}

/* ── Global Mantine overrides (scoped to .page) ───────── */

.page :global(.mantine-Button-root) {
border-radius: 6px;
font-weight: 500;
font-size: 0.875rem;
transition: all 0.15s ease;
}

.page :global(.mantine-Button-root):hover {
transform: translateY(-1px);
box-shadow: 0 2px 8px rgba(21, 171, 255, 0.18);
}

.page :global(.mantine-Input-input),
.page :global(.mantine-Select-input),
.page :global(.mantine-Textarea-input) {
border-radius: 6px;
border: 1px solid #d5dce4;
background: #ffffff;
transition: border-color 0.2s ease, box-shadow 0.2s ease;
}

.page :global(.mantine-Input-input):focus,
.page :global(.mantine-Select-input):focus,
.page :global(.mantine-Textarea-input):focus {
border-color: #15abff;
box-shadow: 0 0 0 3px rgba(21, 171, 255, 0.12);
}

/* ── Page header ──────────────────────────────────────── */

.headerBlock {
display: flex;
justify-content: space-between;
align-items: flex-start;
gap: 1rem;
margin-bottom: 1.25rem;
}

.title {
color: #1a1a2e;
font-weight: 600;
font-size: 1.35rem;
letter-spacing: -0.01em;
}

.subtitle {
color: #6b7a8d;
font-weight: 400;
font-size: 0.875rem;
margin-top: 2px;
}

.actions {
display: flex;
gap: 0.5rem;
flex-wrap: wrap;
}

.statusNote {
color: #94a3b8;
font-size: 0.8rem;
margin-top: 0.35rem;
}

/* ── Card & panel surfaces ────────────────────────────── */

.tablePanel,
.oversightHeader,
.reportHeader,
.notificationPanel,
.moduleCard {
background: #ffffff;
border: 1px solid #e8eef3;
border-radius: 8px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);
padding: 1rem;
}

/* ── Summary stat cards ───────────────────────────────── */

.summaryCard {
background: #ffffff;
border: 1px solid #e8eef3;
border-radius: 8px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);
padding: 1rem 1.25rem;
transition: all 0.2s ease;
position: relative;
overflow: hidden;
}

.summaryCard::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 3px;
background: linear-gradient(90deg, #15abff, #6dc8ff);
opacity: 0;
transition: opacity 0.2s ease;
}

.summaryCard:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(21, 171, 255, 0.1);
border-color: #c4e2f5;
}

.summaryCard:hover::before {
opacity: 1;
}

/* ── Toolbars ─────────────────────────────────────────── */

.notificationToolbar,
.reportToolbar {
background: #F5F7F8;
border: 1px solid #e8eef3;
border-radius: 6px;
padding: 0.875rem;
}

/* ── Notification cards ───────────────────────────────── */

.notificationEmpty {
background: #F5F7F8;
border: 1px dashed #cbd5e1;
border-radius: 8px;
padding: 2rem 1rem;
text-align: center;
color: #6b7a8d;
}

.notificationCardUnread {
background: #f0f9ff;
border-left: 3px solid #15abff;
transition: background 0.15s ease;
}

.notificationCardRead {
background: #ffffff;
border-left: 3px solid #d5dce4;
transition: background 0.15s ease;
}

.notificationCardUnread:hover {
background: #e6f4ff;
}

.notificationCardRead:hover {
background: #F5F7F8;
}

/* ── Data tables ──────────────────────────────────────── */

.tableSurface {
border: 1px solid #e8eef3;
border-radius: 8px;
overflow: hidden;
}

.tableClean :global(thead th) {
background: #F5F7F8;
color: #3d4f5f;
font-weight: 600;
font-size: 0.78rem;
text-transform: uppercase;
letter-spacing: 0.04em;
white-space: nowrap;
border-bottom: 1px solid #e8eef3;
padding: 0.75rem 1rem;
}

.tableClean :global(tbody td) {
vertical-align: middle;
padding: 0.75rem 1rem;
border-bottom: 1px solid #f1f5f8;
color: #3d4f5f;
font-size: 0.875rem;
}

.tableClean :global(tbody tr) {
transition: background 0.1s ease;
}

.tableClean :global(tbody tr:hover) {
background: #f8fbff;
}

/* ── Utilities ────────────────────────────────────────── */

.cellClamp {
max-width: 220px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}

.monoRef {
font-family: 'SFMono-Regular', Menlo, Consolas, 'Courier New', monospace;
color: #3d4f5f;
font-size: 0.8rem;
font-weight: 500;
background: #F5F7F8;
padding: 2px 6px;
border-radius: 4px;
border: 1px solid #e8eef3;
}

.statusBadge {
font-weight: 600;
font-size: 0.75rem;
padding: 3px 10px;
border-radius: 999px;
}

.pillInfo {
background: #15abff12;
border: 1px solid #15abff30;
color: #0d8ddb;
border-radius: 999px;
padding: 3px 10px;
font-size: 0.78rem;
font-weight: 500;
display: inline-block;
}

/* ── Responsive ───────────────────────────────────────── */

@media (max-width: 768px) {
.headerBlock {
flex-direction: column;
align-items: stretch;
}

.cellClamp {
max-width: 140px;
}
}
16 changes: 16 additions & 0 deletions src/Modules/ComplaintManagement/api.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import axios from "axios";
import { COMPLAINT_API_BASE } from "../../routes/complaintRoutes";

const complaintApi = axios.create({
baseURL: COMPLAINT_API_BASE,
});

complaintApi.interceptors.request.use((config) => {
const token = localStorage.getItem("authToken");
if (token) {
config.headers.Authorization = `Token ${token}`;
}
return config;
});

export default complaintApi;
Loading