Skip to content

Commit

Permalink
feat: pathology pages
Browse files Browse the repository at this point in the history
Signed-off-by: Maud Royer <hello@maudroyer.fr>
  • Loading branch information
jillro committed Oct 18, 2024
1 parent 975752e commit 2f62108
Show file tree
Hide file tree
Showing 10 changed files with 317 additions and 83 deletions.
76 changes: 76 additions & 0 deletions src/app/(container)/parcourir/pathologies/[letter]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { fr } from "@codegouvfr/react-dsfr";
import Link from "next/link";
import { Patho } from "@/db/pdbmMySQL/types";
import { pdbmMySQL } from "@/db/pdbmMySQL";
import { notFound } from "next/navigation";

export async function generateStaticParams(): Promise<{ letter: string }[]> {
return pdbmMySQL
.selectFrom("Patho")
.select(({ fn, val }) =>
fn<string>("substr", ["NomPatho", val(1), val(1)]).as("letter"),
)
.orderBy("letter")
.groupBy("letter")
.execute();
}

async function getPathologyPage(letter: string): Promise<Patho[]> {
return pdbmMySQL
.selectFrom("Patho")
.selectAll()
.where("NomPatho", "like", `${letter}%`)
.execute();
}

async function getLetters(): Promise<string[]> {
return (await generateStaticParams()).map((r) => r.letter);
}

export default async function Page({
params: { letter },
}: {
params: { letter: string };
}) {
const letters = await getLetters();
const pathos = await getPathologyPage(letter);
if (!pathos || !pathos.length) return notFound();

return (
<div className={fr.cx("fr-grid-row")}>
<div className={fr.cx("fr-col-md-8")}>
<h1 className={fr.cx("fr-h1", "fr-mb-8w")}>Liste des pathologies</h1>
<p className={fr.cx("fr-text--lg")}>
{letters.map((a) => (
<>
<Link
href={`/parcourir/pathologies/${a}`}
key={a}
className={fr.cx(
"fr-link",
"fr-link--lg",
"fr-mr-3w",
"fr-mb-3w",
)}
>
{a}
</Link>{" "}
</>
))}
</p>
<ul className={fr.cx("fr-raw-list")}>
{pathos.map((patho, i) => (
<li key={i} className={fr.cx("fr-mb-1v")}>
<Link
href={`/pathologie/${patho.codePatho}`}
className={fr.cx("fr-link")}
>
{patho.NomPatho}
</Link>
</li>
))}
</ul>
</div>
</div>
);
}
71 changes: 71 additions & 0 deletions src/app/(container)/pathologie/[code]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { pdbmMySQL } from "@/db/pdbmMySQL";
import DefinitionBanner from "@/components/DefinitionBanner";
import { notFound } from "next/navigation";
import { Patho, Specialite } from "@/db/pdbmMySQL/types";
import { groupSpecialites } from "@/displayUtils";
import liste_CIS_MVP from "@/liste_CIS_MVP.json";
import { fr } from "@codegouvfr/react-dsfr";
import { MedGroupSpecListList } from "@/components/MedGroupSpecList";
import Breadcrumb from "@codegouvfr/react-dsfr/Breadcrumb";

export async function generateStaticParams(): Promise<{ code: string }[]> {
return pdbmMySQL.selectFrom("Patho").select("codePatho as code").execute();
}

async function getPatho(code: string): Promise<Patho> {
const patho = await pdbmMySQL
.selectFrom("Patho")
.selectAll()
.where("codePatho", "=", code)
.executeTakeFirst();

if (!patho) notFound();

return patho;
}

async function getSpecialite(code: string): Promise<Specialite[]> {
return pdbmMySQL
.selectFrom("Specialite")
.selectAll("Specialite")
.leftJoin("Spec_Patho", "Specialite.SpecId", "Spec_Patho.SpecId")
.where("Spec_Patho.codePatho", "=", code)
.where("Specialite.SpecId", "in", liste_CIS_MVP)
.execute();
}

export default async function Page({
params: { code },
}: {
params: { code: string };
}) {
const patho = await getPatho(code);
const specialites = await getSpecialite(code);
const medicaments = groupSpecialites(specialites);
return (
<>
<Breadcrumb
segments={[
{ label: "Accueil", linkProps: { href: "/" } },
{
label: "Listes des pathologies",
linkProps: {
href: `/parcourir/pathologies/${patho.NomPatho.slice(0, 1)}`,
},
},
]}
currentPageLabel={patho.NomPatho}
/>
<DefinitionBanner
type="Pathologie"
title={patho.NomPatho}
definition="Définition de la pathologie"
/>

<h2 className={fr.cx("fr-h6", "fr-mt-4w")}>
{medicaments.length} médicaments traitant la pathologie « anxiété »
</h2>
<MedGroupSpecListList items={medicaments} />
</>
);
}
86 changes: 7 additions & 79 deletions src/app/(container)/rechercher/page.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,13 @@
import path from "node:path";
import { readFileSync } from "node:fs";
import { Fragment } from "react";
import { parse as csvParse } from "csv-parse/sync";
import Link from "next/link";
import { fr } from "@codegouvfr/react-dsfr";
import Tag from "@codegouvfr/react-dsfr/Tag";
import { cx } from "@codegouvfr/react-dsfr/tools/cx";

