Function bodies 223 total
TranscribeShell function · typescript · L10-L52 (43 LOC)frontend/src/app/transcribe/layout.tsx
function TranscribeShell({ children }: { children: React.ReactNode }) {
const { isAuthenticated, isLoading } = useAuth();
const router = useRouter();
useEffect(() => {
if (!isLoading && !isAuthenticated) {
router.push("/login");
}
}, [isAuthenticated, isLoading, router]);
if (isLoading) {
return (
<div className="flex min-h-screen items-center justify-center bg-medical-surface">
<div className="flex flex-col items-center gap-3">
<Loader2 className="h-8 w-8 animate-spin text-brand-600" />
<p className="text-sm text-medical-muted">Loading...</p>
</div>
</div>
);
}
if (!isAuthenticated) {
return null;
}
return (
<div className="flex min-h-screen flex-col">
<Navbar />
<div className="flex flex-1">
<div className="hidden lg:block">
<div className="sticky top-14 h-[calc(100vh-3.5rem)]">
<Sidebar />
</div>
</div>
<main classNamTranscribeLayout function · typescript · L54-L64 (11 LOC)frontend/src/app/transcribe/layout.tsx
export default function TranscribeLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<AuthProvider>
<TranscribeShell>{children}</TranscribeShell>
</AuthProvider>
);
}TranscribePage function · typescript · L27-L323 (297 LOC)frontend/src/app/transcribe/page.tsx
export default function TranscribePage() {
const router = useRouter();
const fileInputRef = useRef<HTMLInputElement>(null);
const [selectedFile, setSelectedFile] = useState<File | null>(null);
const [language, setLanguage] = useState<"en" | "es">("en");
const [uploading, setUploading] = useState(false);
const [error, setError] = useState<string | null>(null);
const [result, setResult] = useState<TranscriptionResult | null>(null);
const [dragActive, setDragActive] = useState(false);
const validateFile = (file: File): string | null => {
const ext = "." + file.name.split(".").pop()?.toLowerCase();
if (!ALLOWED_FORMATS.includes(ext)) {
return `Invalid file format. Allowed formats: ${ALLOWED_FORMATS.join(", ")}`;
}
if (file.size > MAX_FILE_SIZE_BYTES) {
return `File is too large. Maximum size is ${MAX_FILE_SIZE_MB}MB, but your file is ${(file.size / 1024 / 1024).toFixed(1)}MB`;
}
return null;
};
const handleFileSelect = (file: FErrorBoundary class · typescript · L15-L71 (57 LOC)frontend/src/components/ErrorBoundary.tsx
export default class ErrorBoundary extends React.Component<Props, State> {
constructor(props: Props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error: Error): State {
return { hasError: true, error };
}
componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
console.error("Error caught by ErrorBoundary:", error, errorInfo);
}
handleReset = () => {
this.setState({ hasError: false, error: undefined });
};
render() {
if (this.state.hasError) {
return (
<div className="flex min-h-screen flex-col items-center justify-center bg-medical-surface px-4">
<div className="flex max-w-md flex-col items-center gap-4 text-center">
<div className="flex h-12 w-12 items-center justify-center rounded-full bg-red-50">
<AlertCircle className="h-6 w-6 text-red-500" />
</div>
<h1 className="text-lg font-semibold text-medical-dark">
constructor method · typescript · L16-L19 (4 LOC)frontend/src/components/ErrorBoundary.tsx
constructor(props: Props) {
super(props);
this.state = { hasError: false };
}getDerivedStateFromError method · typescript · L21-L23 (3 LOC)frontend/src/components/ErrorBoundary.tsx
static getDerivedStateFromError(error: Error): State {
return { hasError: true, error };
}componentDidCatch method · typescript · L25-L27 (3 LOC)frontend/src/components/ErrorBoundary.tsx
componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
console.error("Error caught by ErrorBoundary:", error, errorInfo);
}Repobility analyzer · published findings · https://repobility.com
render method · typescript · L33-L70 (38 LOC)frontend/src/components/ErrorBoundary.tsx
render() {
if (this.state.hasError) {
return (
<div className="flex min-h-screen flex-col items-center justify-center bg-medical-surface px-4">
<div className="flex max-w-md flex-col items-center gap-4 text-center">
<div className="flex h-12 w-12 items-center justify-center rounded-full bg-red-50">
<AlertCircle className="h-6 w-6 text-red-500" />
</div>
<h1 className="text-lg font-semibold text-medical-dark">
Something went wrong
</h1>
<p className="text-sm text-medical-muted">
We encountered an unexpected error. Please try again or contact support if the issue persists.
</p>
{this.state.error && (
<details className="w-full text-left">
<summary className="cursor-pointer text-xs text-medical-muted hover:text-medical-dark">
Error details
</summary>
<pre cExportButtons function · typescript · L14-L154 (141 LOC)frontend/src/components/ExportButtons.tsx
export default function ExportButtons({
sessionId,
draftId,
noteText,
noteType,
}: ExportButtonsProps) {
const [exportingPdf, setExportingPdf] = useState(false);
const [exportingMeditext, setExportingMeditext] = useState(false);
const [exportError, setExportError] = useState<string | null>(null);
const handleExportText = () => {
const blob = new Blob(
[
`MedScribe AI - Clinical Note Draft\n`,
`Note Type: ${noteType}\n`,
`Session: ${sessionId}\n`,
`Exported: ${new Date().toISOString()}\n`,
`\n${"=".repeat(60)}\n`,
`DRAFT - Requires physician review before clinical use\n`,
`${"=".repeat(60)}\n\n`,
noteText,
`\n\n${"=".repeat(60)}\n`,
`This note was generated by MedScribe AI, a documentation copilot.\n`,
`All content is a draft and requires physician attestation.\n`,
],
{ type: "text/plain;charset=utf-8" },
);
const url = URL.createObjectURL(blob);
conNavbar function · typescript · L8-L94 (87 LOC)frontend/src/components/Navbar.tsx
export default function Navbar() {
const { user, logout } = useAuth();
const [menuOpen, setMenuOpen] = useState(false);
const [mobileOpen, setMobileOpen] = useState(false);
const menuRef = useRef<HTMLDivElement>(null);
useEffect(() => {
function handleClickOutside(e: MouseEvent) {
if (menuRef.current && !menuRef.current.contains(e.target as Node)) {
setMenuOpen(false);
}
}
document.addEventListener("mousedown", handleClickOutside);
return () => document.removeEventListener("mousedown", handleClickOutside);
}, []);
return (
<header className="sticky top-0 z-30 border-b border-medical-border bg-white">
<div className="flex h-14 items-center justify-between px-4 lg:px-6">
{/* Left: logo + mobile toggle */}
<div className="flex items-center gap-3">
<button
className="lg:hidden btn-ghost p-1.5"
onClick={() => setMobileOpen(!mobileOpen)}
aria-label="Toggle sidebar"
handleClickOutside function · typescript · L15-L19 (5 LOC)frontend/src/components/Navbar.tsx
function handleClickOutside(e: MouseEvent) {
if (menuRef.current && !menuRef.current.contains(e.target as Node)) {
setMenuOpen(false);
}
}NoteEditor function · typescript · L13-L110 (98 LOC)frontend/src/components/NoteEditor.tsx
export default function NoteEditor({
value,
onChange,
readOnly = false,
showDraftWatermark = true,
}: NoteEditorProps) {
const [copied, setCopied] = useState(false);
const textareaRef = useRef<HTMLTextAreaElement>(null);
useEffect(() => {
if (textareaRef.current) {
textareaRef.current.style.height = "auto";
textareaRef.current.style.height = `${Math.max(
400,
textareaRef.current.scrollHeight,
)}px`;
}
}, [value]);
const handleCopy = async () => {
try {
await navigator.clipboard.writeText(value);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
} catch {
const textarea = document.createElement("textarea");
textarea.value = value;
document.body.appendChild(textarea);
textarea.select();
document.execCommand("copy");
document.body.removeChild(textarea);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
}
};
return (
<div clagetQuotaLimits function · typescript · L11-L13 (3 LOC)frontend/src/components/QuotaWidget.tsx
function getQuotaLimits(tier: SubscriptionTier) {
return tier === "pro" ? { limit: 50, plan: "Pro" } : { limit: 10, plan: "Free" };
}countSessionsToday function · typescript · L15-L25 (11 LOC)frontend/src/components/QuotaWidget.tsx
function countSessionsToday(sessions: NoteSession[]): number {
const today = new Date();
today.setHours(0, 0, 0, 0);
return sessions.filter((session) => {
if (!session.created_at) return false;
const sessionDate = new Date(session.created_at);
sessionDate.setHours(0, 0, 0, 0);
return sessionDate.getTime() === today.getTime();
}).length;
}QuotaWidget function · typescript · L27-L83 (57 LOC)frontend/src/components/QuotaWidget.tsx
export default function QuotaWidget({ sessions, tier }: QuotaWidgetProps) {
const { limit, plan } = getQuotaLimits(tier);
const used = countSessionsToday(sessions);
const percentage = (used / limit) * 100;
const remaining = limit - used;
return (
<div className="card p-6 mb-6">
<div className="flex items-start justify-between mb-4">
<div className="flex items-center gap-3">
<div className="flex h-10 w-10 items-center justify-center rounded-lg bg-brand-50">
<BarChart3 className="h-5 w-5 text-brand-600" />
</div>
<div>
<h3 className="text-sm font-medium text-medical-dark">Daily Quota</h3>
<p className="mt-0.5 text-xs text-medical-muted">{plan} Plan</p>
</div>
</div>
<div className="text-right">
<p className="text-sm font-semibold text-medical-dark">
{used} of {limit}
</p>
<p className="mt-0.5 text-xs text-medical-muted">
Repobility's GitHub App fixes findings like these · https://github.com/apps/repobility-bot
formatDate function · typescript · L15-L24 (10 LOC)frontend/src/components/SessionCard.tsx
function formatDate(dateString: string): string {
const date = new Date(dateString);
return date.toLocaleDateString("en-US", {
month: "short",
day: "numeric",
year: "numeric",
hour: "numeric",
minute: "2-digit",
});
}SessionCard function · typescript · L26-L144 (119 LOC)frontend/src/components/SessionCard.tsx
export default function SessionCard({ session, onDelete }: SessionCardProps) {
const [deleting, setDeleting] = useState(false);
const isDraft = session.status === "draft";
const latestDraft =
session.drafts && session.drafts.length > 0
? session.drafts[session.drafts.length - 1]
: null;
const handleDelete = async (e: React.MouseEvent) => {
e.preventDefault();
e.stopPropagation();
const confirmed = window.confirm(
"Delete this session and all its drafts? This cannot be undone."
);
if (!confirmed) return;
setDeleting(true);
try {
await api.delete(`/notes/sessions/${session.id}`);
onDelete?.();
} catch (err) {
console.error("Failed to delete session:", err);
alert("Failed to delete session. Please try again.");
} finally {
setDeleting(false);
}
};
return (
<Link href={`/notes/${session.id}`} className="block">
<div className="card p-4 transition-shadow hover:shadow-elevateSidebar function · typescript · L52-L106 (55 LOC)frontend/src/components/Sidebar.tsx
export default function Sidebar() {
const pathname = usePathname();
return (
<aside className="flex h-full w-60 flex-col border-r border-medical-border bg-white">
<nav className="flex-1 space-y-1 px-3 py-4">
<p className="mb-2 px-3 text-xs font-medium uppercase tracking-wider text-medical-muted">
Clinical
</p>
{NAV_ITEMS.map((item) => {
const isActive =
pathname === item.href ||
(item.href !== "/dashboard" && pathname.startsWith(item.href));
return (
<Link
key={item.href}
href={item.href}
className={`flex items-center gap-3 rounded-lg px-3 py-2 text-sm font-medium transition-colors ${
isActive
? "bg-brand-50 text-brand-700"
: "text-medical-muted hover:bg-gray-50 hover:text-medical-dark"
}`}
>
<item.icon className="h-4 w-4" />
{item.labelsleep function · typescript · L22-L24 (3 LOC)frontend/src/lib/api.ts
function sleep(ms: number): Promise<void> {
return new Promise((resolve) => setTimeout(resolve, ms));
}AuthProvider function · typescript · L30-L138 (109 LOC)frontend/src/lib/auth.ts
export function AuthProvider({ children }: { children: ReactNode }) {
const [user, setUser] = useState<User | null>(null);
const [token, setToken] = useState<string | null>(null);
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
const router = useRouter();
useEffect(() => {
const storedToken = localStorage.getItem("medscribe_token");
const storedUser = localStorage.getItem("medscribe_user");
if (storedToken && storedUser) {
setToken(storedToken);
try {
setUser(JSON.parse(storedUser));
} catch {
localStorage.removeItem("medscribe_user");
}
}
setIsLoading(false);
}, []);
const clearError = useCallback(() => setError(null), []);
const login = useCallback(
async (credentials: UserLogin) => {
setIsLoading(true);
setError(null);
try {
const formData = new URLSearchParams();
formData.append("username", credentials.useruseAuth function · typescript · L140-L146 (7 LOC)frontend/src/lib/auth.ts
export function useAuth(): AuthContextValue {
const ctx = useContext(AuthContext);
if (!ctx) {
throw new Error("useAuth must be used inside AuthProvider");
}
return ctx;
}test_one_note_type function · python · L93-L155 (63 LOC)scripts/smoke_test_openai.py
async def test_one_note_type(
note_type: str,
language: str = "en",
model: str = "gpt-4o",
) -> dict:
"""Generate one structured note and validate it. Returns result dict."""
from app.services.structured_generation import (
generate_structured_note,
StructuredGenerationError,
)
dictation = SAMPLE_DICTATION.get(note_type)
if not dictation:
return {"note_type": note_type, "status": "SKIP", "reason": "No sample dictation"}
start = time.monotonic()
try:
structured_note, meta = await generate_structured_note(
input_text=dictation,
note_type=note_type,
language=language,
)
elapsed = time.monotonic() - start
# Render to text
rendered = render_note_text(structured_note)
# Validate plan has items
plan_count = len(structured_note.plan)
billing_count = len(structured_note.billing_keywords)
return {
"note_type":main function · python · L158-L224 (67 LOC)scripts/smoke_test_openai.py
async def main():
import argparse
parser = argparse.ArgumentParser(description="MedScribe AI OpenAI Smoke Test")
parser.add_argument("note_types", nargs="*", help="Note types to test (default: all)")
parser.add_argument("--language", default="en", choices=["en", "es"])
parser.add_argument("--runs", type=int, default=1, help="Number of runs per type")
args = parser.parse_args()
# Verify API key
api_key = os.environ.get("OPENAI_API_KEY", "")
if not api_key or api_key.startswith("sk-..."):
print("ERROR: Set OPENAI_API_KEY environment variable")
sys.exit(1)
types_to_test = args.note_types or list(SAMPLE_DICTATION.keys())
print(f"MedScribe AI — OpenAI Structured Output Smoke Test")
print(f"Schema version: {SCHEMA_VERSION}")
print(f"Language: {args.language}")
print(f"Note types: {', '.join(types_to_test)}")
print(f"Runs per type: {args.runs}")
print(f"{'=' * 60}")
results = []
for note_type in types‹ prevpage 5 / 5