diff --git a/src/components/PMRInterface.tsx b/src/components/PMRInterface.tsx
index 74591d7..3aec2ce 100644
--- a/src/components/PMRInterface.tsx
+++ b/src/components/PMRInterface.tsx
@@ -4,6 +4,7 @@ import { ClinicalSidebar } from './ClinicalSidebar'
import { PatientBanner } from './PatientBanner'
import { SummaryView } from './views/SummaryView'
import { ConsultationsView } from './views/ConsultationsView'
+import { MedicationsView } from './views/MedicationsView'
interface PMRInterfaceProps {
children?: React.ReactNode
@@ -40,6 +41,8 @@ export function PMRInterface({ children }: PMRInterfaceProps) {
return
case 'consultations':
return
+ case 'medications':
+ return
default:
return (
diff --git a/src/components/views/MedicationsView.tsx b/src/components/views/MedicationsView.tsx
new file mode 100644
index 0000000..a58c310
--- /dev/null
+++ b/src/components/views/MedicationsView.tsx
@@ -0,0 +1,332 @@
+import { useState, useMemo } from 'react'
+import { ChevronDown, ChevronUp, ArrowUpDown, ArrowUp, ArrowDown } from 'lucide-react'
+import { medications } from '@/data/medications'
+import type { Medication } from '@/types/pmr'
+
+type SortField = 'name' | 'dose' | 'frequency' | 'startYear' | 'status'
+type SortDirection = 'asc' | 'desc' | null
+
+interface SortState {
+ field: SortField
+ direction: SortDirection
+}
+
+const categoryTabs = [
+ { id: 'Active', label: 'Active Medications', description: 'Technical skills (daily use)' },
+ { id: 'Clinical', label: 'Clinical Medications', description: 'Healthcare domain skills' },
+ { id: 'PRN', label: 'PRN (As Required)', description: 'Strategic & leadership skills' },
+] as const
+
+export function MedicationsView() {
+ const [activeTab, setActiveTab] = useState<'Active' | 'Clinical' | 'PRN'>('Active')
+ const [expandedRow, setExpandedRow] = useState
(null)
+ const [sort, setSort] = useState({ field: 'name', direction: null })
+
+ const prefersReducedMotion = typeof window !== 'undefined'
+ ? window.matchMedia('(prefers-reduced-motion: reduce)').matches
+ : false
+
+ const filteredMedications = useMemo(() => {
+ return medications.filter(med => med.category === activeTab)
+ }, [activeTab])
+
+ const sortedMedications = useMemo(() => {
+ if (!sort.direction) return filteredMedications
+
+ return [...filteredMedications].sort((a, b) => {
+ let comparison = 0
+ switch (sort.field) {
+ case 'name':
+ comparison = a.name.localeCompare(b.name)
+ break
+ case 'dose':
+ comparison = a.dose - b.dose
+ break
+ case 'frequency': {
+ const freqOrder = { 'Daily': 0, 'Weekly': 1, 'Monthly': 2, 'As needed': 3 }
+ comparison = freqOrder[a.frequency] - freqOrder[b.frequency]
+ break
+ }
+ case 'startYear':
+ comparison = a.startYear - b.startYear
+ break
+ case 'status':
+ comparison = a.status.localeCompare(b.status)
+ break
+ }
+ return sort.direction === 'asc' ? comparison : -comparison
+ })
+ }, [filteredMedications, sort])
+
+ const handleSort = (field: SortField) => {
+ if (sort.field === field) {
+ if (sort.direction === 'asc') {
+ setSort({ field, direction: 'desc' })
+ } else if (sort.direction === 'desc') {
+ setSort({ field, direction: null })
+ } else {
+ setSort({ field, direction: 'asc' })
+ }
+ } else {
+ setSort({ field, direction: 'asc' })
+ }
+ }
+
+ const toggleRow = (id: string) => {
+ setExpandedRow(expandedRow === id ? null : id)
+ }
+
+ const getSortIcon = (field: SortField) => {
+ if (sort.field !== field || !sort.direction) {
+ return
+ }
+ return sort.direction === 'asc'
+ ?
+ :
+ }
+
+ return (
+
+
+
+
+ Current Medications
+
+
+ Skills mapped as active medications — proficiency shown as dosage
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+
+ {sortedMedications.map((med, index) => (
+ toggleRow(med.id)}
+ prefersReducedMotion={prefersReducedMotion}
+ />
+ ))}
+
+
+
+
+
+
+ {sortedMedications.length} medications in this category. Click a row to view prescribing history.
+
+
+
+
+ )
+}
+
+interface MedicationRowProps {
+ medication: Medication
+ isExpanded: boolean
+ isAlternating: boolean
+ onToggle: () => void
+ prefersReducedMotion: boolean
+}
+
+function MedicationRow({ medication, isExpanded, isAlternating, onToggle, prefersReducedMotion }: MedicationRowProps) {
+ const statusColors = {
+ 'Active': 'bg-green-500',
+ 'Historical': 'bg-gray-400',
+ }
+
+ return (
+ <>
+
+ |
+
+ |
+
+
+ {medication.name}
+
+ |
+
+
+ {medication.dose}%
+
+ |
+
+
+ {medication.frequency}
+
+ |
+
+
+ {medication.startYear}
+
+ |
+
+
+
+ {medication.status}
+
+ |
+
+ {isExpanded && (
+
+ )}
+ >
+ )
+}
+
+interface PrescribingHistoryProps {
+ history: { year: number; description: string }[]
+ prefersReducedMotion: boolean
+}
+
+function PrescribingHistory({ history, prefersReducedMotion }: PrescribingHistoryProps) {
+ return (
+
+
+
+
+ Prescribing History
+
+
+ {history.map((entry, index) => (
+
+
+ {entry.year}
+
+
+ {entry.description}
+
+
+ ))}
+
+
+ |
+
+ )
+}
diff --git a/src/index.css b/src/index.css
index 39f5a48..7939373 100644
--- a/src/index.css
+++ b/src/index.css
@@ -66,6 +66,15 @@ body {
animation: seedPulse 0.6s ease-in-out infinite;
}
+@keyframes fadeIn {
+ from { opacity: 0; transform: translateY(-4px); }
+ to { opacity: 1; transform: translateY(0); }
+}
+
+.animate-fadeIn {
+ animation: fadeIn 200ms ease-out forwards;
+}
+
.scrollbar-hide {
-ms-overflow-style: none;
scrollbar-width: none;