SPB Git

spb/spboucher.ai Public

spboucher.ai — personal website of Simon-Pierre Boucher.

TypeScript 93.4% HTML 5.5% CSS 1%
22.2 KB · 650 lines tsx
Raw Blame History
1/*2  page.tsx3  spboucher.ai Web4  Author: Simon-Pierre Boucher5  Mail: contact@spboucher.ai6*/78import type { Metadata } from "next";9import type { LucideIcon } from "lucide-react";10import {11  BadgeCheck,12  BookOpen,13  FileText,14  Github,15  Library,16  NotebookPen,17  PencilLine,18  Presentation,19  School,20  Sigma,21  Terminal,22  Users,23  Wrench,24} from "lucide-react";2526import { Badge } from "@/components/ui/badge";27import {28  Card,29  CardContent,30  CardDescription,31  CardHeader,32  CardTitle,33} from "@/components/ui/card";34import { PillLink } from "@/components/pill-link";35import { Reveal } from "@/components/reveal";36import { SectionHeading } from "@/components/section-heading";3738export const metadata: Metadata = {39  title: "Teaching",40  description:41    "Courses taught by Simon-Pierre Boucher at Université Laval — capital markets, financial econometrics, financial management, and financial theory.",42};4344const UQO_REPO = "https://git.spboucher.ai/uqo_cours_public";45const UQO_RAW =46  "https://raw.githubusercontent.com/spboucher-ai/UQO_COURS_PUBLIC/main";4748const imm1033Slides = [49  "seance01_introduction",50  "seance02_cadre_conceptuel",51  "seance03_evaluation_terrain",52  "seance04_analyse_terrain",53  "seance05_reproduction_remplacement",54  "seance06_methodes_estimation",55  "seance07_couts_directs",56  "seance08_couts_indirects",57  "seance09_concepts_depreciation",58  "seance10_depreciation_physique",59  "seance11_depreciation_fonctionnelle",60  "seance12_depreciation_economique",61  "seance13_applications_specialisees",62  "seance14_synthese_revision",63];6465interface UqoCourse {66  code: string;67  title: string;68  description: string;69  dir: string;70  slides: { label: string; file: string; topic?: string }[];71  tps: { label: string; file: string }[];72}7374const uqoCourses: UqoCourse[] = [75  {76    code: "IMM1003",77    title: "Éléments d'évaluation immobilière",78    description:79      "Foundations of real-estate appraisal — market analysis, comparison and income methods.",80    dir: "IMM1003-20_Elements_evaluation_immobiliere",81    slides: Array.from({ length: 14 }, (_, i) => {82      const n = String(i + 1).padStart(2, "0");83      return { label: n, file: `02_Slides/pdf/seance${n}.pdf` };84    }),85    tps: [86      {87        label: "TP1 — Tableau de bord du marché",88        file: "03_Travaux_pratiques/TP1_Tableau_de_bord_du_marche/enonce/IMM1003-20_TP1_enonce.pdf",89      },90      {91        label: "TP2 — Méthode de comparaison",92        file: "03_Travaux_pratiques/TP2_Methode_de_comparaison/enonce/IMM1003-20_TP2_enonce.pdf",93      },94      {95        label: "TP3 — Méthode du revenu",96        file: "03_Travaux_pratiques/TP3_Methode_du_revenu/enonce/IMM1003-20_TP3_enonce.pdf",97      },98    ],99  },100  {101    code: "IMM1033",102    title: "Méthodes du coût",103    description:104      "Cost approach to valuation — land value, replacement cost, and depreciation analysis.",105    dir: "IMM1033-20_Methodes_du_cout",106    slides: imm1033Slides.map((name, i) => ({107      label: String(i + 1).padStart(2, "0"),108      file: `02_Slides/pdf/${name}.pdf`,109      topic: name.slice(9).replace(/_/g, " "),110    })),111    tps: [112      {113        label: "TP1 — Évaluation d'un terrain",114        file: "03_Travaux_pratiques/TP1_Evaluation_d_un_terrain/enonce/IMM1033-20_TP1_enonce.pdf",115      },116      {117        label: "TP2 — Bordereau de coût neuf",118        file: "03_Travaux_pratiques/TP2_Bordereau_de_cout_neuf/enonce/IMM1033-20_TP2_enonce.pdf",119      },120      {121        label: "TP3 — Ventilation de la dépréciation",122        file: "03_Travaux_pratiques/TP3_Ventilation_de_la_depreciation/enonce/IMM1033-20_TP3_enonce.pdf",123      },124    ],125  },126];127128const GH_RAW = "https://raw.githubusercontent.com/spboucher-ai";129130interface MaterialGroup {131  title: string;132  kind: "pills" | "list";133  icon: LucideIcon;134  links: { label: string; file: string; topic?: string }[];135}136137interface UlavalCourse {138  code: string;139  title: string;140  term: string;141  repoName: string;142  description: string;143  groups: MaterialGroup[];144}145146const ulavalCourses: UlavalCourse[] = [147  {148    code: "GSF-3100",149    title: "Capital Markets (Marché des capitaux)",150    term: "Undergraduate · F2021–W2023",151    repoName: "gsf3100",152    description:153      "Fixed income and capital markets — LaTeX Beamer slides for every section of the course.",154    groups: [155      {156        title: "Slides — 13 section decks (PDF)",157        kind: "pills",158        icon: Presentation,159        links: [160          { label: "01", file: "Section 1/GSF3100_S01.pdf" },161          { label: "02", file: "Section 2/GSF3100_S02.pdf" },162          { label: "03", file: "Section 3/GSF3100_S03.pdf" },163          { label: "04", file: "Section 4/GSF3100_S04.pdf" },164          { label: "05", file: "Section 5/GSF3100_S05.pdf" },165          { label: "06", file: "Section 6/GSF3100_S6.pdf" },166          { label: "07", file: "Section 7/GSF3100_S7.pdf" },167          { label: "08", file: "Section 8/GSF3100_S08.pdf" },168          { label: "9a", file: "Section 9/a/GSF3100_S09a.pdf" },169          { label: "9b", file: "Section 9/b/GSF3100_S09b.pdf" },170          { label: "9c", file: "Section 9/c/GSF3100_S09c.pdf" },171          { label: "10a", file: "Section 10/a/GSF3100_S10a.pdf" },172          { label: "10b", file: "Section 10/b/GSF3100_S10b.pdf" },173        ],174      },175    ],176  },177  {178    code: "GSF-6053",179    title: "Financial Econometrics I",180    term: "Graduate · W2022",181    repoName: "gsf6053",182    description:183      "OLS, MLE, hypothesis testing, and time-series econometrics — session slides plus Stata lab sessions.",184    groups: [185      {186        title: "Slides — sessions 2–12 (PDF)",187        kind: "pills",188        icon: Presentation,189        links: Array.from({ length: 11 }, (_, i) => {190          const n = i + 2;191          return {192            label: String(n).padStart(2, "0"),193            file: `Séance ${n}/GSF6053_S${n}.pdf`,194          };195        }),196      },197      {198        title: "Stata labs (PDF)",199        kind: "list",200        icon: Terminal,201        links: [202          { label: "Stata session 02", file: "STATA_S02/GSF6053_STATA_02.pdf" },203          { label: "Stata session 03", file: "STATA_S03/GSF6053_STATA_03.pdf" },204        ],205      },206    ],207  },208  {209    code: "GSF-6053",210    title: "Financial Econometrics I",211    term: "Graduate · W2025",212    repoName: "gsf6053_h25",213    description:214      "Full W2025 edition — lecture slides, typed lecture notes, formal proofs, and 14 exercise sets with complete solutions.",215    groups: [216      {217        title: "Lecture slides (PDF)",218        kind: "list",219        icon: Presentation,220        links: [221          {222            label: "S1 — Introduction",223            file: "PDF/GSF6053_H25_Séance1_Introduction.pdf",224          },225          {226            label: "S1 — Statistics review",227            file: "PDF/GSF6053_H25_Séance1_Révision.pdf",228          },229          { label: "S1 — OLS (MCO)", file: "PDF/GSF6053_H25_Séance1_MCO.pdf" },230          {231            label: "S2 — Maximum likelihood (MLE)",232            file: "PDF/GSF6053_H25_Séance2_MLE.pdf",233          },234          {235            label: "S3 — Hypothesis tests & ANOVA",236            file: "PDF/GS6053_H25_Séance3_Tests_ANOVA.pdf",237          },238          {239            label: "S4 — Extensions of the linear model",240            file: "PDF/GSF6053_H25_Séance4_Extensions_Modèle_Linéaire.pdf",241          },242          {243            label: "S5 — Heteroskedasticity",244            file: "PDF/GSF6053_H25_Séance5_Hétéroscédasticité.pdf",245          },246          {247            label: "S6 — Autocorrelation",248            file: "PDF/GSF6053_H25_Séance6_Autocorrélation.pdf",249          },250        ],251      },252      {253        title: "Lecture notes (PDF)",254        kind: "list",255        icon: NotebookPen,256        links: [257          { label: "Introduction", file: "PDF/GSF6053_H25_NOTE_INTRO.pdf" },258          {259            label: "Prerequisites",260            file: "PDF/GSF6053_H25_NOTE_PRÉALABLE.pdf",261          },262          { label: "OLS (MCO)", file: "PDF/GSF6053_H25_NOTE_MCO.pdf" },263          { label: "MLE", file: "PDF/GSF6053_H25_NOTE_MLE.pdf" },264          {265            label: "Hypothesis testing",266            file: "PDF/GSF6053_H25_NOTE_Test_hypothèse.pdf",267          },268          { label: "ANOVA", file: "PDF/GSF6053_H25_NOTE_ANOVA.pdf" },269          { label: "GLS (MCG)", file: "PDF/GSF6053_H25_NOTE_MCG.pdf" },270          {271            label: "Heteroskedasticity",272            file: "PDF/GSF6053_H25_NOTE_HETEROSCEDASTICITE.pdf",273          },274          { label: "White test", file: "PDF/GSF6053_H25_NOTE_WHITE_TEST.pdf" },275          {276            label: "Breusch–Pagan test",277            file: "PDF/GSF6053_H25_Note_Breusch_Pagan.pdf",278          },279          {280            label: "Autocorrelation",281            file: "PDF/GSF6053_H25_NOTE_AUTOCORÉLATION.pdf",282          },283        ],284      },285      {286        title: "Formal proofs (PDF)",287        kind: "list",288        icon: Sigma,289        links: [290          {291            label: "OLS — summation form",292            file: "PDF/GSF6053_H25_preuve_MCO_sommation.pdf",293          },294          {295            label: "OLS — matrix form",296            file: "PDF/GSF6053_H25_preuve_MCO_matriciel.pdf",297          },298          { label: "GLS", file: "PDF/GSF6053_H25_preuve_MCG.pdf" },299          { label: "MLE", file: "PDF/GSF6053_H25_preuve_MLE.pdf" },300          {301            label: "Cramér–Rao bound",302            file: "PDF/GSF6053_H25_preuve_cramer_rao.pdf",303          },304          {305            label: "Cochrane–Orcutt",306            file: "PDF/GSF6053_H25_preuve_cochrane_orcutt.pdf",307          },308          {309            label: "Prais–Winsten",310            file: "PDF/GSF6053_H25_preuve_prais_winsten.pdf",311          },312        ],313      },314      {315        title: "Exercise sets 1–14 (PDF)",316        kind: "pills",317        icon: PencilLine,318        links: Array.from({ length: 14 }, (_, i) => {319          const n = String(i + 1).padStart(3, "0");320          return {321            label: String(i + 1).padStart(2, "0"),322            file: `PDF/GSF6053_H25_EXO_${n}.pdf`,323          };324        }),325      },326      {327        title: "Solutions 1–14 (PDF)",328        kind: "pills",329        icon: BadgeCheck,330        links: Array.from({ length: 14 }, (_, i) => {331          const n = String(i + 1).padStart(3, "0");332          return {333            label: String(i + 1).padStart(2, "0"),334            file: `PDF/GSF6053_H25_SOL_${n}.pdf`,335          };336        }),337      },338    ],339  },340];341342const courses = [343  {344    code: "GSF-3100",345    title: "Capital Markets",346    level: "Undergraduate",347    terms: "F2021, W2021, F2022, W2023",348  },349  {350    code: "GSF-6053",351    title: "Financial Econometrics I",352    level: "Graduate",353    terms: "W2022, W2025",354  },355  {356    code: "GSF-1500",357    title: "Financial Management",358    level: "Undergraduate",359    terms: "S2022",360  },361  {362    code: "GSF-6028",363    title: "Financial Theory",364    level: "Graduate",365    terms: "W2024",366  },367];368369const taCourses = [370  { code: "GSF-2101", title: "Portfolio Management" },371  { code: "GSF-2102", title: "Corporate Finance" },372  { code: "GSF-6008", title: "Corporate Finance" },373  { code: "GSF-6025", title: "Financial Strategies & Policies I" },374  { code: "GSF-6028", title: "Financial Theory" },375];376377export default function TeachingPage() {378  return (379    <div className="mx-auto max-w-5xl px-4 py-16 sm:px-6">380      <Reveal>381        <SectionHeading382          as="h1"383          eyebrow="Courses"384          title="Teaching"385          icon={BookOpen}386          description="Professor at Université du Québec en Outaouais (UQO), previously Lecturer (2021–Present) and Teaching Assistant (2018–2021) at Université Laval."387        />388      </Reveal>389390      {/* UQO courses with material */}391      <section className="mt-12">392        <Reveal>393          <SectionHeading394            title="Professor — Université du Québec en Outaouais (UQO)"395            icon={School}396            description="Complete course material — Beamer slides, practical assignments with Excel templates, and a Québec real-estate market report — is openly available on GitHub."397          />398        </Reveal>399        <div className="mt-4 grid gap-4 sm:grid-cols-2">400          {uqoCourses.map((course, i) => (401            <Reveal key={course.code} delay={i * 0.08} className="h-full">402              <Card className="flex h-full flex-col">403                <CardHeader>404                  <Badge className="w-fit font-mono">{course.code}</Badge>405                  <CardTitle className="text-lg leading-snug">406                    {course.title}407                  </CardTitle>408                  <CardDescription>{course.description}</CardDescription>409                </CardHeader>410                <CardContent className="flex flex-1 flex-col gap-4">411                  <div>412                    <PillLink413                      href={`${UQO_RAW}/${course.dir}/01_Plan_de_cours/plan_de_cours.pdf`}414                      icon={FileText}415                    >416                      Course plan (PDF)417                    </PillLink>418                  </div>419420                  <div>421                    <p className="inline-flex items-center gap-2 text-sm font-medium">422                      <Presentation423                        className="h-4 w-4 text-primary"424                        aria-hidden="true"425                      />426                      Slides — 14 sessions (PDF)427                    </p>428                    <div className="mt-2 flex flex-wrap gap-1.5">429                      {course.slides.map((slide) => (430                        <a431                          key={slide.file}432                          href={`${UQO_RAW}/${course.dir}/${slide.file}`}433                          target="_blank"434                          rel="noopener noreferrer"435                          title={slide.topic}436                          aria-label={`Session ${slide.label}${slide.topic ? ` — ${slide.topic}` : ""} (PDF)`}437                          className="inline-flex h-8 w-9 items-center justify-center rounded-full border border-border/70 bg-card/70 text-xs font-medium text-muted-foreground shadow-sm transition-all hover:-translate-y-px hover:border-primary/40 hover:bg-primary/10 hover:text-primary"438                        >439                          {slide.label}440                        </a>441                      ))}442                    </div>443                  </div>444445                  <div>446                    <p className="inline-flex items-center gap-2 text-sm font-medium">447                      <Wrench448                        className="h-4 w-4 text-primary"449                        aria-hidden="true"450                      />451                      Practical assignments (PDF)452                    </p>453                    <div className="mt-2 flex flex-wrap gap-1.5">454                      {course.tps.map((tp) => (455                        <PillLink456                          key={tp.file}457                          href={`${UQO_RAW}/${course.dir}/${tp.file}`}458                        >459                          {tp.label}460                        </PillLink>461                      ))}462                    </div>463                  </div>464                </CardContent>465              </Card>466            </Reveal>467          ))}468        </div>469        <Reveal className="mt-4">470          <div className="flex flex-wrap gap-2">471            <PillLink472              href={`${UQO_RAW}/Rapport_Immobilier_Quebec/rapport_immobilier_quebec.pdf`}473              icon={FileText}474            >475              Québec real-estate market report (PDF)476            </PillLink>477            <PillLink href={UQO_REPO} icon={Github}>478              Full course repository479            </PillLink>480          </div>481        </Reveal>482      </section>483484      {/* Lecturer */}485      <section className="mt-12">486        <Reveal>487          <SectionHeading488            title="Lecturer — Université Laval (2021–Present)"489            icon={BookOpen}490          />491          <Card className="mt-4 overflow-x-auto">492            <CardContent className="p-0">493              <table className="w-full text-sm">494                <thead>495                  <tr className="border-b border-border text-left">496                    <th scope="col" className="px-4 py-3 font-medium">497                      Code498                    </th>499                    <th scope="col" className="px-4 py-3 font-medium">500                      Course501                    </th>502                    <th scope="col" className="px-4 py-3 font-medium">503                      Level504                    </th>505                    <th scope="col" className="px-4 py-3 font-medium">506                      Terms507                    </th>508                  </tr>509                </thead>510                <tbody>511                  {courses.map((course) => (512                    <tr513                      key={`${course.code}-${course.terms}`}514                      className="border-b border-border last:border-0"515                    >516                      <td className="px-4 py-3 font-mono text-xs">517                        {course.code}518                      </td>519                      <td className="px-4 py-3 font-medium">{course.title}</td>520                      <td className="px-4 py-3">521                        <Badge522                          variant={523                            course.level === "Graduate"524                              ? "default"525                              : "secondary"526                          }527                        >528                          {course.level}529                        </Badge>530                      </td>531                      <td className="px-4 py-3 text-muted-foreground">532                        {course.terms}533                      </td>534                    </tr>535                  ))}536                </tbody>537              </table>538            </CardContent>539          </Card>540        </Reveal>541542        <Reveal className="mt-8">543          <SectionHeading544            as="h3"545            title="Course Material — Université Laval"546            icon={Library}547            description="Complete material from courses previously taught at Université Laval — LaTeX Beamer slides, lecture notes, formal proofs, Stata labs, and exercise sets with solutions — openly available on GitHub."548          />549        </Reveal>550        <div className="mt-4 space-y-4">551          {ulavalCourses.map((course, i) => (552            <Reveal key={course.repoName} delay={i * 0.08}>553              <Card>554                <CardHeader>555                  <div className="flex flex-wrap items-center gap-2">556                    <Badge className="w-fit font-mono">{course.code}</Badge>557                    <Badge variant="secondary" className="w-fit">558                      {course.term}559                    </Badge>560                  </div>561                  <CardTitle className="text-lg leading-snug">562                    {course.title}563                  </CardTitle>564                  <CardDescription>{course.description}</CardDescription>565                </CardHeader>566                <CardContent className="flex flex-col gap-4">567                  {course.groups.map((group) => (568                    <div key={group.title}>569                      <p className="inline-flex items-center gap-2 text-sm font-medium">570                        <group.icon571                          className="h-4 w-4 text-primary"572                          aria-hidden="true"573                        />574                        {group.title}575                      </p>576                      {group.kind === "pills" ? (577                        <div className="mt-2 flex flex-wrap gap-1.5">578                          {group.links.map((link) => (579                            <a580                              key={link.file}581                              href={encodeURI(582                                `${GH_RAW}/${course.repoName}/main/${link.file}`,583                              )}584                              target="_blank"585                              rel="noopener noreferrer"586                              aria-label={`${course.code} — ${group.title} — ${link.label} (PDF)`}587                              className="inline-flex h-8 min-w-9 items-center justify-center rounded-full border border-border/70 bg-card/70 px-2 text-xs font-medium text-muted-foreground shadow-sm transition-all hover:-translate-y-px hover:border-primary/40 hover:bg-primary/10 hover:text-primary"588                            >589                              {link.label}590                            </a>591                          ))}592                        </div>593                      ) : (594                        <div className="mt-2 flex flex-wrap gap-1.5">595                          {group.links.map((link) => (596                            <PillLink597                              key={link.file}598                              href={encodeURI(599                                `${GH_RAW}/${course.repoName}/main/${link.file}`,600                              )}601                            >602                              {link.label}603                            </PillLink>604                          ))}605                        </div>606                      )}607                    </div>608                  ))}609                  <div>610                    <PillLink611                      href={`https://git.spboucher.ai/${course.repoName}`}612                      icon={Github}613                    >614                      Full course repository615                    </PillLink>616                  </div>617                </CardContent>618              </Card>619            </Reveal>620          ))}621        </div>622      </section>623624      {/* Teaching assistant */}625      <section className="mt-12">626        <Reveal>627          <SectionHeading628            title="Teaching Assistant — Université Laval (2018–2021)"629            icon={Users}630          />631        </Reveal>632        <div className="mt-4 grid gap-4 sm:grid-cols-2 lg:grid-cols-3">633          {taCourses.map((course, i) => (634            <Reveal key={`${course.code}-${course.title}`} delay={i * 0.06}>635              <Card className="h-full">636                <CardHeader>637                  <Badge variant="outline" className="w-fit font-mono">638                    {course.code}639                  </Badge>640                  <CardTitle className="text-base">{course.title}</CardTitle>641                </CardHeader>642              </Card>643            </Reveal>644          ))}645        </div>646      </section>647    </div>648  );649}650