Skip to content

Feat/shadcn layout theme overhaul#2

Merged
denmark0128 merged 3 commits intodevelopmentfrom
feat/shadcn-layout-theme-overhaul
Feb 28, 2026
Merged

Feat/shadcn layout theme overhaul#2
denmark0128 merged 3 commits intodevelopmentfrom
feat/shadcn-layout-theme-overhaul

Conversation

@denmark0128
Copy link
Owner

No description provided.

…ations

- Added recruitment API functions for job postings: get, create, update, and delete.
- Implemented hooks for managing job postings and applications using React Query.
- Enhanced Admin Settings page with improved layout and accessibility features.
- Updated Audit Trail page with better styling and responsive design.
- Introduced new types for leave and attendance management.
- Enhanced Tailwind CSS configuration with theme tokens and improved dark mode support.
- Updated TypeScript configuration for better path resolution.
- Integrated shadcn components and improved sidebar navigation experience.
- Fixed layout stability issues and ensured consistent dark mode appearance.
Copilot AI review requested due to automatic review settings February 28, 2026 07:22
@denmark0128 denmark0128 merged commit c005c19 into development Feb 28, 2026
2 checks passed
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR overhauls the UI layout and theming by adopting shadcn/Radix primitives (sidebar, dialogs, inputs, toasts) and expands the product surface area by implementing Leave, Performance, and Recruitment modules end-to-end (frontend hooks/pages + backend models/routers/services). It also tightens security-related configuration by requiring strong secrets and updating defaults in tests and env examples.

Changes:

  • Add shadcn CLI configuration, Tailwind theme tokens, and UI primitives (sidebar, dialog, select, toasts, date picker, etc.), then refactor layout and common UI to use them.
  • Implement Leave Requests + Performance Reviews + Recruitment (jobs/applications) across frontend (pages/hooks/types) and backend (models/schemas/services/routers).
  • Strengthen operational/security configuration (required secrets in compose/config, cookie flags, password validation) and update tests accordingly.

Reviewed changes

