Function bodies 169 total
GET function · javascript · L7-L39 (33 LOC)src/app/api/editors/route.js
export async function GET() {
try {
// Join the `email_credentials` and `profile` tables on the `user_id` column
const result = await query(
`
SELECT
ec.id,
ec.email,
p.name,
p.photo,
p.title,
p.degree,
p.university
FROM
email_credentials ec
LEFT JOIN
profile p
ON
ec.id = p.user_id
WHERE
ec.role = 'editor'
`
);
return NextResponse.json(result.rows);
} catch (error) {
console.error("Error fetching editors:", error);
return NextResponse.json(
{ message: "Error fetching editors" },
{ status: 500 }
);
}
}DELETE function · javascript · L10-L51 (42 LOC)src/app/api/images/delete-image/route.js
export async function DELETE(req) {
try {
// Parse the request to get the public ID of the image to delete
const { public_id } = await req.json();
if (!public_id) {
return new Response(
JSON.stringify({ error: "Public ID is required" }),
{ status: 400 }
);
}
// Call Cloudinary to delete the image by its public ID
const result = await new Promise((resolve, reject) => {
cloudinary.uploader.destroy(public_id, (error, result) => {
if (error) {
console.error("Error deleting from Cloudinary:", error);
reject(
new Response(
JSON.stringify({
error: "Failed to delete image from Cloudinary",
}),
{ status: 500 }
)
);
} else {uploadBufferToCloudinary function · javascript · L13-L31 (19 LOC)src/app/api/images/generate/route.js
async function uploadBufferToCloudinary(base64, publicId) {
// base64 should be like "data:image/png;base64,AAAA..."
return new Promise((resolve, reject) => {
cloudinary.uploader.upload(
base64,
{
resource_type: "image",
public_id: publicId,
folder: "ai_generated",
overwrite: true,
quality: "auto:good",
},
(err, result) => {
if (err) return reject(err);
resolve(result);
}
);
});
}POST function · javascript · L33-L89 (57 LOC)src/app/api/images/generate/route.js
export async function POST(req) {
try {
const { text, articleId } = await req.json();
if (!text) {
return NextResponse.json({ error: "Missing text" }, { status: 400 });
}
if (!process.env.OPENAI_API_KEY) {
return NextResponse.json({ error: "OpenAI API key not configured" }, { status: 500 });
}
// Build prompt — keep it clear, instruct "no text"
const prompt = `${text}\n\nCreate a clean scientific illustration (no text on the image) that visually represents the simplified article above. Minimalistic, clear, high-quality, suitable as a magazine-style cover image.`;
// Call OpenAI Images (gpt-image-1) - returns base64
const openaiResp = await fetch("https://api.openai.com/v1/images/generations", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${process.env.OPENAI_API_KEY}`,
},
body: JSON.stringify({
model: "gpt-image-1",
prompt,
siPOST function · javascript · L18-L78 (61 LOC)src/app/api/images/upload-image/route.js
export async function POST(req) {
// Parse the incoming form data
const formData = await req.formData();
const file = formData.get("file"); // Get the file from the form data
if (!file) {
return new Response(JSON.stringify({ error: "No file uploaded" }), {
status: 400,
});
}
// Convert the buffer to a Node.js readable stream
const buffer = await file.arrayBuffer(); // Get the file buffer
const readableStream = new Readable({
read() {
this.push(Buffer.from(buffer)); // Push the buffer to the stream
this.push(null); // Signal the end of the stream
},
});
try {
// Upload the image buffer to Cloudinary
const uploadResult = await new Promise((resolve, reject) => {
const uploadStream = cloudinary.uploader.upload_stream(
{
resource_type: "auto", // Automatically detect resource type
upload_preset: proPOST function · javascript · L27-L98 (72 LOC)src/app/api/magic-link/create/route.js
export async function POST(req) {
const adminCheck = requireAdmin(req);
if (adminCheck instanceof NextResponse) return adminCheck;
try {
const body = await req.json();
const tenant = defaultTenant.shortName; // Force tenant to current panel
const email = (body?.email || "").toLowerCase();
if (!tenant || !email) {
return NextResponse.json({ error: "Missing tenant or email" }, { status: 400 });
}
// Load tenant env
getTenantPool(tenant);
const redirectUrl = "/assigned-articles";
// Generate raw + hashed token
const rawToken = crypto.randomBytes(32).toString("hex");
const tokenHash = crypto.createHash("sha256").update(rawToken).digest("hex");
// 30 days from now
const expiresAt = new Date(Date.now() + 30 * 24 * 60 * 60 * 1000);
// Store into tenant DB with expiration
const insertSQL = `
INSERT INTO magic_links (email, token_hash, redirect_url, expires_at)
VALUES ($1, $2, $3, $4)
RETURNING idDELETE function · javascript · L6-L39 (34 LOC)src/app/api/magic-link/delete/route.js
export async function DELETE(req) {
const adminCheck = requireAdmin(req);
if (adminCheck instanceof NextResponse) return adminCheck;
try {
const url = new URL(req.url);
const id = url.searchParams.get("id");
if (!id) {
return NextResponse.json(
{ error: "Missing id" },
{ status: 400 }
);
}
// 🔒 Use backend tenant only — prevent cross-tenant deletion
const tenant = defaultTenant.shortName;
// Perform deletion
await tenantQuery(
tenant,
"DELETE FROM magic_links WHERE id = $1",
[id]
);
return NextResponse.json({ success: true });
} catch (error) {
console.error("Delete magic link error:", error);
return NextResponse.json(
{ error: "Server error" },
{ status: 500 }
);
}
}Repobility · code-quality intelligence · https://repobility.com
GET function · javascript · L7-L58 (52 LOC)src/app/api/magic-link/list/route.js
export async function GET(req) {
const adminCheck = requireAdmin(req);
if (adminCheck instanceof NextResponse) return adminCheck;
// const TENANT_DOMAINS = {
// NF: "https://nfsimplified.com",
// EB: "https://sseb.vercel.app",
// Vitiligo: "https://ssvitiligo.vercel.app",
// CF: "https://sscf-coral.vercel.app",
// ALS: "https://ssals-ten.vercel.app",
// HS: "https://science-simplified-mu.vercel.app/",
// Ashermans: "https://ssashermans.vercel.app",
// RYR1: "https://ssryr1.vercel.app",
// Aicardi: "https://ssaicardi.vercel.app",
// Progeria: "https://ssprogeria.vercel.app",
// RETT: "https://ssrett.vercel.app",
// Canavan: "https://sscanavan.vercel.app",
// HUNTINGTONS: "https://sshuntingtons.vercel.app",
// };
const tenant_domain = tenant.domain;
try {
const allLinks = [];
// Loop over all tenant keys (NF, EB, CF, HS, etc)
constGET function · javascript · L31-L123 (93 LOC)src/app/api/magic-link/verify/route.js
export async function GET(req) {
try {
const { searchParams } = new URL(req.url);
const tenant = defaultTenant.shortName; // Force tenant to current panel
const token = searchParams.get("token");
if (!tenant || !token) {
return NextResponse.json({ error: "Missing tenant or token" }, { status: 400 });
}
// Hash token
const tokenHash = crypto.createHash("sha256").update(token).digest("hex");
// Get magic link row
const sql = `
SELECT *
FROM magic_links
WHERE token_hash = $1
`;
const { rows } = await tenantQuery(tenant, sql, [tokenHash]);
if (rows.length === 0) {
return NextResponse.json({ error: "Invalid or used token" }, { status: 400 });
}
const magicLink = rows[0];
// Check expiration
if (magicLink.expires_at && new Date() > new Date(magicLink.expires_at)) {
return NextResponse.json({ error: "Token expired" }, { status: 400 });
}
// Mark token as used
await tenaPOST function · javascript · L4-L32 (29 LOC)src/app/api/pdfToText/route.js
export async function POST(req) {
try {
// Parse the FormData from the request
const formData = await req.formData();
const file = formData.get("file");
if (!file) {
return NextResponse.json({ error: "No file provided" }, { status: 400 });
}
// Convert file to Buffer
const arrayBuffer = await file.arrayBuffer();
const buffer = Buffer.from(arrayBuffer);
// Parse the PDF file
const pdfData = await pdfParse(buffer);
return NextResponse.json(
{ message: "File uploaded successfully", text: pdfData.text },
{ status: 200 }
);
} catch (error) {
console.error("File upload error:", error);
return NextResponse.json(
{ error: "Error processing the file" },
{ status: 500 }
);
}
}DELETE function · javascript · L10-L54 (45 LOC)src/app/api/profile/delete-image/route.js
export async function DELETE(req) {
try {
// Parse the request to get the public ID of the image to delete
const { public_id } = await req.json();
if (!public_id) {
return new Response(
JSON.stringify({ error: "Public ID is required" }),
{ status: 400 }
);
}
// Ensure the public_id corresponds to the 'profiles' folder
const fullPublicId = `profiles/${public_id}`;
// Call Cloudinary to delete the image by its public ID
const result = await new Promise((resolve, reject) => {
cloudinary.uploader.destroy(fullPublicId, (error, result) => {
if (error) {
console.error("Error deleting from Cloudinary:", error);
reject(
new Response(
JSON.stringify({
error: "Failed to delete image from Cloudinary",
POST function · javascript · L5-L55 (51 LOC)src/app/api/profile/update/route.js
export async function POST(req) {
try {
const {
userId,
name,
photo,
bio,
degree,
title,
university,
linkedin,
labLink,
} = await req.json();
if (!userId) {
return NextResponse.json(
{ message: "User ID is required." },
{ status: 400 }
);
}
// Update the profile
await query(
`UPDATE profile
SET name = $1, photo = $2, bio = $3, degree = $4, title = $5, university = $6, linkedin = $7, lablink = $8
WHERE user_id = $9`,
[
name,
photo,
bio,
degree,
title,
university,
linkedin,
labLink,
userId,
]
);
return NextResponse.json(
{ message: "Profile upPOST function · javascript · L18-L79 (62 LOC)src/app/api/profile/upload-image/route.js
export async function POST(req) {
// Parse the incoming form data
const formData = await req.formData();
const file = formData.get("file"); // Get the file from the form data
if (!file) {
return new Response(JSON.stringify({ error: "No file uploaded" }), {
status: 400,
});
}
// Convert the buffer to a Node.js readable stream
const buffer = await file.arrayBuffer(); // Get the file buffer
const readableStream = new Readable({
read() {
this.push(Buffer.from(buffer)); // Push the buffer to the stream
this.push(null); // Signal the end of the stream
},
});
try {
// Upload the image buffer to Cloudinary in the 'profiles' folder
const uploadResult = await new Promise((resolve, reject) => {
const uploadStream = cloudinary.uploader.upload_stream(
{
resource_type: "auto", // Automatically detect resource type
GET function · javascript · L6-L34 (29 LOC)src/app/api/profile/[userId]/route.js
export async function GET(request, { params }) {
const { userId } = params; // Extract the userId from the URL parameters
try {
// Fetch the profile from the database using the provided userId
const profileResult = await query(
`SELECT user_id, name, email, photo, bio, degree, title, university, linkedin, lablink
FROM profile
WHERE user_id = $1`,
[userId]
);
// Check if the profile exists
if (profileResult.rows.length > 0) {
return NextResponse.json(profileResult.rows[0]); // Send the profile as a JSON response
} else {
return NextResponse.json(
{ message: "Profile not found" },
{ status: 404 }
); // Profile not found
}
} catch (error) {
console.error("Error fetching profile:", error);
return NextResponse.json(
{ message: "Error fetching profile" },
{ status: 50POST function · javascript · L418-L663 (246 LOC)src/app/api/pubmed/route.js
export async function POST(req) {
try {
const { url } = await req.json();
const validPattern =
/(pubmed\.ncbi\.nlm\.nih\.gov\/\d+)|(pmc\.ncbi\.nlm\.nih\.gov\/articles\/PMC\d+)/i;
if (!url || !validPattern.test(url)) {
return NextResponse.json(
{ error: "Invalid PubMed or PubMed Central URL" },
{ status: 400 }
);
}
// Detect DB & ID
let db = "pubmed";
let id = null;
if (/pubmed\.ncbi\.nlm\.nih\.gov/i.test(url)) {
id = url.match(/pubmed\.ncbi\.nlm\.nih\.gov\/(\d+)/i)?.[1];
} else if (/pmc\.ncbi\.nlm\.nih\.gov/i.test(url)) {
id = url.match(/PMC(\d+)/i)?.[1];
db = "pmc";
}
if (!id) {
return NextResponse.json({ error: "Could not extract ID" }, { status: 400 });
}
// Fetch from correct db
const efetchUrl = `https://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fPowered by Repobility — scan your code at https://repobility.com
ArticleCard function · javascript · L171-L225 (55 LOC)src/app/(editor)/assigned-articles/page.jsx
function ArticleCard({ article }) {
const isPublished = article.status === "published";
return (
<Link
href={`/assigned-articles/${article.id}`}
className="admin-card admin-card-interactive block"
>
<div className="p-5 flex gap-5">
{/* Thumbnail */}
<div className="flex-shrink-0">
<img
src={article.image_url || "/default-article-image.png"}
alt=""
className="w-24 h-24 object-cover rounded-lg bg-gray-100"
/>
</div>
{/* Content */}
<div className="flex-1 min-w-0">
<div className="flex items-start justify-between gap-4 mb-2">
<h3 className="text-[1.6rem] font-semibold text-gray-900 line-clamp-2">
{article.title}
</h3>
<StRootLayout function · javascript · L23-L45 (23 LOC)src/app/layout.js
export default function RootLayout({ children }) {
return (
<html lang="en">
<body className={`${outfitFont.variable} antialiased`}>
<Analytics />
<ThemeProvider>
<ToastContainer
position="top-right"
autoClose={2000}
hideProgressBar={true}
closeOnClick
pauseOnHover
draggable
/>
{children}
</ThemeProvider>
</body>
</html>
);
}MagicSuccess function · javascript · L1-L8 (8 LOC)src/app/magic-success/page.js
export default function MagicSuccess() {
return (
<div style={{ padding: 40, textAlign: "center" }}>
<h1>Login Successful</h1>
<p>You will be redirected shortly...</p>
</div>
);
}HomeContent function · javascript · L25-L140 (116 LOC)src/app/page.jsx
function HomeContent() {
const router = useRouter();
const searchParams = useSearchParams();
const { role } = useAuthStore();
console.log("User: ", role);
const handleSearchSubmit = (query) => {
// Navigate to the article search page with the query
router.push(`/articles}`);
};
// Handle HSF redirect (e.g., ?hsf-id=100941 -> /articles/126)
// Only active for HS (Hidradenitis Suppurativa) tenant
useEffect(() => {
if (tenant.shortName !== "HS") return; // Only for HS Foundation links
const hsfId = searchParams.get("hsf-id");
if (hsfId) {
const articleId = getArticleIdFromHsfId(hsfId);
if (articleId) {
router.replace(`/articles/${articleId}`);
return;
}
}
}, [searchParams, router]);
// Check if tenant opts into full-width banner background
const useFullWidthBg = tenant.homeBG_full === true;
useEffect(() => {
cHome function · javascript · L143-L149 (7 LOC)src/app/page.jsx
export default function Home() {
return (
<Suspense fallback={<div>Loading...</div>}>
<HomeContent />
</Suspense>
);
}fetchEditors function · javascript · L23-L40 (18 LOC)src/app/(public)/about/page.jsx
async function fetchEditors() {
const result = await query(`
SELECT DISTINCT
p.user_id AS id,
p.name,
p.photo,
p.title,
p.degree,
p.university
FROM article a
JOIN profile p
ON (a.certifiedby->>'userId')::INT = p.user_id
WHERE a.certifiedby IS NOT NULL
ORDER BY p.name
`);
return result.rows;
}getInitial function · javascript · L43-L45 (3 LOC)src/app/(public)/about/page.jsx
function getInitial(name) {
return name && name.length > 0 ? name[0].toUpperCase() : "N/A";
}getTrialIcon function · javascript · L12-L54 (43 LOC)src/app/(public)/clinical-trials/[nctId]/page.jsx
function getTrialIcon(trial) {
const protocol = trial.raw_data?.protocolSection;
if (!protocol) return "/trial-icons/observational.png";
const studyType = protocol.designModule?.studyType?.toLowerCase() || "";
// Expanded access
if (studyType.includes("expanded")) {
return "/trial-icons/expandedaccess.png";
}
// Observational
if (studyType.includes("observational")) {
return "/trial-icons/observational.png";
}
// Interventional
if (studyType.includes("interventional")) {
const phasesRaw = protocol.designModule?.phases;
const phases = Array.isArray(phasesRaw)
? phasesRaw.map((p) => p.toLowerCase())
: typeof phasesRaw === "string"
? [phasesRaw.toLowerCase()]
: [];
if (phases.some((p) => p.includes("phase 1"))) {
return "/trial-icons/phase1.png";
}
if (phases.some((p) => p.includes("phase 2"))) {
return "/trial-icons/phase2.png";
}
if (phases.some((p) => p.includes("phase 3") || p.includeAll rows above produced by Repobility · https://repobility.com
TrialDetailPage function · javascript · L56-L173 (118 LOC)src/app/(public)/clinical-trials/[nctId]/page.jsx
export default function TrialDetailPage() {
const { nctId } = useParams();
const [trial, setTrial] = useState(null);
const [loading, setLoading] = useState(true);
const [showAllLocations, setShowAllLocations] = useState(false);
useEffect(() => {
const fetchTrial = async () => {
const res = await fetch(`/api/clinical-trials/${nctId}`, {
cache: "no-store",
});
const data = await res.json();
setTrial(data.trial);
setLoading(false);
};
fetchTrial();
}, [nctId]);
if (loading) return <p className="page-loading">Loading…</p>;
if (!trial) return <p className="page-error">Trial not found</p>;
const protocol = trial.raw_data?.protocolSection;
const locations =
protocol?.contactsLocationsModule?.locations
?.map((l) => [l.city, l.state, l.country].filter(Boolean).join(", "))
.filter(Boolean) || [];
const minAge = protocol?.eligibilityModule?.minimumAge;
const maxAge = protocol?.eligibilityModule?.maximuContactPage function · javascript · L18-L341 (324 LOC)src/app/(public)/contact/page.jsx
export default function ContactPage() {
const [articleLink, setArticleLink] = useState("");
const [sendArticleAnonymously, setSendArticleAnonymously] = useState(false);
const [bugName, setBugName] = useState("");
const [bugEmail, setBugEmail] = useState("");
const [bugDescription, setBugDescription] = useState("");
const [bugImage, setBugImage] = useState(null);
const [sendBugAnonymously, setSendBugAnonymously] = useState(false);
const [isArticleLoading, setIsArticleLoading] = useState(false);
const [isBugLoading, setIsBugLoading] = useState(false);
const handleArticleSubmit = async (e) => {
e.preventDefault();
setIsArticleLoading(true);
const user = useAuthStore.getState().user; // Access user from Zustand store
try {
console.log(articleLink, sendArticleAnonymously, user?.userId);
const response = await fetch("/api/contact/article-request", {
method: "POST",
LoginForm function · javascript · L15-L132 (118 LOC)src/app/(public)/login/page.jsx
export default function LoginForm() {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [showPassword, setShowPassword] = useState(false);
const [isLoading, setIsLoading] = useState(false);
const { login, error } = useAuth();
const router = useRouter();
const handleSubmit = async (e) => {
e.preventDefault();
setIsLoading(true);
try {
await login({ email, password });
toast.success("Login successful!");
router.push("/");
} catch (err) {
console.error("Login failed", err);
toast.error(error || "Login failed!");
} finally {
setIsLoading(false);
}
};
useEffect(() => {
document.documentElement.style.setProperty('--auth-bg-top', `url(/assets/${tenant.pathName}/${tenant.loginBGTop})`);
document.documentElement.style.setProperty('--auth-bg-bottom', `url(/assets/${tenant.pathName}/$CreateAccountForm function · javascript · L13-L244 (232 LOC)src/app/(public)/signup/page.jsx
export default function CreateAccountForm() {
const [formData, setFormData] = useState({
firstName: "",
lastName: "",
email: "",
password: "",
confirmPassword: "",
});
const [showPassword, setShowPassword] = useState(false);
const [showConfirmPassword, setShowConfirmPassword] = useState(false);
const [isLoading, setIsLoading] = useState(false); // Add isLoading state
const router = useRouter();
const handleChange = (e) => {
const { name, value } = e.target;
setFormData((prevState) => ({
...prevState,
[name]: value,
}));
};
const handleSubmit = async (e) => {
e.preventDefault();
if (formData.password !== formData.confirmPassword) {
toast.error("Passwords do not match.");
return;
}
setIsLoading(true); // Set loading to true
try {
const response = await fetch("/api/auth/signup", {
ConfirmDialog function · javascript · L28-L82 (55 LOC)src/components/admin/ConfirmDialog.jsx
export default function ConfirmDialog({
open,
onOpenChange,
title,
description,
confirmLabel = "Confirm",
cancelLabel = "Cancel",
variant = "default",
onConfirm,
loading = false
}) {
return (
<AlertDialog open={open} onOpenChange={onOpenChange}>
<AlertDialogContent className="max-w-[400px]">
<AlertDialogHeader>
<AlertDialogTitle className="text-[1.8rem]">
{title}
</AlertDialogTitle>
<AlertDialogDescription className="text-[1.4rem]">
{description}
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel
className="text-[1.4rem] px-6 py-3"
disabled={loading}
>
{cancelLabel}
</AlertDialogCancel>
EmptyState function · javascript · L21-L39 (19 LOC)src/components/admin/EmptyState.jsx
export default function EmptyState({
icon = "inbox",
title,
description,
action
}) {
const Icon = iconMap[icon] || Inbox;
return (
<div className="empty-state">
<Icon className="empty-state-icon" strokeWidth={1.5} />
<h3 className="empty-state-title">{title}</h3>
{description && (
<p className="empty-state-description">{description}</p>
)}
{action && <div className="mt-2">{action}</div>}
</div>
);
}PageHeader function · javascript · L16-L51 (36 LOC)src/components/admin/PageHeader.jsx
export default function PageHeader({
title,
subtitle,
backHref,
backLabel = "Back",
actions,
children
}) {
return (
<div className="page-header">
{backHref && (
<Link
href={backHref}
className="flex items-center gap-2 text-gray-600 hover:text-gray-900 transition-colors mb-2 w-fit"
>
<ArrowLeft size={18} />
<span className="text-[1.4rem] font-medium">{backLabel}</span>
</Link>
)}
<div className="page-header-row">
<div>
<h1 className="page-header-title">{title}</h1>
{subtitle && (
<p className="page-header-subtitle">{subtitle}</p>
)}
</div>
{actions && (
<div className="page-header-actions">
{actions}
SearchInput function · javascript · L15-L67 (53 LOC)src/components/admin/SearchInput.jsx
export default function SearchInput({
value,
onChange,
placeholder = "Search...",
debounceMs = 300,
className = ""
}) {
const [localValue, setLocalValue] = useState(value);
// Sync with external value
useEffect(() => {
setLocalValue(value);
}, [value]);
// Debounced change handler
useEffect(() => {
const timer = setTimeout(() => {
if (localValue !== value) {
onChange(localValue);
}
}, debounceMs);
return () => clearTimeout(timer);
}, [localValue, debounceMs, onChange, value]);
const handleClear = useCallback(() => {
setLocalValue("");
onChange("");
}, [onChange]);
return (
<div className={`search-input-wrapper ${className}`}>
<Search size={18} className="search-input-icon" />
<input
type="text"
value={localValue}
onChange={(e) => setLocalValue(e.target.valuRepobility · MCP-ready · https://repobility.com
StatsCard function · javascript · L15-L51 (37 LOC)src/components/admin/StatsCard.jsx
export default function StatsCard({
label,
value,
change,
changeType = "neutral",
icon: Icon,
className = ""
}) {
return (
<div className={`stats-card ${className}`}>
<div className="flex items-center justify-between">
<span className="stats-card-label">{label}</span>
{Icon && (
<div className="text-gray-400">
<Icon size={20} />
</div>
)}
</div>
<div className="stats-card-value">{value}</div>
{change && (
<div
className={`stats-card-change ${
changeType === "positive"
? "stats-card-change-positive"
: changeType === "negative"
? "stats-card-change-negative"
: "text-gray-500"
}`}
>
StatusBadge function · javascript · L56-L78 (23 LOC)src/components/admin/StatusBadge.jsx
export default function StatusBadge({
variant = "neutral",
label,
showIcon = true,
size = "md"
}) {
const config = variants[variant] || variants.neutral;
const Icon = config.icon;
const sizeClass = size === "sm" ? "badge-sm" : size === "lg" ? "badge-lg" : "";
return (
<span className={`${config.className} ${sizeClass}`}>
{showIcon && Icon && (
<Icon
size={size === "sm" ? 10 : size === "lg" ? 16 : 12}
className={variant === "loading" ? "animate-spin" : ""}
/>
)}
{label}
</span>
);
}ArticleCard function · javascript · L28-L194 (167 LOC)src/components/ArticleCard/ArticleCard.jsx
function ArticleCard({
id,
imageUrl,
date,
title,
summary,
authorImageUrl,
authorName,
authorCreds,
authorInstitution,
pageType,
}) {
const router = useRouter();
const [isLoading, setIsLoading] = useState(false);
const displayName =
authorName && authorName.trim() ? authorName : "Anonymous";
const showDegree =
authorCreds && authorCreds.trim() && authorCreds !== "No Degree";
const articleUrl =
pageType === "pending"
? `/pending-articles/${id}`
: pageType === "assigned"
? `/assigned-articles/${id}`
: `/articles/${id}`;
const handleCardClick = () => {
router.push(articleUrl);
};
const handleFeatureStatus = async (shouldBeFeatured) => {
setIsLoading(true);
try {
const response = await fetch("/api/articles/actions/feature", {
method: "POST",
headers: { "Content-Type": "applicaArticleCardSkeleton function · javascript · L3-L22 (20 LOC)src/components/ArticleCardSkeleton/ArticleCardSkeleton.jsx
export function ArticleCardSkeleton() {
return (
<div className="flex flex-col w-full gap-8">
<Skeleton className="h-[250px] w-full rounded-xl" />
<div className="space-y-4">
<Skeleton className="h-6 w-[100px]" />
<Skeleton className="h-8 w-full" />
<Skeleton className="h-8 w-full" />
<Skeleton className="h-8 w-[90%]" />
</div>
<div className="flex items-center space-x-4">
<Skeleton className="h-20 w-20 rounded-full" />
<div className="space-y-4">
<Skeleton className="h-6 w-[250px]" />
<Skeleton className="h-6 w-[200px]" />
</div>
</div>
</div>
);
}ArticlesListPaginated function · javascript · L18-L229 (212 LOC)src/components/ArticlesListPaginated/ArticlesListPaginated.jsx
export default function ArticlesListPaginated({
articles = [],
articlesPerPage = 6,
loading = false,
error = false,
pageType = "",
}) {
const [currentPage, setCurrentPage] = useState(1);
const [isMobile, setIsMobile] = useState(false);
const isHS = tenant.shortName === "HS"; // ✅ key flag
useEffect(() => {
const handleResize = () => setIsMobile(window.innerWidth <= 768);
handleResize();
window.addEventListener("resize", handleResize);
return () => window.removeEventListener("resize", handleResize);
}, []);
const totalPages = Math.max(1, Math.ceil(articles.length / articlesPerPage));
useEffect(() => {
if (currentPage > totalPages) {
setCurrentPage(totalPages);
}
}, [articles.length, totalPages, currentPage]);
const selectedArticles = articles.slice(
(currentPage - 1) * articlesPerPage,
currentPage * articlesPerPage
);
const handlePageChange = (page) => {
if (page >= 1 && page <= totalPages) {
setCurrentgetActiveNode function · javascript · L19-L33 (15 LOC)src/components/ContentEditor/HeadingSelector.jsx
function getActiveNode() {
let pos = null;
HEADINGS.forEach((_, idx) => {
if (idx == 0 && isActive('paragraph')) {
pos = 0;
}
if (idx > 0 && isActive('heading', {level: idx })) {
pos = idx;
}
})
return pos;
}onValueChange function · javascript · L35-L41 (7 LOC)src/components/ContentEditor/HeadingSelector.jsx
function onValueChange(value) {
if (value == 0) {
setNode('paragraph');
} else {
setNode('heading', { level: value });
}
}onInputChange function · javascript · L9-L17 (9 LOC)src/components/ContentEditor/ImageInputButton.jsx
function onInputChange() {
const file = input.current.files[0];
const reader = new FileReader()
reader.readAsDataURL(file)
reader.onload = () => {
onChange(reader.result);
input.current.value = null;
}
}Repobility · code-quality intelligence · https://repobility.com
GenerateAIImageButton function · javascript · L4-L55 (52 LOC)src/components/GenerateAIImageButtton.jsx
export default function GenerateAIImageButton({ articleId, simplifiedText, onImageGenerated }) {
const [loading, setLoading] = useState(false);
async function handleGenerate() {
if (!simplifiedText || simplifiedText.trim().length < 10) {
alert("Simplified text is required before generating an image.");
return;
}
setLoading(true);
try {
const res = await fetch("/api/articles/generate-ai-image", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
articleId,
simplifiedText,
}),
});
const data = await res.json();
if (!data.success) {
alert("Failed to generate AI image.");
setLoading(false);
return;
}
// Call parent function → update UI
onImageGeneratedhandleGenerate function · javascript · L7-L42 (36 LOC)src/components/GenerateAIImageButtton.jsx
async function handleGenerate() {
if (!simplifiedText || simplifiedText.trim().length < 10) {
alert("Simplified text is required before generating an image.");
return;
}
setLoading(true);
try {
const res = await fetch("/api/articles/generate-ai-image", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
articleId,
simplifiedText,
}),
});
const data = await res.json();
if (!data.success) {
alert("Failed to generate AI image.");
setLoading(false);
return;
}
// Call parent function → update UI
onImageGenerated(data.imageUrl);
} catch (err) {
console.error("Error generating AI image:", err);
alert("An error occurred.");
HomeServiceBanner function · javascript · L6-L26 (21 LOC)src/components/HomeServiceBanner/HomeServiceBanner.jsx
function HomeServiceBanner() {
useEffect(() => {
document.documentElement.style.setProperty('--cta-background', `url(/assets/${tenant.pathName}/home/${tenant.homeExploreAllBG})`);
}, []);
return (
<div className={`service-banner ${tenant.shortName === "HS" || tenant.shortName === "CF" || tenant.shortName === "Vitiligo" || tenant.shortName === "Canavan" || tenant.shortName === "Progeria" || tenant.shortName === "Huntington's" || tenant.shortName === "Rett" || tenant.shortName === "RYR1" || tenant.shortName === "ALS" || tenant.shortName === "NF" || tenant.shortName === "Asherman's" || tenant.shortName === "Aicardi" || tenant.shortName === "TS" || tenant.shortName === "RUNX1" ? "background-alt" : ""}`}>
<div className="service-banner__content">
<h2 className={`heading-quaternary ${tenant.shortName === "ALS" ? "invisible" : ""}`}>
{tenant.text_exploreAllTitle}{" "}
</h2>
<p classNamNavbar function · javascript · L11-L203 (193 LOC)src/components/Navbar/Navbar.jsx
export default function Navbar() {
const { user, isAdmin, role } = useAuthStore();
const { logout } = useAuth();
const [navbarOpen, setNavbarOpen] = useState(false);
const toggleNavbar = () => setNavbarOpen(!navbarOpen);
const navbrand = `/assets/${tenant.pathName}/${tenant.logoWithText}`;
return (
<nav className={`navbar ${tenant.shortName === "HS" ? "hs-mode" : tenant.shortName === "RUNX1" ? "runx1-mode" : ""}`}>
<div className="navbar-inner boxed padding">
{/* Left logo */}
<Link href="/" className="navbrand">
<Image
width={100}
height={50}
src={navbrand}
alt="Logo"
className="navbrand-img"
/>
</Link>
{/* Main nav */}
<ul className="nav-links">
<li>
<Link hrThemeProvider function · javascript · L6-L20 (15 LOC)src/components/ThemeProvider/ThemeProvider.jsx
export default function ThemeProvider({ children }) {
useEffect(() => {
// Set CSS variables based on tenant theme
document.documentElement.style.setProperty('--color-primary', tenant.theme.primary);
document.documentElement.style.setProperty('--color-primary-dark', tenant.theme.primaryDark);
document.documentElement.style.setProperty('--color-light-grey', tenant.theme.lightGrey);
document.documentElement.style.setProperty('--color-text', tenant.theme.text);
document.documentElement.style.setProperty('--color-background', tenant.theme.background);
document.documentElement.style.setProperty('--color-contactUsColor', tenant.theme.contactUsColor);
document.documentElement.style.setProperty('--color-author-text-color', tenant.theme.authorTextColor);
document.documentElement.style.setProperty('--color-footer-bg', tenant.theme.footerBGColor);
}, []);
return children;
} TrialCard function · javascript · L22-L75 (54 LOC)src/components/TrialCard/TrialCard.jsx
export default function TrialCard({ trial }) {
const ageLabel = formatAge(trial.min_age, trial.max_age);
return (
<article className="trial-card article-card">
<div className="trial-card__content">
{/* TITLE */}
<h3 className="trial-card__title">
{trial.short_title || "Clinical Trial"}
</h3>
{/* LOCATION */}
{Array.isArray(trial.locations) && trial.locations.length > 0 && (
<div className="trial-card__location">
<MapPin size={14} />
<span>
{trial.locations.length > 1
? "Multiple Locations"
: [trial.locations[0]?.city, trial.locations[0]?.state]
.filter(Boolean)
.join(", ")}
</span>
</div>
)}
{/* SUMMARY */}
<p className="trial-card__summary">{truncate(trial.ai_summary)}</p>
{/* TRIAL DETAILS LABEL */}
<div className="trial-card__details-labisBadAIText function · javascript · L8-L24 (17 LOC)src/components/TrialDetailQuestions/TrialDetailQuestions.jsx
function isBadAIText(text) {
if (!text || !text.trim()) return true;
const normalized = text.toLowerCase().trim();
// ONLY truly broken AI responses
const hardFailures = [
"please paste",
"if you share",
"i can explain",
"i can summarize",
"not enough information provided",
"the text you shared",
];
return hardFailures.some((p) => normalized.includes(p));
}renderContent function · javascript · L28-L86 (59 LOC)src/components/TrialDetailQuestions/TrialDetailQuestions.jsx
function renderContent(text, fallback, isManual = false) {
if (!isManual && isBadAIText(text)) {
return <p className="trial-paragraph">{fallback}</p>;
}
const cleaned = text
.replace(/###/g, "")
.replace(/##/g, "")
.replace(/\*\*/g, "")
.replace(/---/g, "")
.trim();
const lines = cleaned
.split(/\n{1,}/)
.map((l) => l.trim())
.filter(Boolean);
const items = [];
lines.forEach((line, i) => {
const lower = line.toLowerCase();
if (
lower.includes("who may") ||
lower.includes("who may be able") ||
lower.includes("who cannot") ||
lower.includes("who may not")
) {
items.push(
<h4 key={`h-${i}`} className="trial-subheading">
{line}
</h4>,
);
return;
}
if (line.startsWith("- ") || line.startsWith("• ")) {
items.push(
<li key={`li-${i}`} className="trial-list-item">
{line.replace(/^[-•]\s*/, "")}
</li>,
);
return;Powered by Repobility — scan your code at https://repobility.com
TrialDetailQuestions function · javascript · L90-L183 (94 LOC)src/components/TrialDetailQuestions/TrialDetailQuestions.jsx
export default function TrialDetailQuestions({ trial }) {
const [openIndex, setOpenIndex] = useState(null);
if (!trial) return null;
const sections = [
{
title: "What is the purpose of this study?",
text: trial.ai_purpose_manual || trial.ai_purpose,
isManual: !!trial.ai_purpose_manual,
fallback:
"The purpose of this study is being reviewed by the research team.",
},
{
title: "What treatments are being tested?",
text: trial.ai_treatments_manual || trial.ai_treatments,
isManual: !!trial.ai_treatments_manual,
fallback:
"The study team will explain what treatment or approach is being studied.",
},
{
title: "Is there past research on this treatment?",
text: trial.ai_prior_research_manual || trial.ai_prior_research,
isManual: !!trial.ai_prior_research_manual,
fallback:
"There is limited publicly available information about prior research for this treatment.",
},
TrialsListPaginated function · javascript · L16-L193 (178 LOC)src/components/TrialsListPaginated/TrialsListPaginated.jsx
export default function TrialsListPaginated({
trials = [],
trialsPerPage = 6,
loading = false,
error = false,
}) {
const [currentPage, setCurrentPage] = useState(1);
const [isMobile, setIsMobile] = useState(false);
/* ---------- RESPONSIVE ---------- */
useEffect(() => {
const handleResize = () => setIsMobile(window.innerWidth <= 768);
handleResize();
window.addEventListener("resize", handleResize);
return () => window.removeEventListener("resize", handleResize);
}, []);
const totalPages = Math.max(1, Math.ceil(trials.length / trialsPerPage));
useEffect(() => {
if (currentPage > totalPages) setCurrentPage(totalPages);
}, [trials.length, totalPages, currentPage]);
const selectedTrials = trials.slice(
(currentPage - 1) * trialsPerPage,
currentPage * trialsPerPage
);
const handlePageChange = (page) => {
if (page >= 1 && page <= totalPages) {
setCurrentPage(page);
window.scrollTo({ top: 0, behavior: "smooth" });Skeleton function · javascript · L3-L15 (13 LOC)src/components/ui/skeleton.jsx
function Skeleton({
className,
...props
}) {
return (
(<div
className={cn(
"animate-pulse rounded-md bg-neutral-900/10 dark:bg-neutral-50/10",
className
)}
{...props} />)
);
}