[STU-185] Migrate remaining app pages to shadcn/ui + Tailwind v4#43
[STU-185] Migrate remaining app pages to shadcn/ui + Tailwind v4#43BAWES wants to merge 12 commits into
Conversation
…[STU-163] Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add role="alert" to server-rendered error banners and client-side form error. Wire aria-describedby on form to error id for screen reader announcement. Add autoFocus on email input when validation fails for keyboard focus. Landing page already has aria-hidden, hidden icons, native focusables. Co-Authored-By: Paperclip <noreply@paperclip.ing>
…-176 rebase
Replace index === 1 ? "PDF" : "Live" with explicit {label, status} objects
so reordering the array cannot silently break rendering.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replace legacy CSS classes in FeatureGrid, WorkspaceNavigation, DetailPanels, DataTable, WorkTabs, WorkspaceShell, Skeletons, SlidePanel, and Dashboard with Tailwind v4 utility classes. Add shadcn/ui table component. This migration cascades to 26+ role pages that use these shared components as their primary layout wrapper, eliminating legacy CSS dependencies from the majority of the application surface. Tests: none (UI-only CSS migration, verified with tsc --noEmit)
Replace legacy CSS classes (shell, workspaceRail, workspaceMark, commandOverlay, commandScrim, commandMenu, commandInputWrap, commandList, commandGroup, commandEmpty, shortcutGrid) with Tailwind v4 utility classes. Tests: none (UI-only CSS migration, verified with tsc --noEmit)
Replace all ~30 legacy CSS classes (commandOS, journeyHome, previewPanel, etc.) with Tailwind v4 utility classes using CSS variable tokens. Tests: none (visual-only CSS migration; type check passes) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replace financeStart/financePrimary/financeSteps, detailGrid, detailPanel, transferActions/payoutList, and 30+ HubContent journey/preview classes with Tailwind v4 utility classes using CSS variable tokens. Tests: none (visual-only CSS migration; type check passes) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (6)
💤 Files with no reviewable changes (1)
✅ Files skipped from review due to trivial changes (1)
WalkthroughThis PR executes a large-scale design system migration, replacing semantic CSS class names with Tailwind utility classes across 26 files. New table UI primitives are introduced, legacy CSS is removed, authentication logic is simplified, and workspace/hub layouts are restructured to use Tailwind-based styling while preserving all behavioral logic. ChangesDesign System Migration
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (6)
src/modules/workspace/DataTable.tsx (1)
41-43: ⚡ Quick winAvoid double horizontal-scroll wrappers around
Table.
Tablealready wraps content withoverflow-auto, so the extraoverflow-x-autowrapper on Line 41 is redundant and can introduce nested scroll behavior. Prefer a single scroll container here.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/modules/workspace/DataTable.tsx` around lines 41 - 43, In DataTable.tsx remove the redundant outer wrapper that applies "overflow-x-auto" around the Table (the div that wraps Table and TableHeader) because Table already provides overflow-auto; delete that extra div or move any required spacing/styling onto the Table itself so you have a single scroll container (update the DataTable component to render Table directly with its TableHeader/TableBody children).src/modules/finance/TransferActionBar.tsx (2)
77-81: ⚡ Quick winConstrain long candidate text to protect action-button layout.
Line 79–81 can overflow in narrow widths because the row is a single horizontal flex with CTA on the right. Add truncation/wrapping constraints so long names/meta don’t push the button out.
Proposed fix
- <strong className="text-sm font-semibold text-[var(--ink)]">{candidate.title}</strong> - <span className="text-[13px] text-[var(--muted)]">{candidate.subtitle}</span> - <small className="text-[13px] text-[var(--muted)]">{candidate.meta}</small> + <strong className="text-sm font-semibold text-[var(--ink)] truncate">{candidate.title}</strong> + <span className="text-[13px] text-[var(--muted)] truncate">{candidate.subtitle}</span> + <small className="text-[13px] text-[var(--muted)] truncate">{candidate.meta}</small>🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/modules/finance/TransferActionBar.tsx` around lines 77 - 81, The candidate text (candidate.title, candidate.subtitle, candidate.meta) in TransferActionBar.tsx can overflow and push the CTA out; constrain these elements by applying overflow-hidden + text-overflow: ellipsis and a width constraint (e.g., max-width or flex-basis) to the container and/or the individual elements, and use whitespace-nowrap or truncate classes on the title (and optionally subtitle/meta) so long content is truncated instead of expanding the flex row—update the inner div (the one with "flex flex-col gap-0.5 min-w-0") and the specific elements rendering candidate.title/subtitle/meta to include these truncation/width constraints.
97-97: ⚡ Quick winAllow the payment form controls to wrap on small screens.
Line 97 keeps input and button on one row, which can overflow in compact viewports. Adding wrapping improves mobile task completion.
Proposed fix
- <form action={markPaymentReceivedAction} className="flex gap-2 items-center"> + <form action={markPaymentReceivedAction} className="flex flex-wrap gap-2 items-center">🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/modules/finance/TransferActionBar.tsx` at line 97, The form in TransferActionBar (the <form action={markPaymentReceivedAction} ...>) forces a single-row layout and can overflow on small screens; update its className to allow wrapping (e.g., add "flex-wrap" or "flex-wrap gap-2 items-center") so inputs and buttons wrap on narrow viewports while preserving gaps and alignment.src/modules/hub/HubContent.tsx (1)
115-282: 🏗️ Heavy liftConsolidate duplicated Hub layout to one render source.
This component now mirrors a large portion of
src/app/hub/page.tsx, which increases drift risk and future bug surface. Consider extracting shared sections (or a shared presentational component) so style/UX changes are made once.Also applies to: 287-369
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/modules/hub/HubContent.tsx` around lines 115 - 282, The PR duplicates large parts of the Hub UI between HubContent (this file) and src/app/hub/page.tsx; extract the shared presentational layout into a single reusable component (e.g., HubLayout or HubShell) and reuse it from both places: move the header (session display, search form, HubShortcuts), the "Start here" guide block (uses guide, hubContext, Link), the workflows grid (uses guide.journeys), the live queues + search panel (uses data, hubRecordHref, RecordPreview) into the new component and accept props {session, data, guide, commands, hubContext, requiredRole, embedded} so HubContent and page.tsx simply render <HubLayout {...props} />; ensure unique symbols referenced here (HubShortcuts, RecordPreview, hubRecordHref, guide.journeys, data.results) are preserved and passed through, and keep any conditional logic (requiredRole check, data.preview conditional) inside the shared component.src/modules/workspace/WorkspaceShell.tsx (1)
68-68: ⚡ Quick winAvoid hard-coded viewport width in stage container.
w-[calc(100vw-236px)]is fragile in embedded layouts and can cause subtle overflow/misalignment. Let the grid/container define width (w-fullis safer).Proposed fix
- <section className="min-w-0 w-[calc(100vw-236px)] overflow-x-hidden grid content-start gap-3.5 p-3.5 max-md:w-auto max-md:p-2.5 max-md:pb-[76px]"> + <section className="min-w-0 w-full overflow-x-hidden grid content-start gap-3.5 p-3.5 max-md:w-auto max-md:p-2.5 max-md:pb-[76px]">🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/modules/workspace/WorkspaceShell.tsx` at line 68, The section in WorkspaceShell.tsx uses a brittle fixed viewport calc width (the class w-[calc(100vw-236px)]) that breaks embedded layouts; replace that token with a fluid width (e.g., w-full) in the section's className so the grid/container controls sizing, and preserve the existing responsive modifiers (max-md:w-auto, max-md:p-2.5, max-md:pb-[76px]) to keep current mobile behavior; ensure no other layout-specific styles elsewhere rely on that hard-coded width.src/app/admin/transfers/page.tsx (1)
28-36: 💤 Low valueConsider consolidating color tokens.
The styling mixes hard-coded color values for light mode (
bg-white,border-[#dfe4ed],bg-[#111827]) with CSS variable references for dark mode (dark:bg-[var(--surface)],dark:border-[var(--line)]). For better maintainability and consistency, consider using CSS variables for both light and dark modes.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/app/admin/transfers/page.tsx` around lines 28 - 36, The UI uses hard-coded light-mode colors in the JSX (e.g., bg-white, border-[`#dfe4ed`], bg-[`#111827`], text-white) while dark-mode uses CSS variables; replace those hard-coded tokens with corresponding CSS variables and update the component to reference them (modify the container div's className and the Link's className where latest is rendered) so both light and dark themes consume the same variable names (ensure the CSS defines the light-mode values for variables like --surface, --line, --brand-bg or similarly named tokens). Also run a quick visual check of Start with a transfer run (the h2/p/Link block) to confirm spacing and contrast remain correct after swapping to variables.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/app/login/page.tsx`:
- Around line 80-85: The two error message <p> blocks that read params.error ===
"expired" and params.error === "account" need to be rendered into an accessible
live region so screen readers announce them immediately; replace or wrap each
<p> with an element that includes role="alert" (or aria-live="assertive" and
aria-atomic="true") while preserving the existing className and text, e.g.,
render a <div role="alert" aria-live="assertive" aria-atomic="true"
className="...">...message...</div> for both the expired and account branches so
assistive tech will announce the failures.
In `@src/modules/auth/LoginForm.tsx`:
- Line 54: The current LoginForm renders auth errors as a plain <p>
(state.error), which is not announced to screen readers; update the error
element (where state.error is rendered) to be an accessible live region by
adding role="alert" or aria-live="assertive" (and keep the visual styling) so
assistive technologies announce invalid-credential responses immediately; locate
the rendering in the LoginForm component (the expression using state.error) and
replace the plain <p> with an element that includes role="alert" or aria-live
and the same className.
In `@src/modules/workspace/DetailPanels.tsx`:
- Around line 49-69: The current item container in DetailPanels.tsx always uses
the two-column grid class "grid-cols-[minmax(0,1fr)_minmax(126px,auto)]" which
reserves the meta column even when row.meta is falsy; update the container's
className (the JSX element keyed by row.id) to compute the grid template
conditionally based on row.meta so when row.meta is absent it uses a single
flexible column (e.g., "grid-cols-[minmax(0,1fr)]") and when present it uses the
two-column template; locate the conditional around row.meta in the same
component and adjust the className generation (or split into two render
branches) so the primary content no longer gets truncated unnecessarily.
In `@src/modules/workspace/WorkspaceNavigation.tsx`:
- Around line 17-27: The Link JSX that renders the nav item (the element with
className string containing "w-full min-h-[42px] flex items-center ...", which
wraps <Icon ... /> and <strong>{item.label}</strong>) needs a horizontal gap
utility so the label isn't crowded; update that className to include a gap class
(e.g., "gap-2" or "gap-x-2") alongside "flex items-center" so the icon and text
are spaced consistently.
In `@src/modules/workspace/WorkspaceShell.tsx`:
- Around line 105-108: The WorkspaceShell renders a duplicate mobile nav in
embedded mode; update the JSX so WorkspaceMobileNavigation (the component
instantiated with props items={navItems} and role={session.role}) is only
rendered when the component is not in embedded mode (i.e., wrap or conditionally
render WorkspaceMobileNavigation based on the embedded prop), leaving the rest
of the layout (including stage) untouched to prevent duplicate mobile nav UI in
embedded pages.
---
Nitpick comments:
In `@src/app/admin/transfers/page.tsx`:
- Around line 28-36: The UI uses hard-coded light-mode colors in the JSX (e.g.,
bg-white, border-[`#dfe4ed`], bg-[`#111827`], text-white) while dark-mode uses CSS
variables; replace those hard-coded tokens with corresponding CSS variables and
update the component to reference them (modify the container div's className and
the Link's className where latest is rendered) so both light and dark themes
consume the same variable names (ensure the CSS defines the light-mode values
for variables like --surface, --line, --brand-bg or similarly named tokens).
Also run a quick visual check of Start with a transfer run (the h2/p/Link block)
to confirm spacing and contrast remain correct after swapping to variables.
In `@src/modules/finance/TransferActionBar.tsx`:
- Around line 77-81: The candidate text (candidate.title, candidate.subtitle,
candidate.meta) in TransferActionBar.tsx can overflow and push the CTA out;
constrain these elements by applying overflow-hidden + text-overflow: ellipsis
and a width constraint (e.g., max-width or flex-basis) to the container and/or
the individual elements, and use whitespace-nowrap or truncate classes on the
title (and optionally subtitle/meta) so long content is truncated instead of
expanding the flex row—update the inner div (the one with "flex flex-col gap-0.5
min-w-0") and the specific elements rendering candidate.title/subtitle/meta to
include these truncation/width constraints.
- Line 97: The form in TransferActionBar (the <form
action={markPaymentReceivedAction} ...>) forces a single-row layout and can
overflow on small screens; update its className to allow wrapping (e.g., add
"flex-wrap" or "flex-wrap gap-2 items-center") so inputs and buttons wrap on
narrow viewports while preserving gaps and alignment.
In `@src/modules/hub/HubContent.tsx`:
- Around line 115-282: The PR duplicates large parts of the Hub UI between
HubContent (this file) and src/app/hub/page.tsx; extract the shared
presentational layout into a single reusable component (e.g., HubLayout or
HubShell) and reuse it from both places: move the header (session display,
search form, HubShortcuts), the "Start here" guide block (uses guide,
hubContext, Link), the workflows grid (uses guide.journeys), the live queues +
search panel (uses data, hubRecordHref, RecordPreview) into the new component
and accept props {session, data, guide, commands, hubContext, requiredRole,
embedded} so HubContent and page.tsx simply render <HubLayout {...props} />;
ensure unique symbols referenced here (HubShortcuts, RecordPreview,
hubRecordHref, guide.journeys, data.results) are preserved and passed through,
and keep any conditional logic (requiredRole check, data.preview conditional)
inside the shared component.
In `@src/modules/workspace/DataTable.tsx`:
- Around line 41-43: In DataTable.tsx remove the redundant outer wrapper that
applies "overflow-x-auto" around the Table (the div that wraps Table and
TableHeader) because Table already provides overflow-auto; delete that extra div
or move any required spacing/styling onto the Table itself so you have a single
scroll container (update the DataTable component to render Table directly with
its TableHeader/TableBody children).
In `@src/modules/workspace/WorkspaceShell.tsx`:
- Line 68: The section in WorkspaceShell.tsx uses a brittle fixed viewport calc
width (the class w-[calc(100vw-236px)]) that breaks embedded layouts; replace
that token with a fluid width (e.g., w-full) in the section's className so the
grid/container controls sizing, and preserve the existing responsive modifiers
(max-md:w-auto, max-md:p-2.5, max-md:pb-[76px]) to keep current mobile behavior;
ensure no other layout-specific styles elsewhere rely on that hard-coded width.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 17257d87-d4ea-4f8f-a76d-b01bc5d0f007
📒 Files selected for processing (27)
src/app/admin/companies/[id]/page.tsxsrc/app/admin/transfers/[id]/page.tsxsrc/app/admin/transfers/page.tsxsrc/app/candidate/payments/[id]/page.tsxsrc/app/company/companies/[id]/page.tsxsrc/app/company/requests/[id]/page.tsxsrc/app/hub/page.tsxsrc/app/login/[role]/page.tsxsrc/app/login/page.tsxsrc/app/page.tsxsrc/app/staff/interviews/[id]/page.tsxsrc/app/styles.csssrc/components/ui/label.tsxsrc/components/ui/table.tsxsrc/modules/auth/LoginForm.tsxsrc/modules/dashboard/Dashboard.tsxsrc/modules/finance/TransferActionBar.tsxsrc/modules/hub/HubContent.tsxsrc/modules/workspace/DataTable.tsxsrc/modules/workspace/DetailPanels.tsxsrc/modules/workspace/FeatureGrid.tsxsrc/modules/workspace/Skeletons.tsxsrc/modules/workspace/SlidePanel.tsxsrc/modules/workspace/WorkTabs.tsxsrc/modules/workspace/WorkspaceNavigation.tsxsrc/modules/workspace/WorkspaceOS.tsxsrc/modules/workspace/WorkspaceShell.tsx
💤 Files with no reviewable changes (1)
- src/app/login/[role]/page.tsx
Removes ~2,400 lines of deprecated CSS class definitions that were left behind after migrating pages to Tailwind v4 + shadcn/ui. All removed classes were verified unused in className attributes across the entire codebase. Preserved: shadcn component styles (uiButton/uiBadge/uiCard/uiInput), candidate edit forms, error/loading pages, mobile tab bar, sheet component, linear candidate card, and still-used form/request classes. Tests: all CI gates pass (tsc, lint, build, validate) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…-185] - Add role="alert" aria-live="assertive" to login error messages for screen-reader support - Remove duplicate mobile nav in WorkspaceShell embedded mode - Make DetailPanels grid conditional on row.meta presence - Add gap-2 to desktop nav link for icon/label spacing Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Co-Authored-By: Paperclip <noreply@paperclip.ing>
|
Deployment failed with the following error: Learn More: https://vercel.com/khalid-proj?upgradeToPro=build-rate-limit |
Summary
Changes
Shared workspace components
Pages & modules
CI Gate
npm run lint— zero warnings/errorsnpx tsc --noEmit— zero type errorsnpm run build— all 42 routes compilednpm run test:validate— 76/76 tests passedFollow-up
src/app/styles.css(~900 lines of dead CSS)candidate*prefixed classes🤖 Generated with Claude Code
Summary by CodeRabbit
Style
New Features
Accessibility
Bug Fixes