# Project export: How likely am I to pass?

This document was generated by HackStack to give an AI agent context about a hackathon project. Sections are labeled with their provenance; content marked as truncated was cut to keep this document small.

## Project metadata

- Hackathon: CruzHacks 2024
- Tagline: Our tool analyzes the professor, providing a comprehensive guide and understanding of each professor's teaching style, course difficulty, and overall effectiveness that is powered by ChatGPT and RMP.
- Devpost: https://devpost.com/software/how-likely-am-i-to-pass
- GitHub: https://github.com/fercevik729/howlikelyamitopass
- Demo: https://helpmepass.study/
- Result: winner (Education Hacks)
- Team: 4 GitHub contributor(s) — Furkan Ercevik (53 commits), Daniel Chang (24 commits), Jose Chavez (9 commits), Denny Au (2 commits)

## Devpost submission (written by the team)

### Inspiration

Deciding which classes to take can be challenging, with most students relying on word of mouth or platforms like Rate My Professor for guidance. But is there a more effective way for students to prepare, both generally and for specific courses? Enter "How Likely Am I to Pass?" – a tool designed to support both new and current students in excelling in their academic pursuits.

### What it does

Our platform provides a comprehensive list of courses and professors for the current quarter. Students can access detailed information about each professor, informed by reviews from fellow students. Following this, you will complete a personalized questionnaire. This questionnaire is designed to help our AI evaluate the potential challenges you might face, based on your current academic habits and situation.

### How we built it

We built it by first scraping data from all the sources that we needed to and aggregating it in a database. Then we made it accessible through API routes in our Next.js project. Next, we integrated it with our React frontend and created our Langchain prompts. Finally, we connected all parts of our full stack application and polished the frontend some more.

### Challenges we ran into

Scraping problems, Next.js quirks, React and TailwindCSS learning curve, database problems, deployment problems, and AI problems.

### Accomplishments we're proud of

There were many challenges that we faced, from setting up the database to changing minor styling bugs. The most good-feeling accomplishment was getting the API and Database server setup and connecting all of those, plus the AI portion, connected.

### What we learned

We learned a lot of React, Next.js, and Tailwind. We also learned of ways to improve our web-application along the way.

### What's next

Speeds are definitely a concern, but to have more accurate data is vital. We want to add a more personalized and detailed form for students to fill out for better prediction of their results.

## README (from the GitHub repository)

This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).

## Getting Started

First, run the development server:

```bash
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev
```

Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.

You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.

This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.

## Learn More

To learn more about Next.js, take a look at the following resources:

- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.

You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!

## Deploy on Vercel

The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.

Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.


## Detected evidence (automated analysis)

Indexed codebase: 37 recognized source files, 58 KB.
- CSS (language) — detected in the code
- JavaScript (language) — detected in the code
- LangChain (technology) — detected in the code
- Next.js (technology) — detected in the code
- Python (language) — detected in the code
- React (technology) — detected in the code
- SQL (language) — detected in the code
- Tailwind CSS (technology) — detected in the code
- TypeScript (language) — detected in the code

## Codebase structure (from repository index)

### Files (49 of 49)

```
.eslintrc.json
.gitignore
.husky/pre-commit
.prettierrc
docker-compose.yml
next.config.mjs
package.json
patches/react-wheel-of-prizes+1.0.9.patch
postcss.config.js
prisma/migrations/20240120203731_init/migration.sql
prisma/migrations/20240120225741_many_profs_many_qos/migration.sql
prisma/migrations/20240120232650_courses_unique/migration.sql
prisma/migrations/20240120234135_rm_qoid_from_profs/migration.sql
prisma/migrations/migration_lock.toml
prisma/schema.prisma
push-to-db_script.js
README.md
src/app/about/page.tsx
src/app/actions/courses.ts
src/app/api/ai/info/route.ts
src/app/api/ai/questions/route.ts
src/app/api/ai/summary/route.ts
src/app/api/course/route.ts
src/app/api/courses/route.ts
src/app/api/professor/route.ts
src/app/api/professors/route.ts
src/app/credits/page.tsx
src/app/evaluate/page.tsx
src/app/globals.css
src/app/layout.tsx
src/app/page.tsx
src/app/results/page.tsx
src/app/sample.json
src/app/skills/page.tsx
src/components/NavBar.tsx
src/components/ProfessorChoice.tsx
src/components/ProfessorStats.tsx
src/components/ResultsPercentage.tsx
src/components/SkillsComponent.tsx
src/config.ts
src/db.ts
src/lib/ai.ts
src/types/model.ts
tailwind.config.ts
tsconfig.json
webscraping/courses_scraper.py
webscraping/README.md
webscraping/requirements.txt
webscraping/souprmp.py
```

### Dependencies

- package.json: @emotion/react@^11.11.3, @emotion/styled@^11.11.0, @langchain/openai@^0.0.12, @mui/icons-material@^5.15.5, @mui/material@^5.15.5, @prisma/client@^5.8.1, @types/node@^20, @types/react@^18, @types/react-dom@^18, autoprefixer@^10.0.1, eslint@^8, eslint-config-next@14.1.0, eslint-config-prettier@^9.1.0, eslint-config-typescript@^3.0.0, husky@^8.0.3, langchain@^0.1.4, lint-staged@^15.2.0, next@^14.1.0, node-fetch@^2.7.0, patch-package@^8.0.0, postcss@^8, prettier@3.2.4, prisma@^5.8.1, react@^18, react-countup@^6.5.0, react-dom@^18, react-icons@^5.0.1, react-wheel-of-prizes@^1.0.9, tailwindcss@^3.3.0, typescript@^5, zod@^3.22.4, zod-to-json-schema@^3.22.3
- webscraping/requirements.txt: beautifulsoup4@==4.12.3, bs4@==0.0.2, certifi@==2023.11.17, charset-normalizer@==3.3.2, idna@==3.6, lxml@==5.1.0, RateMyProfessorAPI@==1.3.6, requests@==2.31.0, soupsieve@==2.5, urllib3@==2.1.0

### Recent commits (newest first)

- Final formatting
- Merge remote-tracking branch 'origin/main'
- Added default card and fixed landing page
- Merge pull request #17 from fercevik729/evaluateUITweaks
- Fixed text boxes shifting around on load
- Merge pull request #16 from fercevik729/skillsButton
- Merge remote-tracking branch 'origin/main'
- Added skeletons
- Merge branch 'main' into skillsButton
- Improved vertical spacing
- Skills page loading and better button
- fixed the styling in evaluate (#15)
- Added dynamic data for pros and cons
- Merge pull request #14 from fercevik729/evaluateSkillsIntegration
- Merge branch 'main' into evaluateSkillsIntegration
- Formatted /results
- Merged main changes
- Merged main changes, skills -> results completed
- Merge remote-tracking branch 'origin/main'
- Fixed formatting for /results

## Key source files (fetched from GitHub, selected and truncated for size)

### docker-compose.yml

```yaml
version: "3.7"

services:
  postgres:
    container_name: help-me-pass
    image: postgres
    environment:
      POSTGRES_DB: ${POSTGRES_DB}
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
    ports:
      - "5432:5432"

```

### package.json

```
{
  "name": "howlikelyamitopass",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint",
    "format": "prettier --write .",
    "prepare": "husky install",
    "postinstall": "npx patch-package"
  },
  "dependencies": {
    "@emotion/react": "^11.11.3",
    "@emotion/styled": "^11.11.0",
    "@langchain/openai": "^0.0.12",
    "@mui/icons-material": "^5.15.5",
    "@mui/material": "^5.15.5",
    "@prisma/client": "^5.8.1",
    "eslint-config-prettier": "^9.1.0",
    "eslint-config-typescript": "^3.0.0",
    "husky": "^8.0.3",
    "langchain": "^0.1.4",
    "lint-staged": "^15.2.0",
    "next": "^14.1.0",
    "node-fetch": "^2.7.0",
    "patch-package": "^8.0.0",
    "react": "^18",
    "react-countup": "^6.5.0",
    "react-dom": "^18",
    "react-icons": "^5.0.1",
    "react-wheel-of-prizes": "^1.0.9",
    "zod": "^3.22.4",
    "zod-to-json-schema": "^3.22.3"
  },
  "devDependencies": {
    "@types/node": "^20",
    "@types/react": "^18",
    "@types/react-dom": "^18",
    "autoprefixer": "^10.0.1",
    "eslint": "^8",
    "eslint-config-next": "14.1.0",
    "postcss": "^8",
    "prettier": "3.2.4",
    "prisma": "^5.8.1",
    "tailwindcss": "^3.3.0",
    "typescript": "^5"
  },
  "lint-staged": {
    "*.{ts,tsx,js,jsx}": [
      "prettier --write",
      "eslint --fix"
    ]
  },
  "overrides": {
    "react-wheel-of-prizes": {
      "react": "$react"
    }
  }
}

```

### webscraping/requirements.txt

```
beautifulsoup4==4.12.3
bs4==0.0.2
certifi==2023.11.17
charset-normalizer==3.3.2
idna==3.6
lxml==5.1.0
RateMyProfessorAPI==1.3.6
requests==2.31.0
soupsieve==2.5
urllib3==2.1.0

```

### src/app/layout.tsx

```typescript
import type { Metadata } from "next";
import "./globals.css";
import NavBar from "@/components/NavBar";
import { Inter } from "next/font/google";

const inter = Inter({ subsets: ["latin"] });

export const metadata: Metadata = {
  title: "HelpMePass",
  description: "An app to help you pass your CS classes",
};

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en">
      <body className={inter.className}>
        <NavBar />
        {children}
      </body>
    </html>
  );
}

```

### src/app/page.tsx

```typescript
"use client";
import Image from "next/image";
import { Button } from "@mui/material";
import { useEffect } from "react";
import Link from "next/link";

export default function Home() {
  useEffect(() => {
    document.body.style.overflow = "hidden";
    document.body.style.height = "100vh";
    return () => {
      document.body.style.overflow = "";
      document.body.style.height = "";
    };
  }, []);
  return (
    <main>
      <section
        id={"hero"}
        className={`flex items-center justify-center h-screen`}
      >
        <div className={"flex flex-col gap-[56px] text-white text-right"}>
          <h1 className={"text-8xl font-bold"}>How Can I Pass?</h1>
          <span className={"text-xl"}>
            The answers that CS majors are looking for.
          </span>
          <Link href={"/evaluate"} passHref>
            <Button
              style={{
                backgroundColor: "white",
                color: "black",
                padding: "12px 40px",
                borderRadius: "25px",
                opacity: 0.7,
              }}
              className={"w-fit"}
              variant={"contained"}
              color={"secondary"}
            >
              Get Started
            </Button>
          </Link>
        </div>
        <div className={"ml-left"}>
          <Image
            className={"ml-5"}
            src={"/spaceship.svg"}
            alt={"spaceship"}
            width={500}
            height={500}
          />
        </div>
      </section>
    </main>
  );
}

```

### src/app/about/page.tsx

```typescript
"use client";
import React, { useEffect } from "react";

export default function Results() {
  // Preventing about me to have the ability to scroll
  useEffect(() => {
    document.body.style.overflow = "hidden";
    document.body.style.height = "100vh";
    return () => {
      document.body.style.overflow = "";
      document.body.style.height = "";
    };
  }, []);

  return (
    <div
      style={{
        display: "flex",
        flexDirection: "column",
        alignItems: "center",
        marginTop: "20vh",
        height: "50vh",
      }}
    >
      <h1 style={{ fontSize: "8rem", fontWeight: "bold", color: "#fff" }}>
        About
      </h1>
      <p
        style={{
          color: "#cff",
          fontSize: "1.25rem",
          maxWidth: "1200px",
          textAlign: "center",
        }}
      >
        A seamless interaction from RateMyProfessor&apos;s data to AI that
        provides summarized information of the professor&apos;s teaching
        environment. Our platform also provides the UCSC course catalog as well.
        Our goal is to inform computer science undergraduates of their chances
        in passing a course and providing the information they need to succeed.
      </p>
    </div>
  );
}

```

### src/app/evaluate/page.tsx

```typescript
"use client";
import ProfessorChoice from "@/components/ProfessorChoice";
import ProfessorStats from "@/components/ProfessorStats";
import { APP_URL } from "@/config";
import { Course, Professor } from "@/types/model";
import { useEffect, useState } from "react";

export default function Evaluate() {
  const [data, setData] = useState<Course[]>([]);
  const [course, setCourse] = useState<string>("");
  const [professorSelected, setProfessorSelected] = useState<
    Professor | undefined
  >(undefined);

  useEffect(() => {
    const fetchData = async () => {
      try {
        const res = await fetch(`${APP_URL}/api/courses`);

        const courses: Course[] = await res.json();
        setData(courses);
      } catch (err) {
        console.log(err);
      }
    };
    fetchData();
  }, []);

  return (
    <div className={"max-w-[1200px] mt-10 mx-auto"}>
      <p className={"text-5xl font-bold text-center"}>
        Lookup Course & Professor
      </p>
      <div
        className={"mt-16 grid grid-cols-2 gap-x-7 px-[25px] justify-between"}
      >
        <ProfessorChoice
          courses={data}
          professorSelected={professorSelected}
          setProfessorSelected={setProfessorSelected}
          setCourse={setCourse}
        />
        {professorSelected && (
          <ProfessorStats professor={professorSelected} course={course} />
        )}
        {!professorSelected && <div className={"w-[450px]"}></div>}
      </div>
    </div>
  );
}

```

### src/app/credits/page.tsx

```typescript
"use client";
import React, { useEffect } from "react";

export default function Results() {
  // Preventing about me to have the ability to scroll
  useEffect(() => {
    document.body.style.overflow = "hidden";
    document.body.style.height = "100vh";
    return () => {
      document.body.style.overflow = "";
      document.body.style.height = "";
    };
  }, []);

  return (
    <div
      style={{
        display: "flex",
        flexDirection: "column",
        alignItems: "center",
        marginTop: "20vh",
        height: "50vh",
      }}
    >
      <h1 style={{ fontSize: "8rem", fontWeight: "bold", color: "#fff" }}>
        Credits
      </h1>
      <p
        style={{
          color: "#cff",
          fontSize: "1.25rem",
          maxWidth: "1300px",
          textAlign: "center",
        }}
      >
        The tools we used are: Next.js, React, BeautifulSoup4,
        RateMyProfessorAPI, Material UI, Langchain, Prisma, Vercel, SQL
      </p>
      <div
        style={{
          display: "grid",
          gridTemplateColumns: "repeat(4, 1fr)",
          gap: "20px",
          padding: "20px",
          width: "100vw",
        }}
      >
        <div
          style={{
            fontSize: "2rem",
            fontWeight: "bold",
            textAlign: "center",
            width: "100%",
            marginTop: "75px",
          }}
        >
          Furkan Ercevik
        </div>
        <div
          style={{
            fontSize: "2rem",
            fontWeight: "bold",
            textAlign: "center",
            width: "100%",
            marginTop: "75px",
          }}
        >
          Jose Chavez
        </div>
        <div
          style={{
            fontSize: "2rem",
            fontWeight: "bold",
            textAlign: "center",
            width: "100%",
            marginTop: "75px",
          }}
        >
          Daniel Chang
        </div>
        <div
          style={{
            fontSize: "2rem",
            fontWeight: "bold",
            textAlign: "center",
            width: "100%",
            marginTop: "75px",
          }}
        >
          Denny Au
        </div>
        <div style={{ color: "#cff", textAlign: "center", width: "100%" }}>
          Created langchain prompts, setup database and API&apos;s, deployed to
          Vercel, and integrated backend with frontend
        </div>
        <div style={{ color: "#cff", textAlign: "center", width: "100%" }}>
          Web scraper for the BSOE website, frontend class selection page, API
          setup
        </div>
        <div style={{ color: "#cff", textAlign: "center", width: "100%" }}>
          Figma mockup of the website, frontend skills page
        </div>
        <div style={{ color: "#cff", textAlign: "center", width: "100%" }}>
          Backend web scraper for RateMyProfessor and frontend about/credits
        </div>
      </div>
    </div>
  );
}

```

### src/app/results/page.tsx

```typescript
"use client";
import { APP_URL } from "@/config";
import { Button, CircularProgress } from "@mui/material";
import { useSearchParams } from "next/navigation";
import React, { Suspense, useEffect, useState } from "react";
import ResultsPercentage from "@/components/ResultsPercentage";
import Link from "next/link";

function SurveyResponse() {
  const searchParams = useSearchParams();
  const questions = searchParams.get("questions")?.split(";;;");
  const answers = searchParams.get("answers")?.split(",");
  const course = searchParams.get("course");
  const professor = searchParams.get("professor");
  const pros = searchParams.get("pros")?.split(";;;");
  const cons = searchParams.get("cons")?.split(";;;");

  const [summary, setSummary] = useState<string>("");
  const [passRate, setPassRate] = useState<number>(0);
  const [loading, setLoading] = useState<boolean>(true);
  const [error, setError] = useState<boolean>(false);
  const [loadwheel, setLoadwheel] = useState(true);

  useEffect(() => {
    if (summary !== "") return;
    setSummary(" ");
    async function getReport() {
      setLoading(true);
      const res = await fetch(`${APP_URL}/api/ai/summary`, {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          questions,
          answers,
          professor,
          course,
        }),
      });
      const data = await res.json();
      setSummary(data.report);
      setPassRate(data.passRate);
      setLoadwheel(false);
    }

    getReport()
      .then(() => {
        setLoading(false);
        setError(false);
      })
      .catch((err) => {
        console.error(err);
        setError(true);
      });
  }, [answers, course, professor, questions, summary]);

  useEffect(() => {
    if (!loadwheel) setLoadwheel(true);
  }, [loadwheel]);

  if (loading) {
    return (
      <CircularProgress
        sx={{
          color: "white",
        }}
      />
    );
  }
  if (error) {
    return (
      <>
        <p>There was an error generating your report. Please try again.</p>
      </>
    );
  }

  return (
    <div className="flex flex-row justify-between">
      {loadwheel && <ResultsPercentage percentage={passRate * 100} />}

      <div className="flex flex-col text-wrap w-1/3 mx-36">
        <h2 className="text-2xl mb-2">Summary</h2>
        <p>{summary}</p>
      </div>
      <div className="flex flex-row text-wrap w-1/3">
        <div className="flex flex-col pr-8">
          <h2 className="text-2xl mb-2">Pros</h2>
          {pros?.map((pro: any) => {
            return <p key={`Pro: ${pro}`}>{pro}</p>;
          })}
        </div>
        <div className="flex flex-col border-l-2 pl-8">
          <h2 className="text-2xl mb-2">Cons</h2>
          {cons?.map((con: any) => {
            return <p key={`Con: ${con}`}>{con}</p>;
          })}
        </div>
      </div>
    </div>
  );
}

export default function Results() {
  return (
    <main>
      <section id={"hero"} className={`flex flex-col py-36 items-center gap-4`}>
        <h2 className="text-3xl mb-8 text-center font-bold">Your Results</h2>
        <Suspense
          fallback={
            <CircularProgress
              sx={{
                color: "white",
              }}
            />
          }
        >
          <SurveyResponse />
        </Suspense>
        <Link href={"/evaluate"} className="mt-8">
          <Button
            variant="outlined"
            style={{
              color: "white",
              borderColor: "white",
            }}
          >
            Return to professors!
          </Button>
        </Link>
      </section>
    </main>
  );
}

```

### src/app/skills/page.tsx

```typescript
"use client";

import React, { Suspense, useEffect, useState } from "react";
import SkillsComponent from "@/components/SkillsComponent";
import { redirect, useSearchParams } from "next/navigation";
import Fade from "@mui/material/Fade";
import { CircularProgress } from "@mui/material";
import { APP_URL } from "@/config";
import Link from "next/link";

function Skills() {
  const searchParams = useSearchParams();
  const Class = searchParams.get("course");
  const Professor = searchParams.get("professor");
  if (!Class || !Professor) {
    console.error(`Error: Class or professor not provided as search parameter`);
    redirect("/evaluate");
  }

  /*
        To-do:
        - Use Class and Professor to obtain SKILLS
    */

  const [questions, setQuestions] = useState<string[]>([]);
  const [answers, setAnswers] = useState<string[]>([]);
  const [num, setNum] = useState(0);
  const [shown, setShown] = useState(false);
  const [done, setDone] = useState(false);
  const [goback, setGoback] = useState(false);
  const [loading, setLoading] = useState(true);
  const [loading2, setLoading2] = useState(false);
  const [loaded, setLoaded] = useState(false);
  const [skills, setSkills] = useState([
    {
      question: "",
      options: [""],
      circles: false,
    },
  ]);
  const [pros, setPros] = useState<string[]>([]);
  const [cons, setCons] = useState<string[]>([]);
  const [prerequisites, setPrerequisites] = useState<string[]>([]);
  const [dots, setDots] = useState("");

  useEffect(() => {
    const interval = setInterval(() => {
      if (dots === "...") setDots("");
      else setDots(dots + ".");
    }, 300);
    return () => clearInterval(interval);
  }, [dots]);

  useEffect(() => {
    if (!loading) return;
    setLoading(false);
    const getProsCons = async () => {
      try {
        // console.error('Getting pros and cons');
        const res = await fetch(`${APP_URL}/api/ai/info`, {
          method: "POST",
          body: JSON.stringify({ name: Professor, course: Class }),
        });
        // const ret = await res.json();
        // console.log(ret);
        const { pros, cons, prerequisites } = await res.json();
        // console.error('Pros', pros);
        // console.error('Cons', cons);
        // console.error('Prereqs', prerequisites);
        setPros(pros);
        setCons(cons);
        setPrerequisites(prerequisites);
        setLoading2(true);
      } catch (err) {
        console.error(err);
      }
    };
    getProsCons();
  }, [loading, Class, Professor]);
  useEffect(() => {
    if (!loading2) return;
    setLoading2(false);
    const getQuestions = async () => {
      try {
        const res = await fetch(`${APP_URL}/api/ai/questions`, {
          method: "POST",
          body: JSON.stringify({ prerequisites, pros, cons }),
        });
        const { questions } = await res.json();
        // console.error('Questions', questions);
        setQuestions(questions);
      } catch (err) {
        console.error(err);
      }
    };
    getQuestions();
  }, [loading2, cons, prerequisites, pros]);
  useEffect(() => {
    if (questions.length === 0 || skills.length > 1 || loaded) return;
    setLoaded(true);
    const survey = [{ question: "", options: [""], circles: false }];
    survey.pop();
    questions.forEach((query) => {
      const qs = query.split("\n");
      qs.forEach((q) => {
        if (q.length < 10) return;
        if (q.charCodeAt(0) > 47 && q.charCodeAt(0) < 58) q = q.slice(3);
        if (q[0] === " ") q = q.slice(1);
        if (
          q.includes("A-F") ||
          q.includes("grade") ||
          (q.includes("scale") && q.includes("F"))
        ) {
          survey.push({
            question: q,
            options: ["A", "B", "C", "D", "F"],
            circles: true,
          });
        } else if (q.includes("1") && q.includes("5")) {
          survey.push({
            question: q,
            options: ["1", "2", "3", "4", "5"],
            circles: true,
          });
        } else if (q.includes("1") && q.includes("10")) {
          survey.push({
            question: q,
            options: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"],
            circles: true,
          });
        } else if (q.includes("How")) return;
        else {
          survey.push({
            question: q,
            options: ["Yes", "No"],
            circles: false,
          });
        }
      });
    });
    setSkills(survey);
  }, [questions, skills, loaded]);
  // useEffect(() => {
  //   if (done) {
  //     // redirect('/results');
  //     redirect(`/results?questions=${questions.join(';;;')}&answers=${answers.join(';;;')}&pros=${pros.join(';;;')}&cons=${cons.join(';;;')}`);
  //   }
  // }, [done]);
  useEffect(() => {
    if (goback) redirect("/evaluate");
  }, [goback]);

  const handleChoose = (option: string) => {
    setAnswers([...answers, option]);
    setShown(false);
  };
  const handleSkip = () => {
    setAnswers([...answers, ""]);
    setShown(false);
  };
  const handleBack = () => {
    if (answers.length === 0) {
      setGoback(true);
    }
    setShown(false);
    const a = answers;
    a.pop();
    setAnswers(a);
  };
  useEffect(() => {
    if (shown) return;
    const timer = setTimeout(() => {
      if (answers.length >= skills.length) setDone(true);
      else setNum(answers.length);
      setShown(true);
    }, 200);
    return () => clearTimeout(timer);
  }, [shown, answers.length]);

  return (
    <main>
      <section
        id={"hero"}
        className={`flex flex-col py-20 items-center h-[80vh]`}
      >
        <p className="text-2xl mb-8 text-center font-bold">{`${Class} - ${Professor}`}</p>
        <Fade in={shown} timeout={{ enter: 300, exit: 300 }}>
          {!done ? (
            <div>
              {!(loading || loading2 || !loaded) && (
                <SkillsComponent
                  question={skills[num].question}
                  options={skills[num].options}
                  ci
[truncated — 1477 more characters]
```

[27 more indexed source files omitted to keep this export small. The full file list is in the Codebase structure section above.]