06
UI Upgrade — shadcn/ui
Replace custom UI with healthcare-grade accessible components
Week 7–914 daysEstimated: 56h totalQuality Leap
Why this matters
This is where your app goes from 'migrated' to 'premium'. shadcn/ui gives you accessible, keyboard-navigable, beautifully animated components. Your doctors and patients will notice the quality difference immediately.
High-Priority Upgrades
Prescription tables → shadcn DataTable
All forms → shadcn Form + react-hook-form + zod
DigitalPrescription modal → shadcn Dialog
Custom toasts → Sonner <Toaster />
All <img> tags → next/image
Loading states → shadcn Skeleton
Mobile navigation → shadcn Sheet
Doctor search → shadcn Command + Popover
components/prescriptions/columns.jsx — DataTable columns
'use client'
import { ColumnDef } from '@tanstack/react-table'
import { Badge } from '@/components/ui/badge'
export const columns = [
{ accessorKey: 'patientName', header: 'Patient' },
{ accessorKey: 'medication', header: 'Medication' },
{ accessorKey: 'dosage', header: 'Dosage' },
{
accessorKey: 'status',
header: 'Status',
cell: ({ row }) => (
<Badge variant={row.original.status === 'active' ? 'default' : 'secondary'}>
{row.original.status}
</Badge>
),
},
]Form migration pattern — useState → react-hook-form
// BEFORE: Manual useState for every field
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const [error, setError] = useState('')
// AFTER: react-hook-form + zod
import { useForm } from 'react-hook-form'
import { zodResolver } from '@hookform/resolvers/zod'
import { z } from 'zod'
const schema = z.object({
email: z.string().email('Invalid email'),
password: z.string().min(8, 'Min 8 characters'),
})
const { register, handleSubmit, formState: { errors } } = useForm({
resolver: zodResolver(schema),
})next/image — S3 URL replacement
// BEFORE: plain <img> tag
<img src={user.avatar} alt="Profile" className="w-12 h-12 rounded-full" />
// AFTER: next/image with S3 domain configured
import Image from 'next/image'
<Image
src={user.avatar}
alt="Profile"
width={48}
height={48}
className="rounded-full"
/>
// Requires in next.config.js:
// images: { remotePatterns: [{ hostname: '*.amazonaws.com' }] }