import { Specialite, SubstanceNom } from "@/db/pdbmMySQL/types";
import { getAtcLabels } from "@/data/atc";
import { SubstanceNom } from "@/db/pdbmMySQL/types";
import { getResults } from "@/db/search";
import { formatSpecName } from "@/displayUtils";
import AutocompleteSearch from "@/components/AutocompleteSearch";

const atcData = csvParse(
readFileSync(
path.join(process.cwd(), "src", "data", "CIS-ATC_2024-04-07.csv"),
),
) as string[][];
function getAtc(CIS: string) {
const atc = atcData.find((row) => row[0] === CIS);
return atc ? atc[1] : null;
}
import MedGroupSpecList from "@/components/MedGroupSpecList";

const SubstanceResult = ({ item }: { item: SubstanceNom }) => (
<li className={fr.cx("fr-mb-3w")}>
Expand All @@ -40,68 +26,6 @@ const SubstanceResult = ({ item }: { item: SubstanceNom }) => (
</li>
);

const MedicamentGroupResult = async ({
item,
}: {
item: { groupName: string; specialites: Specialite[] };
}) => {
const atc = getAtc(item.specialites[0].SpecId);
const atcLabels = atc ? await getAtcLabels(atc) : null;
const [, subClass, substance] = atcLabels ? atcLabels : [null, null, null];
return (
<li className={fr.cx("fr-mb-3w")}>
<div>
<div className={fr.cx("fr-mb-1v")}>
<span className={fr.cx("fr-text--md", "fr-text--bold")}>
{formatSpecName(item.groupName)}
</span>
</div>
<div className={fr.cx("fr-grid-row")} style={{ flexWrap: "nowrap" }}>
<div className={"fr-mr-1w"}>
<i className={cx("fr-icon--custom-pill", fr.cx("fr-icon--sm"))} />
</div>
<ul className={fr.cx("fr-tags-group", "fr-mb-n1v")}>
{subClass && (
<Tag
small
nativeButtonProps={{
className: fr.cx("fr-tag--yellow-tournesol"),
}}
>
{subClass}
</Tag>
)}
{substance && (
<Tag
small
nativeButtonProps={{
className: fr.cx("fr-tag--purple-glycine"),
}}
>
{substance}
</Tag>
)}
</ul>
</div>
</div>
<ul className={fr.cx("fr-raw-list", "fr-pl-3w")}>
{item.specialites?.map((specialite, i) => (
<li key={i} className={fr.cx("fr-mb-1v")}>
<Link
href={`/medicament/${specialite.SpecId}`}
className={fr.cx("fr-text--sm", "fr-link")}
>
{formatSpecName(specialite.SpecDenom01)
.replace(`${formatSpecName(item.groupName)}, `, "")
.replace(formatSpecName(item.groupName), "")}
</Link>
</li>
))}
</ul>
</li>
);
};

export default async function Page({
searchParams,
}: {
Expand Down Expand Up @@ -132,7 +56,11 @@ export default async function Page({
{"NomLib" in result ? (
<SubstanceResult item={result} />
) : (
<MedicamentGroupResult key={index} item={result} />
<MedGroupSpecList
key={index}
medGroup={[result.groupName, result.specialites]}
className={fr.cx("fr-mb-3w")}
/>
)}
</Fragment>
))}
Expand Down
2 changes: 1 addition & 1 deletion src/app/(container)/substance/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ export default async function Page({
Médicaments contenant uniquement « {substance.NomLib} »
</h2>
<ul>
{Array.from(groupSpecialites(specialites).entries()).map(
{groupSpecialites(specialites).map(
([groupName, specialites]: [string, Specialite[]]) => (
<li key={groupName} className={"fr-mb-2w"}>
<b>{formatSpecName(groupName)}</b>
Expand Down
11 changes: 11 additions & 0 deletions src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,17 @@ export default function RootLayout({
serviceTitle="" // hack pour que la tagline soit bien affichée
serviceTagline="La référence officielle sur les données des médicaments"
quickAccessItems={[headerFooterDisplayItem]}
navigation={[
{
text: "Par ordre alphabétique",
menuLinks: [
{
text: "Toutes les pathologies",
linkProps: { href: "/parcourir/pathologies/A" },
},
],
},
]}
/>
{children}
<Footer
Expand Down
27 changes: 27 additions & 0 deletions src/components/DefinitionBanner.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { fr } from "@codegouvfr/react-dsfr";
import Badge from "@codegouvfr/react-dsfr/Badge";
import Card from "@codegouvfr/react-dsfr/Card";

export default async function DefinitionBanner({
type,
title,
definition,
}: {
type: string;
title: string;
definition: string;
}) {
return (
<div className={fr.cx("fr-grid-row")}>
<div className={fr.cx("fr-col-md-8")}>
<Badge className={fr.cx("fr-badge--purple-glycine")}>{type}</Badge>
<h1 className={fr.cx("fr-h1", "fr-mt-1w", "fr-mb-6w")}>{title}</h1>
<div className={fr.cx("fr-grid-row")}>
<div className={fr.cx("fr-col")}>
<Card title="Définition" titleAs={"h6"} desc={definition} />
</div>
</div>
</div>
</div>
);
}
Loading

0 comments on commit 2f62108

Please sign in to comment.