Copilot reviewed 93 out of 94 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
progress.md Documents recent UI/theming overhaul progress
frontend/vite.config.ts Adds @ alias resolution for Vite
frontend/tsconfig.json Adds TS path mapping for @/*
frontend/tsconfig.app.json Adds TS path mapping for @/* in app build
frontend/tailwind.config.ts Adds shadcn-style theme tokens + animate plugin
frontend/src/types/index.ts Adds list wrappers + Leave/Recruitment/Performance types
frontend/src/modules/settings/AuditTrailPage.tsx Updates styling for dark mode + table overflow handling
frontend/src/modules/settings/AdminSettingsPage.tsx Refactors header/actions + styling adjustments
frontend/src/modules/recruitment/hooks.ts Implements React Query hooks for recruitment module
frontend/src/modules/recruitment/api.ts Adds recruitment API client functions
frontend/src/modules/profile/ProfilePage.tsx Aligns profile cards to theme tokens
frontend/src/modules/performance/hooks.ts Implements React Query hooks for performance module
frontend/src/modules/performance/api.ts Adds performance API client functions
frontend/src/modules/performance/PerformancePage.tsx Replaces placeholder with full Performance UI CRUD
frontend/src/modules/payroll/PayrollPage.tsx Switches to DatePicker + adapts employees response shape
frontend/src/modules/leave/hooks.ts Implements React Query hooks for leave module
frontend/src/modules/leave/api.ts Adds leave request API client functions
frontend/src/modules/leave/LeavePage.tsx Replaces placeholder with full Leave Requests UI
frontend/src/modules/employees/api.ts Updates employees API to return { items, total }
frontend/src/modules/employees/EmployeesPage.tsx Adapts employees list usage + pagination callback
frontend/src/modules/employees/EmployeeForm.tsx Layout tweaks; schedule editor adjustments
frontend/src/modules/employees/EmployeeDetailPage.tsx Adapts employee lookup to new list shape
frontend/src/modules/departments/DepartmentsPage.tsx Adapts employee options to new list shape + pagination callback
frontend/src/modules/departments/DepartmentDetailPage.tsx Adapts employee filtering to new list shape
frontend/src/modules/dashboard/DashboardPage.tsx Adapts employees list shape + dark mode styles
frontend/src/main.tsx Adds ThemeProvider wrapper
frontend/src/lib/utils.ts Adjusts imports (clsx/twMerge) formatting
frontend/src/layouts/MainLayout.tsx Replaces custom sidebar with shadcn sidebar composition
frontend/src/index.css Moves to CSS variables + dark-mode overrides + scrollbar behavior
frontend/src/hooks/use-mobile.tsx Adds mobile breakpoint hook
frontend/src/context/ThemeContext.tsx Adds a (separate) theme context implementation
frontend/src/context/NotificationContext.tsx Replaces custom notifications with Sonner toasts
frontend/src/components/ui/tooltip.tsx Adds Radix tooltip wrapper
frontend/src/components/ui/textarea.tsx Adds shadcn textarea component
frontend/src/components/ui/tabs.tsx Updates tabs to shadcn/Radix implementation
frontend/src/components/ui/sonner.tsx Adds themed Sonner toaster wrapper
frontend/src/components/ui/skeleton.tsx Adds skeleton component
frontend/src/components/ui/sheet.tsx Adds sheet (dialog) component
frontend/src/components/ui/separator.tsx Adds separator component
frontend/src/components/ui/select.tsx Replaces native select with Radix-based select
frontend/src/components/ui/popover.tsx Updates popover to shadcn/Radix implementation
frontend/src/components/ui/pagination.tsx Adds pagination primitives
frontend/src/components/ui/modal.tsx Reimplements Modal via Dialog primitives
frontend/src/components/ui/label.tsx Replaces label with Radix label wrapper
frontend/src/components/ui/input.tsx Replaces input with shadcn input component
frontend/src/components/ui/dropdown-menu.tsx Expands dropdown menu primitives to shadcn/Radix set
frontend/src/components/ui/dialog.tsx Adds dialog primitives
frontend/src/components/ui/date-picker.tsx Adds reusable date picker component
frontend/src/components/ui/collapsible.tsx Adds collapsible primitives
frontend/src/components/ui/card.tsx Updates card primitives to shadcn style
frontend/src/components/ui/calendar.tsx Updates calendar to shadcn DayPicker integration
frontend/src/components/ui/button.tsx Updates button component to shadcn variant system
frontend/src/components/ui/badge.tsx Updates badge component to shadcn variant system
frontend/src/components/ui/avatar.tsx Adds Radix avatar wrapper
frontend/src/components/ui/alert.tsx Updates alert to shadcn variant system
frontend/src/components/theme-provider.tsx Adds shadcn-style theme provider for light/dark/system
frontend/src/components/shared/TableControls.tsx Replaces simple pagination with numbered pagination UI
frontend/src/components/shared/PageHeader.tsx Adds dark-mode styling to header text
frontend/src/components/shared/ImageDropInput.tsx Adds dark-mode styling
frontend/src/components/mode-toggle.tsx Adds theme toggle dropdown
frontend/src/components/app-sidebar.tsx Adds composed AppSidebar using shadcn sidebar primitives
frontend/package.json Adds Radix deps, Sonner, Tailwind animate, etc.
frontend/index.html Adds early theme bootstrap script + color-scheme meta
frontend/components.json Adds shadcn CLI config
docker-compose.yml Requires secret env vars + adds backend healthcheck gating
backend/tests/test_leave_requests.py Adds leave request validation tests
backend/tests/test_employees.py Updates employee list assertions for { items, total }
backend/tests/test_auth.py Updates passwords + employee list shape usage
backend/tests/test_audit.py Updates test passwords
backend/tests/test_attendance.py Updates biometric ingest API key usage
backend/tests/conftest.py Sets required env vars for tests + updates default passwords
backend/app/settings/schemas.py Migrates Pydantic v2 config to ConfigDict
backend/app/recruitment/service.py Implements recruitment service logic
backend/app/recruitment/schemas.py Adds recruitment Pydantic schemas
backend/app/recruitment/router.py Adds recruitment endpoints + audit logging
backend/app/recruitment/models.py Adds recruitment SQLAlchemy models/enums
backend/app/performance/service.py Implements performance review service logic
backend/app/performance/schemas.py Adds performance Pydantic schemas
backend/app/performance/router.py Adds performance endpoints + audit logging
backend/app/performance/models.py Adds performance SQLAlchemy models/enums
backend/app/payroll/router.py Removes N+1 employee lookups via batch loading
backend/app/payroll/models.py Uses UTC-aware timestamp default helper
backend/app/main.py Uses lifespan startup for seeding + imports models for create_all
backend/app/leave/service.py Adds leave request logic + applies admin settings to attendance summary
backend/app/leave/schemas.py Adds leave request schemas and list wrapper
backend/app/leave/router.py Adds leave request endpoints + role restrictions + audit logging
backend/app/leave/models.py Adds leave request model + enums + UTC timestamp defaults
backend/app/employees/service.py Adds pagination/filtering to list employees
backend/app/employees/schemas.py Migrates Pydantic v2 config to ConfigDict
backend/app/employees/router.py Adds query params + returns { items, total }
backend/app/config.py Requires secrets/passwords + validates strength + expands env file search
backend/app/auth/schemas.py Adds password strength validators
backend/app/auth/router.py Sets cookie flags based on environment
backend/app/audit/models.py Uses UTC-aware timestamp default helper
backend/.env.example Updates password guidance in example env
.env.example Adds JWT expiry env var and updates examples
Comments suppressed due to low confidence (1)

frontend/src/modules/settings/AdminSettingsPage.tsx:185

  • Form field captions were changed from semantic <Label> elements to <p> text, which removes programmatic label association for inputs/selects (hurts screen reader and click-to-focus behavior). Prefer keeping Label with htmlFor + matching id on the control (or otherwise ensure accessible labeling).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +3 to +6
import { useTheme } from '@/components/theme-provider'

type ToasterProps = React.ComponentProps<typeof Sonner>

Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

React is referenced for React.ComponentProps but not imported. With jsx: react-jsx, this will fail type-checking (Cannot find name 'React'). Import React types (e.g., import type React from 'react' / import type { ComponentProps } from 'react') or refactor to avoid the React. namespace.

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +65
import { createContext, useContext, useEffect, useMemo, useState, type ReactNode } from 'react'

type ThemePreference = 'light' | 'dark'

interface ThemeContextValue {
theme: ThemePreference
setTheme: (theme: ThemePreference) => void
toggleTheme: () => void
}

const ThemeContext = createContext<ThemeContextValue | undefined>(undefined)

const THEME_STORAGE_KEY = 'theme-preference'

function getInitialTheme(): ThemePreference {
if (typeof window === 'undefined') {
return 'light'
}

const savedTheme = window.localStorage.getItem(THEME_STORAGE_KEY)
if (savedTheme === 'light' || savedTheme === 'dark') {
return savedTheme
}

return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
}

function applyTheme(theme: ThemePreference) {
const root = document.documentElement
const isDark = theme === 'dark'
root.classList.toggle('dark', isDark)
root.style.colorScheme = isDark ? 'dark' : 'light'
}

interface ThemeProviderProps {
children: ReactNode
}

export function ThemeProvider({ children }: ThemeProviderProps) {
const [theme, setThemeState] = useState<ThemePreference>(getInitialTheme)

useEffect(() => {
applyTheme(theme)
window.localStorage.setItem(THEME_STORAGE_KEY, theme)
}, [theme])

const value = useMemo<ThemeContextValue>(
() => ({
theme,
setTheme: setThemeState,
toggleTheme: () => setThemeState((currentTheme) => (currentTheme === 'dark' ? 'light' : 'dark')),
}),
[theme],
)

return <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>
}

export function useTheme() {
const context = useContext(ThemeContext)
if (!context) {
throw new Error('useTheme must be used within a ThemeProvider')
}
return context
} No newline at end of file
Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ThemeContext appears to be unused (no imports/usages found in frontend/src) and duplicates the new shadcn-style components/theme-provider. Consider removing this file or wiring the app to use it consistently to avoid confusion and multiple theme storage keys/behaviors.

Copilot uses AI. Check for mistakes.
Comment on lines 29 to 42
"date-fns": "^4.1.0",
"geist": "^1.7.0",
"lucide-react": "^0.575.0",
"next-themes": "^0.4.6",
"react": "^19.2.0",
"react-day-picker": "^9.14.0",
"react-dom": "^19.2.0",
"react-hook-form": "^7.71.2",
"react-router-dom": "^7.13.1",
"recharts": "^3.7.0",
"sonner": "^2.0.7",
"tailwind-merge": "^3.5.0",
"tailwindcss-animate": "^1.0.7",
"zod": "^4.3.6"
Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

next-themes is added as a dependency but doesn’t appear to be used anywhere in frontend/src. If the project is using the local components/theme-provider implementation instead, remove next-themes to reduce install size and avoid unused deps.

Copilot uses AI. Check for mistakes.
Comment on lines +18 to +28
from app.recruitment.service import (
create_application,
create_job_posting,
delete_job_posting,
get_application,
get_job_posting,
list_applications,
list_job_postings,
update_application,
update_job_posting,
)
Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

get_application is imported but never used in this router. If you have linting/static checks, this will fail; otherwise it’s still dead code that’s easy to remove.

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +7
import { cn } from "@/lib/utils"

function Skeleton({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) {
return (
Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

React is referenced in the props type (React.HTMLAttributes) but this file doesn't import React. In this TS config (jsx: react-jsx), React isn't in scope, so the build will fail. Import the needed type from react (e.g., import type { HTMLAttributes } from 'react') or import React.

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +9
import { createContext, useContext, useEffect, useState } from 'react'

type Theme = 'dark' | 'light' | 'system'

type ThemeProviderProps = {
children: React.ReactNode
defaultTheme?: Theme
storageKey?: string
}
Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

React.ReactNode is used in the ThemeProviderProps type but React isn't imported, which will break type-checking under jsx: react-jsx. Import ReactNode (or type React/* as React) from react and use that type instead.

Copilot uses AI. Check for mistakes.
Comment on lines +35 to +55
const AlertTitle = React.forwardRef<
HTMLParagraphElement,
React.HTMLAttributes<HTMLHeadingElement>
>(({ className, ...props }, ref) => (
<h5
ref={ref}
className={cn("mb-1 font-medium leading-none tracking-tight", className)}
{...props}
/>
))
AlertTitle.displayName = "AlertTitle"

const AlertDescription = React.forwardRef<
HTMLParagraphElement,
React.HTMLAttributes<HTMLParagraphElement>
>(({ className, ...props }, ref) => (
<div
ref={ref}
className={cn("text-sm [&_p]:leading-relaxed", className)}
{...props}
/>
Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AlertTitle / AlertDescription forwardRef generics don't match the rendered elements (h5 and div). This causes TypeScript ref type errors (e.g., HTMLParagraphElement ref passed to an h5). Update the ref element types and prop types to match the actual tags (or change the tags to match the declared types).

Copilot uses AI. Check for mistakes.
Comment on lines +11 to +17
const storageKey = 'theme-preference'
const savedTheme = localStorage.getItem(storageKey)
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches
const shouldUseDark = savedTheme ? savedTheme === 'dark' : prefersDark
const root = document.documentElement
root.classList.toggle('dark', shouldUseDark)
root.style.colorScheme = shouldUseDark ? 'dark' : 'light'
Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The inline theme bootstrap script reads from localStorage key theme-preference, but the app’s ThemeProvider is configured with storageKey="vite-ui-theme". This will cause the initial theme (and subsequent persisted theme) to be inconsistent / flash incorrectly. Align the keys (and supported values, including system if needed) between index.html and the runtime ThemeProvider.

Suggested change
const storageKey = 'theme-preference'
const savedTheme = localStorage.getItem(storageKey)
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches
const shouldUseDark = savedTheme ? savedTheme === 'dark' : prefersDark
const root = document.documentElement
root.classList.toggle('dark', shouldUseDark)
root.style.colorScheme = shouldUseDark ? 'dark' : 'light'
const storageKey = 'vite-ui-theme'
const savedTheme = localStorage.getItem(storageKey)
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches
const resolvedTheme =
savedTheme === 'light' || savedTheme === 'dark'
? savedTheme
: prefersDark
? 'dark'
: 'light'
const root = document.documentElement
root.classList.toggle('dark', resolvedTheme === 'dark')
root.style.colorScheme = resolvedTheme

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants