diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 53515c3..ba402c2 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -4,21 +4,21 @@ name: Mirror
on:
push:
- branches: [ "main" ]
+ branches: ["main"]
jobs:
build:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v4
- with:
- fetch-depth: 0
- - uses: action-pack/gitlab-sync@v3
- with:
- # GitLab repo URL
- url: https://gitlab.sccs.swarthmore.edu/sccs/scheduler.git
- # GitLab username
- username: mirrorbot
- # GitLab token
- token: ${{ secrets.GITLAB_TOKEN }}
+ - uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+ - uses: action-pack/gitlab-sync@v3
+ with:
+ # GitLab repo URL
+ url: https://gitlab.sccs.swarthmore.edu/sccs/planner.git
+ # GitLab username
+ username: mirrorbot
+ # GitLab token
+ token: ${{ secrets.GITLAB_TOKEN }}
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index cc6cd89..1c314ca 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -21,11 +21,11 @@ build:
stage: build
script:
- docker compose -f docker-compose.yml build
- - docker push $SCCS_REGISTRY/sccs/scheduler/scheduler:latest
+ - docker push $SCCS_REGISTRY/sccs/planner/planner:latest
deploy_docker_stage:
stage: deploy
variables:
DOCKER_HOST: "tcp://130.58.218.21:2376"
script:
- - docker stack deploy --with-registry-auth -c ./docker-compose.yml scheduler
+ - docker stack deploy --with-registry-auth -c ./docker-compose.yml planner
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..d22ebbd
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,49 @@
+# Contributing
+
+Thanks for considering contributing to Scheduler-V2!
+
+## Opening issues
+
+If you find a bug, please feel free to [open an issue](https://github.com/swat-sccs/scheduler-v2/issues).
+
+If you taking the time to mention a problem, even a seemingly minor one, it is greatly appreciated, and a totally valid contribution to this project. Thank you!
+
+## Fixing bugs
+
+We love pull requests. Here’s a quick guide:
+
+1. [Fork this repository](https://github.com/swat-sccs/scheduler-v2/fork) and then clone it locally:
+
+ ```bash
+ git clone --recursive https://github.com/swat-sccs/scheduler-v2.git
+ ```
+
+2. Create a topic branch for your changes:
+
+ ```bash
+ git checkout -b fix-for-that-thing
+ ```
+3. Commit a failing test for the bug:
+
+ ```bash
+ git commit -am "Adds a failing test to demonstrate that thing"
+ ```
+
+4. Commit a fix that makes the test pass:
+
+ ```bash
+ git commit -am "Adds a fix for that thing!"
+ ```
+
+6. If everything looks good, push to your fork:
+
+ ```bash
+ git push origin fix-for-that-thing
+ ```
+
+7. [Submit a pull request.](https://github.com/swat-sccs/scheduler-v2/pulls)
+
+
+## Adding new features
+
+Thinking of adding a new feature? Awesome! [open an issue](https://github.com/swat-sccs/scheduler-v2/issues). and let’s work on it together!
diff --git a/README.md b/README.md
index 72972ff..c7c538d 100644
--- a/README.md
+++ b/README.md
@@ -1,33 +1,57 @@
-# Scheduler v2
+
-## Technologies Used
+
-- [Next.js 14](https://nextjs.org/docs/getting-started)
-- [NextUI v2](https://nextui.org/)
-- [Tailwind CSS](https://tailwindcss.com/)
-- [Tailwind Variants](https://tailwind-variants.org)
-- [TypeScript](https://www.typescriptlang.org/)
-- [Framer Motion](https://www.framer.com/motion/)
-- [next-themes](https://github.com/pacocoursey/next-themes)
-- [Golang](https://go.dev/)
+
SCCS Course Planner
+
+
The SCCS Course Planner is an all in one solution for planning your classes at Swarthmore College!
+
+![repo_last_commit]
+[![License][repo_license_img]][repo_license_url]
+![repo_size]
+![build_status]
+
+
Looking to plan your classes? Visit the live site!
+
-### Install dependencies
+## 🏁 Getting Started
-Install [Golang](https://go.dev/dl/)
+### Install
-Install [NodeJS](https://nodejs.org/en) v18.18 or higher
+
+
+[Golang](https://go.dev/dl/)
+
+[NodeJS](https://nodejs.org/en) v18.18 or higher
+
+[Docker](https://docs.docker.com/engine/install/)
+
+
+
+### Clone the Repo
-### Clone the Repo(recursivly!)
```bash
- git clone --recursive https://github.com/swat-sccs/scheduler-v2.git
- cd scheduler-v2
+ git clone --recursive https://github.com/swat-sccs/planner.git
+ git checkout dev
+ cd planner
```
### Configure your .env file
+
Paste the following into a .env in the root of the project.
-```env
-DATABASE_URL="postgresql://postgres:example@localhost:5432/scheduler_db"
+```bash
+echo 'DATABASE_URL="postgresql://postgres:example@localhost:5432/planner_db"' > .env
+```
+
+Pase the following into a .env in the /swatscraper dir
+
+```bash
+ echo 'HOST=localhost
+ SQL_USER=postgres
+ PASS=example
+ DBNAME=planner_db
+ OPMODE="DEV"' > ./swatscraper/.env
```
### Run the development server
@@ -42,30 +66,40 @@ first run only:
```bash
go mod init github.com/swatscraper
go mod tidy
-```
-
-```bash
go run main.go -semester=spring -year=2025 # Change to semester of choice
-
```
-
-
-### View the dev site
+## View the dev site
Head on over to http://localhost:3000
-
-
### (Optional) View the database visually and in the browser!
```bash
npx prisma studio
```
-Head on over to http://localhost:5555. Use this to confirm your database is populated.
+Head on over to http://localhost:5555. Use this to confirm your database is populated.
+
+## 📡 Technologies in Use
+- [Next.js 14](https://nextjs.org/docs/getting-started)
+- [NextUI v2](https://nextui.org/)
+- [Tailwind CSS](https://tailwindcss.com/)
+- [Tailwind Variants](https://tailwind-variants.org)
+- [TypeScript](https://www.typescriptlang.org/)
+- [Framer Motion](https://www.framer.com/motion/)
+- [next-themes](https://github.com/pacocoursey/next-themes)
+- [Golang](https://go.dev/)
## License
-Licensed under the [MIT license](https://github.com/swat-sccs/scheduler-v2/blob/main/LICENSE).
+Licensed under the [MIT license](https://github.com/swat-sccs/planner/blob/main/LICENSE).
+
+
+
+[repo_license_img]: https://img.shields.io/badge/license-Mit-red?style=for-the-badge&logo=none
+[repo_license_url]: https://github.com/swat-sccs/planner?tab=MIT-1-ov-file#readme
+[repo_last_commit]: https://img.shields.io/github/last-commit/swat-sccs/planner?style=for-the-badge&link=https%3A%2F%2Fgithub.com%2Fswat-sccs%2Fplanner&color=%2343AA8B
+[build_status]: https://img.shields.io/github/check-runs/swat-sccs/planner/main?style=for-the-badge&label=Build&color=%2343AA8B
+[repo_size]: https://img.shields.io/github/repo-size/swat-sccs/planner?style=for-the-badge
diff --git a/app/actions/getCourses.ts b/app/actions/getCourses.ts
index 8470c31..9be0a29 100644
--- a/app/actions/getCourses.ts
+++ b/app/actions/getCourses.ts
@@ -3,14 +3,130 @@
import { cookies } from "next/headers";
import prisma from "../../lib/prisma";
import { Prisma } from "@prisma/client";
+import { auth } from "@/lib/auth";
+import { getPlanCookie } from "./actions";
+
+export async function getUniqueCodes() {
+ const codes = await prisma.sectionAttribute.findMany();
+ const daCodes: any = [];
+
+ for (let i = 0; i < codes.length; i++) {
+ if (!daCodes.includes(codes[i].code)) {
+ daCodes.push(codes[i].code);
+ }
+ }
+
+ return daCodes;
+}
+
+export async function getUniqueStartEndTimes() {
+ const meetingTimes = await prisma.meetingTime.findMany({
+ where: {
+ beginTime: { not: "" },
+ },
+ orderBy: {
+ beginTime: "asc",
+ },
+ });
+ const startTimes: any = [];
+ const endTimes: any = [];
+
+ for (let i = 0; i < meetingTimes.length; i++) {
+ if (!startTimes.includes(meetingTimes[i].beginTime)) {
+ startTimes.push(meetingTimes[i].beginTime);
+ }
+ if (!endTimes.includes(meetingTimes[i].endTime)) {
+ endTimes.push(meetingTimes[i].endTime);
+ }
+ }
+
+ const times = { startTimes: startTimes, endTimes: endTimes };
+
+ return times;
+}
+
+export async function getTerms() {
+ const courses = await prisma.course.findMany();
+ const output: any = [];
+
+ for (let i = 0; i < courses.length; i++) {
+ if (!output.includes(courses[i].year)) {
+ output.push(courses[i].year);
+ }
+ }
+
+ return output;
+}
+
export async function setPlanCookie(plan: string) {
(await cookies()).set("plan", plan);
}
-export async function getInitialCourses() {
+export async function getPlanCourses1() {
+ const planCookie: any = await getPlanCookie();
+ const session = await auth();
+
+ return await prisma.coursePlan.findMany({
+ where: {
+ AND: {
+ User: {
+ uuid: session?.user.id,
+ },
+ //id: parseInt(planCookie),
+ },
+ },
+ include: {
+ courses: true,
+ },
+ });
+}
+
+export async function getPlanCourses(planID: any) {
+ //let DOTW: Array = dotw.split(",");
+
return await prisma.course.findMany({
relationLoadStrategy: "join", // or 'query'
- take: 10,
+ where: {
+ CoursePlan: {
+ some: {
+ id: parseInt(planID),
+ },
+ },
+ },
+ include: {
+ CoursePlan: true,
+ },
+ });
+}
+
+export async function getInitialCoursePlans() {
+ //let DOTW: Array = dotw.split(",");
+
+ return await prisma.coursePlan.findMany({
+ relationLoadStrategy: "join", // or 'query'
+ include: {
+ courses: true,
+ },
+ });
+}
+
+export async function getInitialCourses(
+ query: any,
+ term: any,
+ dotw: any,
+ stime: any
+) {
+ const startTime = stime.toString().split(",").filter(Number);
+ return await prisma.course.findMany({
+ relationLoadStrategy: "join", // or 'query'
+ take: 20,
+ where: {
+ ...(term
+ ? {
+ year: term,
+ }
+ : {}),
+ },
include: {
sectionAttributes: true,
@@ -26,13 +142,13 @@ export async function getInitialCourses() {
export async function getCourses(
take: any,
- cursor: any,
query: any,
term: any,
dotw: any,
stime: any
) {
const startTime = stime.toString().split(",").filter(Number);
+
return await prisma.course.findMany({
relationLoadStrategy: "join", // or 'query'
take: take,
@@ -47,15 +163,19 @@ export async function getCourses(
instructor: true,
},
- orderBy: [
- {
- _relevance: {
- fields: ["courseTitle", "subject", "courseNumber"],
- search: query.trim().split(" ").join(" & "),
- sort: "desc",
- },
- },
- ],
+ ...(query
+ ? {
+ orderBy: [
+ {
+ _relevance: {
+ fields: ["courseTitle", "subject", "courseNumber"],
+ search: query.trim().split(" ").join(" & "),
+ sort: "desc",
+ },
+ },
+ ],
+ }
+ : ""),
where: {
...(term
? {
diff --git a/app/page.tsx b/app/page.tsx
index e13e2d6..9f0fc5f 100644
--- a/app/page.tsx
+++ b/app/page.tsx
@@ -6,61 +6,15 @@ import { cookies } from "next/headers";
import Search from "../components/Search";
import { FullCourseList } from "../components/FullCourseList";
import CreatePlan from "../components/CreatePlan";
-import prisma from "../lib/prisma";
-import { getInitialCourses } from "../app/actions/getCourses";
+import {
+ getInitialCourses,
+ getPlanCourses1,
+ getTerms,
+ getUniqueStartEndTimes,
+ getUniqueCodes,
+} from "../app/actions/getCourses";
import { redirect } from "next/navigation";
-
-async function getCourses() {
- const courses = await prisma.course.findMany();
- const output: any = [];
-
- for (let i = 0; i < courses.length; i++) {
- if (!output.includes(courses[i].year)) {
- output.push(courses[i].year);
- }
- }
-
- return output;
-}
-
-async function getUniqueStartEndTimes() {
- const meetingTimes = await prisma.meetingTime.findMany({
- where: {
- beginTime: { not: "" },
- },
- orderBy: {
- beginTime: "asc",
- },
- });
- const startTimes: any = [];
- const endTimes: any = [];
-
- for (let i = 0; i < meetingTimes.length; i++) {
- if (!startTimes.includes(meetingTimes[i].beginTime)) {
- startTimes.push(meetingTimes[i].beginTime);
- }
- if (!endTimes.includes(meetingTimes[i].endTime)) {
- endTimes.push(meetingTimes[i].endTime);
- }
- }
-
- const times = { startTimes: startTimes, endTimes: endTimes };
-
- return times;
-}
-
-async function getUniquCodes() {
- const codes = await prisma.sectionAttribute.findMany();
- const daCodes: any = [];
-
- for (let i = 0; i < codes.length; i++) {
- if (!daCodes.includes(codes[i].code)) {
- daCodes.push(codes[i].code);
- }
- }
-
- return daCodes;
-}
+import { CoursePlan } from "@prisma/client";
export default async function Page(props: {
searchParams?: Promise<{
@@ -72,9 +26,12 @@ export default async function Page(props: {
}>;
}) {
const cookieStore = await cookies();
+ const planID = await cookieStore.get("plan");
const pagePref = cookieStore.get("pagePref");
+
if (pagePref && pagePref.value != "/") {
redirect(pagePref.value);
+
}
const searchParams = await props.searchParams;
@@ -83,7 +40,8 @@ export default async function Page(props: {
const dotw = searchParams?.dotw || [];
const stime = searchParams?.stime || [];
const homePageProps: any = {};
- const initalCourses = await getInitialCourses();
+ const initalCourses = await getInitialCourses(query, term, dotw, stime);
+ const planCourses: CoursePlan[] = await getPlanCourses1();
homePageProps["fullCourseList"] = (
}
>
-
+
);
return ; // return with no events
}
async function Home(props: any) {
- const terms = await getCourses();
+ const terms = await getTerms();
const uniqueTimes = await getUniqueStartEndTimes();
- const codes = await getUniquCodes();
+ const codes = await getUniqueCodes();
return (
<>
@@ -134,7 +92,7 @@ async function Home(props: any) {
-
+ {props.createPlan}
>
diff --git a/components/FullCourseList.tsx b/components/FullCourseList.tsx
index ae394b7..62e9172 100644
--- a/components/FullCourseList.tsx
+++ b/components/FullCourseList.tsx
@@ -38,7 +38,7 @@ export function FullCourseList({
setCursor((cursor) => cursor + NUMBER_OF_USERS_TO_FETCH);
setTake((take) => take + NUMBER_OF_USERS_TO_FETCH);
- const apiCourses = await getCourses(take, cursor, query, term, dotw, stime);
+ const apiCourses = await getCourses(take, query, term, dotw, stime);
if (
inView &&
(apiCourses.length == 0 || apiCourses.length == courses.length)
diff --git a/components/OLD.FullCourseList.tsx b/components/OLD.FullCourseList.tsx
deleted file mode 100644
index ab2e7bc..0000000
--- a/components/OLD.FullCourseList.tsx
+++ /dev/null
@@ -1,149 +0,0 @@
-import { Course, Prisma } from "@prisma/client";
-
-import prisma from "../lib/prisma";
-
-import CourseCard from "./CourseCard";
-import React from "react";
-
-async function getCourses(
- query: string,
- term: string,
- dotw: Array,
- stime: Array
-) {
- //let DOTW: Array = dotw.split(",");
-
- //query = query.trim().replace(/^[a-zA-Z0-9:]+$/g, "");
-
- const startTime = stime.toString().split(",").filter(Number);
-
- return await prisma.course.findMany({
- relationLoadStrategy: "join", // or 'query'
- include: {
- sectionAttributes: true,
- facultyMeet: {
- include: {
- meetingTimes: true,
- },
- },
- instructor: true,
- },
-
- orderBy: [
- {
- _relevance: {
- fields: ["courseTitle", "subject", "courseNumber"],
- search: query.trim().split(" ").join(" & "),
- sort: "desc",
- },
- },
- ],
- where: {
- ...(term
- ? {
- year: term,
- }
- : {}),
- //year: term,
-
- ...(query
- ? {
- OR: [
- {
- courseTitle: {
- search: query.trim().split(" ").join(" | "),
- mode: "insensitive",
- },
- },
- {
- sectionAttributes: {
- some: {
- code: {
- search: query.trim().split(" ").join(" | "),
- mode: "insensitive",
- },
- },
- },
- },
- {
- subject: {
- search: query.trim().split(" ").join(" | "),
- mode: "insensitive",
- },
- },
- {
- courseNumber: {
- search: query.trim().split(" ").join(" | "),
- mode: "insensitive",
- },
- },
- {
- instructor: {
- displayName: {
- search: query.trim().split(" ").join(" | "),
- mode: "insensitive",
- },
- },
- },
- ],
- }
- : {}),
-
- ...(startTime.length > 0
- ? {
- facultyMeet: {
- meetingTimes: {
- beginTime: {
- in: startTime,
- },
- },
- },
- }
- : {}),
-
- ...(dotw.length > 0
- ? {
- facultyMeet: {
- meetingTimes: {
- is: {
- monday: dotw.includes("monday") ? true : Prisma.skip,
- tuesday: dotw.includes("tuesday") ? true : Prisma.skip,
- wednesday: dotw.includes("wednesday") ? true : Prisma.skip,
- thursday: dotw.includes("thursday") ? true : Prisma.skip,
- friday: dotw.includes("friday") ? true : Prisma.skip,
- saturday: dotw.includes("saturday") ? true : Prisma.skip,
- sunday: dotw.includes("sunday") ? true : Prisma.skip,
- },
- },
- },
- }
- : {}),
- },
- });
-}
-
-export async function FullCourseList({
- query,
- term,
- dotw,
- stime,
-}: {
- query: string;
- term: string;
- dotw: Array;
- stime: Array;
-}) {
- const courseList: Course[] = await getCourses(query, term, dotw, stime);
-
- return (
- <>
-
- {courseList?.map((course: any) => (
-
-
-
- ))}
-
- >
- );
-}
diff --git a/components/PlanContext.tsx b/components/PlanContext.tsx
new file mode 100644
index 0000000..2119847
--- /dev/null
+++ b/components/PlanContext.tsx
@@ -0,0 +1,24 @@
+"use client";
+import { createContext, useContext, useState } from "react";
+import { CoursePlan } from "@prisma/client";
+import { getInitialCoursePlans } from "../app/actions/getCourses";
+
+const PlanContext = createContext([]);
+
+export const PlanContextProvider = ({
+ children,
+}: {
+ children: React.ReactNode;
+}) => {
+ const [coursePlans, setCoursePlans] = useState([]);
+
+ return (
+
+ {children}
+
+ );
+};
+
+export const usePlanContext = () => {
+ return useContext(PlanContext);
+};
diff --git a/components/Search.tsx b/components/Search.tsx
index 4087c90..c0633cd 100644
--- a/components/Search.tsx
+++ b/components/Search.tsx
@@ -51,7 +51,7 @@ export default function Search(props: any) {
params.delete("query");
}
replace(`${pathname}?${params.toString()}`);
- });
+ }, 100);
const handleSelectionChange = (e: any) => {
setSelectedTerm([e.target.value]);
@@ -85,6 +85,7 @@ export default function Search(props: any) {
setSelectedDOTW(searchParams.get("dotw")?.toString().split(","));
setSelectedStartTime(searchParams.get("stime")?.toString().split(","));
//handleSelectionChange({ target: { value: selectedTerm } });
+
}, [searchParams]);
useEffect(() => {
diff --git a/docker-compose.debug.yml b/docker-compose.debug.yml
index a389da7..1a94fa4 100644
--- a/docker-compose.debug.yml
+++ b/docker-compose.debug.yml
@@ -1,5 +1,6 @@
services:
- schedulerv2:
+ planner-dev:
+ container_name: planner-dev
build:
context: .
dockerfile: ./Dockerfile.dev
@@ -8,8 +9,7 @@ services:
environment:
NODE_ENV: development
DOMAIN: http://127.0.0.1:3000/
- DATABASE_URL: "postgresql://postgres:example@postgres:5432/scheduler_db"
- POSTGRES_DB: scheduler_db
+ POSTGRES_DB: planner_db
env_file:
- .env
ports:
@@ -19,13 +19,14 @@ services:
- internal
command: sh -c "npm install --silent && npx prisma migrate dev --name init && npx prisma generate && npm run dev "
- postgres:
+ planner-db-dev:
+ container_name: planner-db-dev
image: postgres:16.4-bullseye
ports:
- 5432:5432
environment:
POSTGRES_PASSWORD: example
- POSTGRES_DB: scheduler_db
+ POSTGRES_DB: planner_db
networks:
- internal
volumes:
diff --git a/docker-compose.yml b/docker-compose.yml
index 341ea2c..887f8ee 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,6 +1,6 @@
services:
- scheduler:
- image: registry.sccs.swarthmore.edu/sccs/scheduler/scheduler:latest
+ planner:
+ image: registry.sccs.swarthmore.edu/sccs/planner/planner:latest
build:
context: .
dockerfile: ./Dockerfile
@@ -9,28 +9,28 @@ services:
- .env
environment:
NODE_ENV: production
- DOMAIN: https://schedulerv2.sccs.swarthmore.edu
+ DOMAIN: https://plan.sccs.swarthmore.edu
depends_on:
- - scheduler-db
+ - planner-db
deploy:
labels:
- - 'traefik.enable=true'
- - 'traefik.docker.network=traefik'
- - 'traefik.http.routers.scheduler.entrypoints=https'
- - 'traefik.http.routers.scheduler.rule=Host(`schedulerv2.sccs.swarthmore.edu`)'
- - 'traefik.http.routers.scheduler.tls=true'
- - 'traefik.http.routers.scheduler.tls.certresolver=letsEncrypt'
- - 'traefik.http.services.scheduler.loadbalancer.server.port=3000'
+ - "traefik.enable=true"
+ - "traefik.docker.network=traefik"
+ - "traefik.http.routers.planner.entrypoints=https"
+ - "traefik.http.routers.planner.rule=Host(`plan.sccs.swarthmore.edu`)"
+ - "traefik.http.routers.planner.tls=true"
+ - "traefik.http.routers.planner.tls.certresolver=letsEncrypt"
+ - "traefik.http.services.planner.loadbalancer.server.port=3000"
command: sh -c "sleep 5 && npx prisma migrate deploy && npm start "
networks:
- traefik
- internal
- scheduler-db:
- hostname: scheduler-db
+ planner-db:
+ hostname: planner-db
image: postgres:16.4-bullseye
volumes:
- - scheduler-dbdata:/var/lib/postgresql/data
+ - planner-dbdata:/var/lib/postgresql/data
env_file:
- .env
ports:
@@ -38,8 +38,8 @@ services:
networks:
- internal
- scheduler-cron:
- image: registry.sccs.swarthmore.edu/sccs/scheduler/scheduler-cron:latest
+ planner-cron:
+ image: registry.sccs.swarthmore.edu/sccs/planner/planner-cron:latest
build:
context: .
dockerfile: ./Dockerfile.cron
@@ -47,7 +47,7 @@ services:
env_file:
- .env
depends_on:
- - scheduler-db
+ - planner-db
networks:
- internal
@@ -60,9 +60,9 @@ networks:
external: true
volumes:
- scheduler-dbdata:
- name: scheduler-dbdata
+ planner-dbdata:
+ name: planner-dbdata
driver_opts:
type: nfs
o: "nfsvers=4,addr=130.58.218.26,rw,nolock,soft"
- device: ":/volumes/scheduler-dbdata"
+ device: ":/volumes/planner-dbdata"
diff --git a/public/logo/logo.png b/public/logo/logo.png
new file mode 100644
index 0000000..22b8179
Binary files /dev/null and b/public/logo/logo.png differ