style(frontend): mobile responsive polish for Dashboard/Providers/Upload/Reconciliation

This commit is contained in:
Tyler
2026-06-20 16:51:17 -06:00
parent b980e77cf2
commit 1476c90570
4 changed files with 33 additions and 29 deletions
+5 -5
View File
@@ -108,7 +108,7 @@ export function Dashboard() {
const sectionBase = kpiBase + kpiStep * 5 + 60; // after the last KPI const sectionBase = kpiBase + kpiStep * 5 + 60; // after the last KPI
return ( return (
<div className="space-y-10"> <div className="space-y-6 md:space-y-10">
{/* Hero */} {/* Hero */}
<header <header
className="relative animate-fade-in overflow-hidden" className="relative animate-fade-in overflow-hidden"
@@ -129,13 +129,13 @@ export function Dashboard() {
{fmt.usd(kpis.billed)} {fmt.usd(kpis.billed)}
</div> </div>
<div className="relative z-10 flex items-end justify-between gap-6 flex-wrap"> <div className="relative z-10 flex items-end justify-between gap-4 sm:gap-6 flex-wrap">
<div> <div className="min-w-0">
<div className="text-[10.5px] font-semibold uppercase tracking-[0.18em] text-muted-foreground mb-2 flex items-center gap-2"> <div className="text-[10.5px] font-semibold uppercase tracking-[0.18em] text-muted-foreground mb-2 flex items-center gap-2">
<span className="inline-block h-px w-6 bg-border" /> <span className="inline-block h-px w-6 bg-border" />
Today · {fmt.date(new Date().toISOString())} Today · {fmt.date(new Date().toISOString())}
</div> </div>
<h1 className="text-[28px] leading-[1.15] font-semibold tracking-tight"> <h1 className="text-[22px] sm:text-[28px] leading-[1.15] font-semibold tracking-tight">
Good morning, Jordan. Good morning, Jordan.
</h1> </h1>
<p className="text-muted-foreground mt-1.5 max-w-xl text-[14px] leading-relaxed"> <p className="text-muted-foreground mt-1.5 max-w-xl text-[14px] leading-relaxed">
@@ -157,7 +157,7 @@ export function Dashboard() {
{/* KPIs — every card carries a trend. */} {/* KPIs — every card carries a trend. */}
<section <section
aria-label="Key performance indicators" aria-label="Key performance indicators"
className="grid gap-4 grid-cols-2 lg:grid-cols-5" className="grid gap-4 grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-5"
> >
<KpiCard <KpiCard
label="Claims" label="Claims"
+3 -3
View File
@@ -10,13 +10,13 @@ export function Providers() {
const items = data?.items ?? []; const items = data?.items ?? [];
return ( return (
<div className="space-y-8 animate-fade-in"> <div className="space-y-6 md:space-y-8 animate-fade-in">
<header> <header>
<div className="text-[10.5px] font-semibold uppercase tracking-[0.18em] text-muted-foreground mb-2 flex items-center gap-2"> <div className="text-[10.5px] font-semibold uppercase tracking-[0.18em] text-muted-foreground mb-2 flex items-center gap-2">
<span className="inline-block h-px w-6 bg-border" /> <span className="inline-block h-px w-6 bg-border" />
Providers Providers
</div> </div>
<h1 className="text-[22px] font-semibold tracking-tight">Provider directory</h1> <h1 className="text-[22px] sm:text-[26px] font-semibold tracking-tight">Provider directory</h1>
<p className="text-muted-foreground mt-1.5 text-[14px]"> <p className="text-muted-foreground mt-1.5 text-[14px]">
NPIs registered with the clearinghouse for 837P submission and 835 NPIs registered with the clearinghouse for 837P submission and 835
remittance retrieval. remittance retrieval.
@@ -49,7 +49,7 @@ export function Providers() {
{items.map((p) => ( {items.map((p) => (
<article <article
key={p.npi} key={p.npi}
className="surface rounded-xl p-6 flex flex-col gap-4 hover:bg-muted/20 transition-colors" className="surface rounded-xl p-4 sm:p-6 flex flex-col gap-4 hover:bg-muted/20 transition-colors"
> >
<div className="flex items-start gap-3"> <div className="flex items-start gap-3">
<div className="h-10 w-10 rounded-lg bg-muted/60 flex items-center justify-center text-foreground"> <div className="h-10 w-10 rounded-lg bg-muted/60 flex items-center justify-center text-foreground">
+16 -14
View File
@@ -27,17 +27,17 @@ export function ReconciliationPage() {
if (unmatched.isLoading) { if (unmatched.isLoading) {
return ( return (
<div className="space-y-8 animate-fade-in"> <div className="space-y-6 md:space-y-8 animate-fade-in">
<header> <header>
<div className="text-[10.5px] font-semibold uppercase tracking-[0.18em] text-muted-foreground mb-2 flex items-center gap-2"> <div className="text-[10.5px] font-semibold uppercase tracking-[0.18em] text-muted-foreground mb-2 flex items-center gap-2">
<span className="inline-block h-px w-6 bg-border" /> <span className="inline-block h-px w-6 bg-border" />
Reconciliation Reconciliation
</div> </div>
<h1 className="text-[22px] font-semibold tracking-tight"> <h1 className="text-[22px] sm:text-[26px] font-semibold tracking-tight">
Manual pairing Manual pairing
</h1> </h1>
</header> </header>
<div className="grid grid-cols-2 gap-4"> <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<Skeleton variant="default" height={320} /> <Skeleton variant="default" height={320} />
<Skeleton variant="default" height={320} /> <Skeleton variant="default" height={320} />
</div> </div>
@@ -51,13 +51,13 @@ export function ReconciliationPage() {
? unmatched.error.message ? unmatched.error.message
: String(unmatched.error); : String(unmatched.error);
return ( return (
<div className="space-y-8 animate-fade-in"> <div className="space-y-6 md:space-y-8 animate-fade-in">
<header> <header>
<div className="text-[10.5px] font-semibold uppercase tracking-[0.18em] text-muted-foreground mb-2 flex items-center gap-2"> <div className="text-[10.5px] font-semibold uppercase tracking-[0.18em] text-muted-foreground mb-2 flex items-center gap-2">
<span className="inline-block h-px w-6 bg-border" /> <span className="inline-block h-px w-6 bg-border" />
Reconciliation Reconciliation
</div> </div>
<h1 className="text-[22px] font-semibold tracking-tight"> <h1 className="text-[22px] sm:text-[26px] font-semibold tracking-tight">
Manual pairing Manual pairing
</h1> </h1>
</header> </header>
@@ -78,13 +78,13 @@ export function ReconciliationPage() {
if (empty) { if (empty) {
return ( return (
<div className="space-y-8 animate-fade-in"> <div className="space-y-6 md:space-y-8 animate-fade-in">
<header> <header>
<div className="text-[10.5px] font-semibold uppercase tracking-[0.18em] text-muted-foreground mb-2 flex items-center gap-2"> <div className="text-[10.5px] font-semibold uppercase tracking-[0.18em] text-muted-foreground mb-2 flex items-center gap-2">
<span className="inline-block h-px w-6 bg-border" /> <span className="inline-block h-px w-6 bg-border" />
Reconciliation Reconciliation
</div> </div>
<h1 className="text-[22px] font-semibold tracking-tight"> <h1 className="text-[22px] sm:text-[26px] font-semibold tracking-tight">
Manual pairing Manual pairing
</h1> </h1>
</header> </header>
@@ -125,13 +125,13 @@ export function ReconciliationPage() {
}; };
return ( return (
<div className="space-y-8 animate-fade-in"> <div className="space-y-6 md:space-y-8 animate-fade-in">
<header> <header>
<div className="text-[10.5px] font-semibold uppercase tracking-[0.18em] text-muted-foreground mb-2 flex items-center gap-2"> <div className="text-[10.5px] font-semibold uppercase tracking-[0.18em] text-muted-foreground mb-2 flex items-center gap-2">
<span className="inline-block h-px w-6 bg-border" /> <span className="inline-block h-px w-6 bg-border" />
Reconciliation Reconciliation
</div> </div>
<h1 className="text-[22px] font-semibold tracking-tight"> <h1 className="text-[22px] sm:text-[26px] font-semibold tracking-tight">
Manual pairing Manual pairing
</h1> </h1>
<p className="text-muted-foreground mt-1.5 text-[14px]"> <p className="text-muted-foreground mt-1.5 text-[14px]">
@@ -139,7 +139,7 @@ export function ReconciliationPage() {
</p> </p>
</header> </header>
<div className="grid grid-cols-2 gap-4"> <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
{/* Claims column */} {/* Claims column */}
<div className="surface rounded-xl border border-border/60 p-4 space-y-2"> <div className="surface rounded-xl border border-border/60 p-4 space-y-2">
<h2 className="text-[10.5px] font-semibold uppercase tracking-[0.18em] text-muted-foreground"> <h2 className="text-[10.5px] font-semibold uppercase tracking-[0.18em] text-muted-foreground">
@@ -155,7 +155,7 @@ export function ReconciliationPage() {
onClick={() => setSelectedClaim(c.id)} onClick={() => setSelectedClaim(c.id)}
aria-pressed={active} aria-pressed={active}
className={cn( className={cn(
"w-full text-left p-3 rounded-md border transition-colors", "w-full text-left p-3 min-h-[44px] rounded-md border transition-colors",
active active
? "border-accent bg-accent/5" ? "border-accent bg-accent/5"
: "border-border/60 hover:border-border" : "border-border/60 hover:border-border"
@@ -190,7 +190,7 @@ export function ReconciliationPage() {
onClick={() => setSelectedRemit(r.id)} onClick={() => setSelectedRemit(r.id)}
aria-pressed={active} aria-pressed={active}
className={cn( className={cn(
"w-full text-left p-3 rounded-md border transition-colors", "w-full text-left p-3 min-h-[44px] rounded-md border transition-colors",
active active
? "border-accent bg-accent/5" ? "border-accent bg-accent/5"
: "border-border/60 hover:border-border" : "border-border/60 hover:border-border"
@@ -215,10 +215,11 @@ export function ReconciliationPage() {
</div> </div>
</div> </div>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2 flex-wrap">
<Button <Button
onClick={handleMatch} onClick={handleMatch}
disabled={!selectedClaim || !selectedRemit || match.isPending} disabled={!selectedClaim || !selectedRemit || match.isPending}
className="min-h-[44px] sm:min-h-0"
> >
<GitMerge className="h-3.5 w-3.5 mr-1.5" /> <GitMerge className="h-3.5 w-3.5 mr-1.5" />
Match selected Match selected
@@ -227,12 +228,13 @@ export function ReconciliationPage() {
variant="outline" variant="outline"
onClick={handleClear} onClick={handleClear}
disabled={(!selectedClaim && !selectedRemit) || match.isPending} disabled={(!selectedClaim && !selectedRemit) || match.isPending}
className="min-h-[44px] sm:min-h-0"
> >
<X className="h-3.5 w-3.5 mr-1.5" /> <X className="h-3.5 w-3.5 mr-1.5" />
Clear selection Clear selection
</Button> </Button>
{selectedClaim || selectedRemit ? ( {selectedClaim || selectedRemit ? (
<span className="text-xs text-muted-foreground ml-2"> <span className="text-xs text-muted-foreground sm:ml-2 basis-full sm:basis-auto">
{selectedClaim ? `Claim ${selectedClaim}` : "No claim"} {selectedClaim ? `Claim ${selectedClaim}` : "No claim"}
{" · "} {" · "}
{selectedRemit ? `Remit ${selectedRemit}` : "No remit"} {selectedRemit ? `Remit ${selectedRemit}` : "No remit"}
+9 -7
View File
@@ -233,7 +233,7 @@ function ClaimCard837({ claim }: { claim: ClaimOutput }) {
<div className="text-[10.5px] font-semibold uppercase tracking-[0.18em] text-muted-foreground mb-1.5"> <div className="text-[10.5px] font-semibold uppercase tracking-[0.18em] text-muted-foreground mb-1.5">
Service lines Service lines
</div> </div>
<div className="rounded-md border border-border/40 overflow-hidden"> <div className="rounded-md border border-border/40 overflow-x-auto">
<table className="w-full text-[12px]"> <table className="w-full text-[12px]">
<thead className="bg-muted/30"> <thead className="bg-muted/30">
<tr className="text-left text-muted-foreground"> <tr className="text-left text-muted-foreground">
@@ -403,7 +403,7 @@ function ClaimCard835({ claim }: { claim: ClaimPayment }) {
<div className="text-[10.5px] font-semibold uppercase tracking-[0.18em] text-muted-foreground mb-1.5"> <div className="text-[10.5px] font-semibold uppercase tracking-[0.18em] text-muted-foreground mb-1.5">
Service payments Service payments
</div> </div>
<div className="rounded-md border border-border/40 overflow-hidden"> <div className="rounded-md border border-border/40 overflow-x-auto">
<table className="w-full text-[12px]"> <table className="w-full text-[12px]">
<thead className="bg-muted/30"> <thead className="bg-muted/30">
<tr className="text-left text-muted-foreground"> <tr className="text-left text-muted-foreground">
@@ -584,13 +584,13 @@ export function Upload() {
} }
return ( return (
<div className="space-y-8 animate-fade-in"> <div className="space-y-6 md:space-y-8 animate-fade-in">
<header> <header>
<div className="text-[10.5px] font-semibold uppercase tracking-[0.18em] text-muted-foreground mb-2 flex items-center gap-2"> <div className="text-[10.5px] font-semibold uppercase tracking-[0.18em] text-muted-foreground mb-2 flex items-center gap-2">
<span className="inline-block h-px w-6 bg-border" /> <span className="inline-block h-px w-6 bg-border" />
Upload · EDI parser Upload · EDI parser
</div> </div>
<h1 className="text-[22px] font-semibold tracking-tight"> <h1 className="text-[22px] sm:text-[26px] font-semibold tracking-tight">
Parse an X12 file Parse an X12 file
</h1> </h1>
<p className="text-muted-foreground mt-1.5 text-[14px] max-w-2xl"> <p className="text-muted-foreground mt-1.5 text-[14px] max-w-2xl">
@@ -665,7 +665,7 @@ export function Upload() {
if (e.key === "Enter" || e.key === " ") inputRef.current?.click(); if (e.key === "Enter" || e.key === " ") inputRef.current?.click();
}} }}
className={cn( className={cn(
"relative flex flex-col items-center justify-center gap-2 rounded-lg border border-dashed border-border/60 bg-muted/20 px-6 py-8 cursor-pointer transition-colors", "relative flex flex-col items-center justify-center gap-2 rounded-lg border border-dashed border-border/60 bg-muted/20 px-6 py-10 sm:py-8 min-h-[140px] sm:min-h-[120px] cursor-pointer transition-colors",
"hover:bg-muted/30 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring" "hover:bg-muted/30 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
)} )}
> >
@@ -704,7 +704,7 @@ export function Upload() {
/> />
</div> </div>
<div className="flex items-center justify-between gap-3"> <div className="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
<div className="text-[12px] text-muted-foreground"> <div className="text-[12px] text-muted-foreground">
{api.isConfigured ? ( {api.isConfigured ? (
<span className="inline-flex items-center gap-1.5"> <span className="inline-flex items-center gap-1.5">
@@ -721,12 +721,13 @@ export function Upload() {
</span> </span>
)} )}
</div> </div>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2 flex-wrap">
{file ? ( {file ? (
<Button <Button
variant="ghost" variant="ghost"
onClick={() => pickFile(null)} onClick={() => pickFile(null)}
disabled={running} disabled={running}
className="min-h-[44px] sm:min-h-0"
> >
Clear Clear
</Button> </Button>
@@ -734,6 +735,7 @@ export function Upload() {
<Button <Button
onClick={onParse} onClick={onParse}
disabled={!file || running} disabled={!file || running}
className="min-h-[44px] sm:min-h-0"
> >
{running ? ( {running ? (
<> <>