- {/* Schedule Preview */}
-
-
-
+
+
+
+ {/* Schedule Preview */}
+
+
+
-
-
- {/* Sidebar */}
-
-
+
+
)
}
diff --git a/src/react-app-env.d.ts b/src/react-app-env.d.ts
deleted file mode 100644
index 6431bc5f..00000000
--- a/src/react-app-env.d.ts
+++ /dev/null
@@ -1 +0,0 @@
-///
diff --git a/src/utils/data.ts b/src/utils/data.ts
deleted file mode 100644
index 9f0acc3b..00000000
--- a/src/utils/data.ts
+++ /dev/null
@@ -1,1109 +0,0 @@
-import { Major, Course } from '../@types'
-
-export const majorsData: Major[] = [
-// {
-// id: 1,
-// name: 'Licenciatura em Engenharia Informática e Computação',
-// course_id: 0,
-// faculty: 1,
-// acronym: 'M.EIC',
-// course_type: 'M',
-// year: 2021,
-// url: 'https://sigarra.up.pt/feup/pt/cur_geral.cur_view?pv_curso_id=22862',
-// plan_url: 'https://sigarra.up.pt/feup/pt/CUR_GERAL.CUR_PLANOS_ESTUDOS_VIEW?pv_plano_id=31204&pv_ano_lectivo=2021',
-// last_updated: '2022-02-19T14:41:34Z',
-// },
-// {
-// id: 2,
-// name: 'Licenciatura em Engenharia Eletrotécnica e de Computadores',
-// course_id: 0,
-// faculty: 1,
-// acronym: 'M.EIC',
-// course_type: 'M',
-// year: 2021,
-// url: 'https://sigarra.up.pt/feup/pt/cur_geral.cur_view?pv_curso_id=22862',
-// plan_url: 'https://sigarra.up.pt/feup/pt/CUR_GERAL.CUR_PLANOS_ESTUDOS_VIEW?pv_plano_id=31204&pv_ano_lectivo=2021',
-// last_updated: '2022-02-19T14:41:34Z',
-// },
-// {
-// id: 3,
-// name: 'Licenciatura em Engenharia Civil',
-// course_id: 0,
-// faculty: 1,
-// acronym: 'M.EIC',
-// course_type: 'M',
-// year: 2021,
-// url: 'https://sigarra.up.pt/feup/pt/cur_geral.cur_view?pv_curso_id=22862',
-// plan_url: 'https://sigarra.up.pt/feup/pt/CUR_GERAL.CUR_PLANOS_ESTUDOS_VIEW?pv_plano_id=31204&pv_ano_lectivo=2021',
-// last_updated: '2022-02-19T14:41:34Z',
-// },
-// {
-// id: 4,
-// name: 'Licenciatura em Engenharia Mecânica',
-// course_id: 0,
-// faculty: 1,
-// acronym: 'M.EIC',
-// course_type: 'M',
-// year: 2021,
-// url: 'https://sigarra.up.pt/feup/pt/cur_geral.cur_view?pv_curso_id=22862',
-// plan_url: 'https://sigarra.up.pt/feup/pt/CUR_GERAL.CUR_PLANOS_ESTUDOS_VIEW?pv_plano_id=31204&pv_ano_lectivo=2021',
-// last_updated: '2022-02-19T14:41:34Z',
-// },
-// {
-// id: 5,
-// name: 'Mestrado em Engenharia Informática e Computação',
-// course_id: 0,
-// faculty: 1,
-// acronym: 'M.EIC',
-// course_type: 'M',
-// year: 2021,
-// url: 'https://sigarra.up.pt/feup/pt/cur_geral.cur_view?pv_curso_id=22862',
-// plan_url: 'https://sigarra.up.pt/feup/pt/CUR_GERAL.CUR_PLANOS_ESTUDOS_VIEW?pv_plano_id=31204&pv_ano_lectivo=2021',
-// last_updated: '2022-02-19T14:41:34Z',
-// },
-// {
-// id: 6,
-// name: 'Mestrado em Engenharia Eletrotécnica e de Computadores',
-// course_id: 0,
-// faculty: 1,
-// acronym: 'M.EIC',
-// course_type: 'M',
-// year: 2021,
-// url: 'https://sigarra.up.pt/feup/pt/cur_geral.cur_view?pv_curso_id=22862',
-// plan_url: 'https://sigarra.up.pt/feup/pt/CUR_GERAL.CUR_PLANOS_ESTUDOS_VIEW?pv_plano_id=31204&pv_ano_lectivo=2021',
-// last_updated: '2022-02-19T14:41:34Z',
-// },
-// {
-// id: 7,
-// name: 'Mestrado em Engenharia Civil',
-// course_id: 0,
-// faculty: 1,
-// acronym: 'M.EIC',
-// course_type: 'M',
-// year: 2021,
-// url: 'https://sigarra.up.pt/feup/pt/cur_geral.cur_view?pv_curso_id=22862',
-// plan_url: 'https://sigarra.up.pt/feup/pt/CUR_GERAL.CUR_PLANOS_ESTUDOS_VIEW?pv_plano_id=31204&pv_ano_lectivo=2021',
-// last_updated: '2022-02-19T14:41:34Z',
-// },
-// {
-// id: 8,
-// name: 'Mestrado em Engenharia Química',
-// course_id: 0,
-// faculty: 1,
-// acronym: 'M.EIC',
-// course_type: 'M',
-// year: 2021,
-// url: 'https://sigarra.up.pt/feup/pt/cur_geral.cur_view?pv_curso_id=22862',
-// plan_url: 'https://sigarra.up.pt/feup/pt/CUR_GERAL.CUR_PLANOS_ESTUDOS_VIEW?pv_plano_id=31204&pv_ano_lectivo=2021',
-// last_updated: '2022-02-19T14:41:34Z',
-// },
-// {
-// id: 9,
-// name: 'Mestrado em Engenharia Mecânica',
-// course_id: 0,
-// faculty: 1,
-// acronym: 'M.EIC',
-// course_type: 'M',
-// year: 2021,
-// url: 'https://sigarra.up.pt/feup/pt/cur_geral.cur_view?pv_curso_id=22862',
-// plan_url: 'https://sigarra.up.pt/feup/pt/CUR_GERAL.CUR_PLANOS_ESTUDOS_VIEW?pv_plano_id=31204&pv_ano_lectivo=2021',
-// last_updated: '2022-02-19T14:41:34Z',
-// },
-// {
-// id: 10,
-// name: 'Mestrado em Engenharia do Ambiente',
-// course_id: 0,
-// faculty: 1,
-// acronym: 'M.EIC',
-// course_type: 'M',
-// year: 2021,
-// url: 'https://sigarra.up.pt/feup/pt/cur_geral.cur_view?pv_curso_id=22862',
-// plan_url: 'https://sigarra.up.pt/feup/pt/CUR_GERAL.CUR_PLANOS_ESTUDOS_VIEW?pv_plano_id=31204&pv_ano_lectivo=2021',
-// last_updated: '2022-02-19T14:41:34Z',
-// },
-// {
-// id: 11,
-// name: 'Mestrado em Engenharia e Gestão Industrial',
-// course_id: 0,
-// faculty: 1,
-// acronym: 'M.EIC',
-// course_type: 'M',
-// year: 2021,
-// url: 'https://sigarra.up.pt/feup/pt/cur_geral.cur_view?pv_curso_id=22862',
-// plan_url: 'https://sigarra.up.pt/feup/pt/CUR_GERAL.CUR_PLANOS_ESTUDOS_VIEW?pv_plano_id=31204&pv_ano_lectivo=2021',
-// last_updated: '2022-02-19T14:41:34Z',
-// },
-// ]
-
-// export const coursesData: Course[][] = [
-// [
-// {
-// id: 1,
-// course_id: 0,
-// course_unit_id: 484400,
-// course: 'L.EIC007',
-// name: 'Análise Matemática II',
-// acronym: 'AM II',
-// url: 'https://sigarra.up.pt/feup/pt/ucurr_geral.ficha_uc_view?pv_ocorrencia_id=484400',
-// course_unit_year: 1,
-// semester: 2,
-// year: 2021,
-// schedule_url: 'https://sigarra.up.pt/feup/pt/hor_geral.ucurr_view?pv_ocorrencia_id=484400 ',
-// last_updated: '2022-02-19T14:43:27Z',
-// },
-// {
-// id: 2,
-// course_id: 0,
-// course_unit_id: 484401,
-// course: 'L.EIC008',
-// name: 'Física I',
-// acronym: 'F I',
-// url: 'https://sigarra.up.pt/feup/pt/ucurr_geral.ficha_uc_view?pv_ocorrencia_id=484401',
-// course_unit_year: 1,
-// semester: 2,
-// year: 2021,
-// schedule_url: 'https://sigarra.up.pt/feup/pt/hor_geral.ucurr_view?pv_ocorrencia_id=484401 ',
-// last_updated: '2022-02-19T14:43:27Z',
-// },
-// {
-// id: 3,
-// course_id: 0,
-// course_unit_id: 484423,
-// course: 'L.EIC010',
-// name: 'Teoria da Computação',
-// acronym: 'TC',
-// url: 'https://sigarra.up.pt/feup/pt/ucurr_geral.ficha_uc_view?pv_ocorrencia_id=484423',
-// course_unit_year: 1,
-// semester: 2,
-// year: 2021,
-// schedule_url: 'https://sigarra.up.pt/feup/pt/hor_geral.ucurr_view?pv_ocorrencia_id=484423 ',
-// last_updated: '2022-02-19T14:43:27Z',
-// },
-// {
-// id: 4,
-// course_id: 0,
-// course_unit_id: 484399,
-// course: 'L.EIC006',
-// name: 'Arquitetura de Computadores',
-// acronym: 'AC',
-// url: 'https://sigarra.up.pt/feup/pt/ucurr_geral.ficha_uc_view?pv_ocorrencia_id=484399',
-// course_unit_year: 1,
-// semester: 2,
-// year: 2021,
-// schedule_url: 'https://sigarra.up.pt/feup/pt/hor_geral.ucurr_view?pv_ocorrencia_id=484399 ',
-// last_updated: '2022-02-19T14:43:27Z',
-// },
-// {
-// id: 5,
-// course_id: 0,
-// course_unit_id: 484422,
-// course: 'L.EIC009',
-// name: 'Programação',
-// acronym: 'P',
-// url: 'https://sigarra.up.pt/feup/pt/ucurr_geral.ficha_uc_view?pv_ocorrencia_id=484422',
-// course_unit_year: 1,
-// semester: 2,
-// year: 2021,
-// schedule_url: 'https://sigarra.up.pt/feup/pt/hor_geral.ucurr_view?pv_ocorrencia_id=484422 ',
-// last_updated: '2022-02-19T14:43:27Z',
-// },
-// ],
-// [
-// {
-// id: 6,
-// course_id: 0,
-// course_unit_id: 484426,
-// course: 'L.EIC018',
-// name: 'Laboratório de Computadores',
-// acronym: 'LC',
-// url: 'https://sigarra.up.pt/feup/pt/ucurr_geral.ficha_uc_view?pv_ocorrencia_id=484426',
-// course_unit_year: 2,
-// semester: 2,
-// year: 2021,
-// schedule_url: 'https://sigarra.up.pt/feup/pt/hor_geral.ucurr_view?pv_ocorrencia_id=484426 ',
-// last_updated: '2022-02-19T14:43:27Z',
-// },
-// {
-// id: 7,
-// course_id: 0,
-// course_unit_id: 484427,
-// course: 'L.EIC019',
-// name: 'Linguagens e Tecnologias Web',
-// acronym: 'LTW',
-// url: 'https://sigarra.up.pt/feup/pt/ucurr_geral.ficha_uc_view?pv_ocorrencia_id=484427',
-// course_unit_year: 2,
-// semester: 2,
-// year: 2021,
-// schedule_url: 'https://sigarra.up.pt/feup/pt/hor_geral.ucurr_view?pv_ocorrencia_id=484427 ',
-// last_updated: '2022-02-19T14:43:27Z',
-// },
-// {
-// id: 8,
-// course_id: 0,
-// course_unit_id: 484424,
-// course: 'L.EIC016',
-// name: 'Desenho de Algoritmos',
-// acronym: 'DA',
-// url: 'https://sigarra.up.pt/feup/pt/ucurr_geral.ficha_uc_view?pv_ocorrencia_id=484424',
-// course_unit_year: 2,
-// semester: 2,
-// year: 2021,
-// schedule_url: 'https://sigarra.up.pt/feup/pt/hor_geral.ucurr_view?pv_ocorrencia_id=484424 ',
-// last_updated: '2022-02-19T14:43:27Z',
-// },
-// {
-// id: 9,
-// course_id: 0,
-// course_unit_id: 484425,
-// course: 'L.EIC017',
-// name: 'Engenharia de Software',
-// acronym: 'ES',
-// url: 'https://sigarra.up.pt/feup/pt/ucurr_geral.ficha_uc_view?pv_ocorrencia_id=484425',
-// course_unit_year: 2,
-// semester: 2,
-// year: 2021,
-// schedule_url: 'https://sigarra.up.pt/feup/pt/hor_geral.ucurr_view?pv_ocorrencia_id=484425 ',
-// last_updated: '2022-02-19T14:43:27Z',
-// },
-// {
-// id: 10,
-// course_id: 0,
-// course_unit_id: 484428,
-// course: 'L.EIC020',
-// name: 'Métodos Estatísticos',
-// acronym: 'ME',
-// url: 'https://sigarra.up.pt/feup/pt/ucurr_geral.ficha_uc_view?pv_ocorrencia_id=484428',
-// course_unit_year: 2,
-// semester: 2,
-// year: 2021,
-// schedule_url: 'https://sigarra.up.pt/feup/pt/hor_geral.ucurr_view?pv_ocorrencia_id=484428 ',
-// last_updated: '2022-02-19T14:43:27Z',
-// },
-// ],
-// [
-// {
-// id: 11,
-// course_id: 0,
-// course_unit_id: 484381,
-// course: 'L.EIC028',
-// name: 'Computação Paralela e Distribuída',
-// acronym: 'CPD',
-// url: 'https://sigarra.up.pt/feup/pt/ucurr_geral.ficha_uc_view?pv_ocorrencia_id=484381',
-// course_unit_year: 3,
-// semester: 2,
-// year: 2021,
-// schedule_url: 'https://sigarra.up.pt/feup/pt/hor_geral.ucurr_view?pv_ocorrencia_id=484381 ',
-// last_updated: '2022-02-19T14:43:27Z',
-// },
-// {
-// id: 12,
-// course_id: 0,
-// course_unit_id: 484379,
-// course: 'L.EIC026',
-// name: 'Compiladores',
-// acronym: 'C',
-// url: 'https://sigarra.up.pt/feup/pt/ucurr_geral.ficha_uc_view?pv_ocorrencia_id=484379',
-// course_unit_year: 3,
-// semester: 2,
-// year: 2021,
-// schedule_url: 'https://sigarra.up.pt/feup/pt/hor_geral.ucurr_view?pv_ocorrencia_id=484379 ',
-// last_updated: '2022-02-19T14:43:27Z',
-// },
-// {
-// id: 13,
-// course_id: 0,
-// course_unit_id: 484380,
-// course: 'L.EIC027',
-// name: 'Computação Gráfica',
-// acronym: 'CG',
-// url: 'https://sigarra.up.pt/feup/pt/ucurr_geral.ficha_uc_view?pv_ocorrencia_id=484380',
-// course_unit_year: 3,
-// semester: 2,
-// year: 2021,
-// schedule_url: 'https://sigarra.up.pt/feup/pt/hor_geral.ucurr_view?pv_ocorrencia_id=484380 ',
-// last_updated: '2022-02-19T14:43:27Z',
-// },
-// {
-// id: 14,
-// course_id: 0,
-// course_unit_id: 484443,
-// course: 'L.EIC030',
-// name: 'Projeto Integrador',
-// acronym: 'PI',
-// url: 'https://sigarra.up.pt/feup/pt/ucurr_geral.ficha_uc_view?pv_ocorrencia_id=484443',
-// course_unit_year: 3,
-// semester: 2,
-// year: 2021,
-// schedule_url: 'https://sigarra.up.pt/feup/pt/hor_geral.ucurr_view?pv_ocorrencia_id=484443 ',
-// last_updated: '2022-02-19T14:43:27Z',
-// },
-// {
-// id: 15,
-// course_id: 0,
-// course_unit_id: 484442,
-// course: 'L.EIC029',
-// name: 'Inteligência Artificial',
-// acronym: 'IA',
-// url: 'https://sigarra.up.pt/feup/pt/ucurr_geral.ficha_uc_view?pv_ocorrencia_id=484442',
-// course_unit_year: 3,
-// semester: 2,
-// year: 2021,
-// schedule_url: 'https://sigarra.up.pt/feup/pt/hor_geral.ucurr_view?pv_ocorrencia_id=484442 ',
-// last_updated: '2022-02-19T14:43:27Z',
-// },
-// ],
-// ]
-
-// export const schedulesData: CourseSchedule[][] = [
-// [
-// {
-// day: 1,
-// duration: '2.0',
-// start_time: '9.0',
-// location: 'B002',
-// lesson_type: 'T',
-// teacher_acronym: 'LPR',
-// course_unit_id: 484442,
-// last_updated: '2022-05-17T21:45:51Z',
-// class_name: null,
-// composed_class_name: 'COMP_2345',
-// },
-// {
-// day: 3,
-// duration: '2.0',
-// start_time: '10.5',
-// location: 'B342',
-// lesson_type: 'TP',
-// teacher_acronym: 'HLC',
-// course_unit_id: 484442,
-// last_updated: '2022-05-17T21:45:51Z',
-// class_name: '3LEIC01',
-// composed_class_name: null,
-// },
-// {
-// day: 3,
-// duration: '2.0',
-// start_time: '8.5',
-// location: 'B217',
-// lesson_type: 'TP',
-// teacher_acronym: 'APR',
-// course_unit_id: 484442,
-// last_updated: '2022-05-17T21:45:51Z',
-// class_name: '3LEIC02',
-// composed_class_name: null,
-// },
-// {
-// day: 2,
-// duration: '2.0',
-// start_time: '10.5',
-// location: 'B206',
-// lesson_type: 'TP',
-// teacher_acronym: 'NRSG',
-// course_unit_id: 484442,
-// last_updated: '2022-05-17T21:45:51Z',
-// class_name: '3LEIC03',
-// composed_class_name: null,
-// },
-// {
-// day: 2,
-// duration: '2.0',
-// start_time: '8.5',
-// location: 'B202',
-// lesson_type: 'TP',
-// teacher_acronym: 'NRSG',
-// course_unit_id: 484442,
-// last_updated: '2022-05-17T21:45:51Z',
-// class_name: '3LEIC04',
-// composed_class_name: null,
-// },
-// {
-// day: 2,
-// duration: '2.0',
-// start_time: '10.5',
-// location: 'B107',
-// lesson_type: 'TP',
-// teacher_acronym: 'LPR',
-// course_unit_id: 484442,
-// last_updated: '2022-05-17T21:45:51Z',
-// class_name: '3LEIC05',
-// composed_class_name: null,
-// },
-// {
-// day: 2,
-// duration: '2.0',
-// start_time: '8.5',
-// location: 'B307',
-// lesson_type: 'TP',
-// teacher_acronym: 'HLC',
-// course_unit_id: 484442,
-// last_updated: '2022-05-17T21:45:51Z',
-// class_name: '3LEIC06',
-// composed_class_name: null,
-// },
-// {
-// day: 3,
-// duration: '2.0',
-// start_time: '10.5',
-// location: 'B306',
-// lesson_type: 'TP',
-// teacher_acronym: 'APR',
-// course_unit_id: 484442,
-// last_updated: '2022-05-17T21:45:51Z',
-// class_name: '3LEIC07',
-// composed_class_name: null,
-// },
-// {
-// day: 3,
-// duration: '2.0',
-// start_time: '8.5',
-// location: 'B204',
-// lesson_type: 'TP',
-// teacher_acronym: 'HLC',
-// course_unit_id: 484442,
-// last_updated: '2022-05-17T21:45:51Z',
-// class_name: '3LEIC08',
-// composed_class_name: null,
-// },
-// ],
-// [
-// {
-// day: 5,
-// duration: '3.0',
-// start_time: '10',
-// location: 'B119',
-// lesson_type: 'OT',
-// teacher_acronym: 'APR',
-// course_unit_id: 484443,
-// last_updated: '2022-05-17T21:45:51Z',
-// class_name: '3LEIC01',
-// composed_class_name: null,
-// },
-// {
-// day: 5,
-// duration: '3.0',
-// start_time: '14',
-// location: 'B340',
-// lesson_type: 'OT',
-// teacher_acronym: 'NHF',
-// course_unit_id: 484443,
-// last_updated: '2022-05-17T21:45:51Z',
-// class_name: '3LEIC02',
-// composed_class_name: null,
-// },
-// {
-// day: 5,
-// duration: '3.0',
-// start_time: '14',
-// location: 'B113',
-// lesson_type: 'OT',
-// teacher_acronym: 'JPF',
-// course_unit_id: 484443,
-// last_updated: '2022-05-17T21:45:51Z',
-// class_name: '3LEIC03',
-// composed_class_name: null,
-// },
-// {
-// day: 5,
-// duration: '3.0',
-// start_time: '14',
-// location: 'B115',
-// lesson_type: 'OT',
-// teacher_acronym: 'MTC',
-// course_unit_id: 484443,
-// last_updated: '2022-05-17T21:45:51Z',
-// class_name: '3LEIC04',
-// composed_class_name: null,
-// },
-// {
-// day: 5,
-// duration: '3.0',
-// start_time: '10',
-// location: 'B220',
-// lesson_type: 'OT',
-// teacher_acronym: 'NHF',
-// course_unit_id: 484443,
-// last_updated: '2022-05-17T21:45:51Z',
-// class_name: '3LEIC05',
-// composed_class_name: null,
-// },
-// {
-// day: 5,
-// duration: '3.0',
-// start_time: '10',
-// location: 'B339',
-// lesson_type: 'OT',
-// teacher_acronym: 'PMAB',
-// course_unit_id: 484443,
-// last_updated: '2022-05-17T21:45:51Z',
-// class_name: '3LEIC06',
-// composed_class_name: null,
-// },
-// {
-// day: 5,
-// duration: '3.0',
-// start_time: '14',
-// location: 'B322',
-// lesson_type: 'OT',
-// teacher_acronym: 'PMAB',
-// course_unit_id: 484443,
-// last_updated: '2022-05-17T21:45:51Z',
-// class_name: null,
-// composed_class_name: 'COMP_2598',
-// },
-// {
-// day: 5,
-// duration: '3.0',
-// start_time: '10',
-// location: 'B340',
-// lesson_type: 'OT',
-// teacher_acronym: 'tbs',
-// course_unit_id: 484443,
-// last_updated: '2022-05-17T21:45:51Z',
-// class_name: null,
-// composed_class_name: 'COMP_2771',
-// },
-// ],
-// [
-// {
-// day: 4,
-// duration: '2.0',
-// start_time: '10.5',
-// location: 'B013',
-// lesson_type: 'T',
-// teacher_acronym: 'DCC-AMSMF+PNF',
-// course_unit_id: 484379,
-// last_updated: '2022-05-17T21:45:51Z',
-// class_name: null,
-// composed_class_name: 'COMP_3112',
-// },
-// {
-// day: 4,
-// duration: '2.0',
-// start_time: '14',
-// location: 'B013',
-// lesson_type: 'T',
-// teacher_acronym: 'DCC-AMSMF+PNF',
-// course_unit_id: 484379,
-// last_updated: '2022-05-17T21:45:51Z',
-// class_name: null,
-// composed_class_name: 'COMP_3110',
-// },
-// {
-// day: 2,
-// duration: '2.0',
-// start_time: '10.5',
-// location: 'B342',
-// lesson_type: 'P',
-// teacher_acronym: 'AMSMF',
-// course_unit_id: 484379,
-// last_updated: '2022-05-17T21:45:51Z',
-// class_name: '3LEIC01',
-// composed_class_name: null,
-// },
-// {
-// day: 3,
-// duration: '2.0',
-// start_time: '10.5',
-// location: 'B217',
-// lesson_type: 'P',
-// teacher_acronym: 'LGBC',
-// course_unit_id: 484379,
-// last_updated: '2022-05-17T21:45:51Z',
-// class_name: '3LEIC02',
-// composed_class_name: null,
-// },
-// {
-// day: 3,
-// duration: '2.0',
-// start_time: '10.5',
-// location: 'B205',
-// lesson_type: 'P',
-// teacher_acronym: 'PMSP',
-// course_unit_id: 484379,
-// last_updated: '2022-05-17T21:45:51Z',
-// class_name: '3LEIC03',
-// composed_class_name: null,
-// },
-// {
-// day: 3,
-// duration: '2.0',
-// start_time: '8.5',
-// location: 'B310',
-// lesson_type: 'P',
-// teacher_acronym: 'PMSP',
-// course_unit_id: 484379,
-// last_updated: '2022-05-17T21:45:51Z',
-// class_name: '3LEIC04',
-// composed_class_name: null,
-// },
-// {
-// day: 3,
-// duration: '2.0',
-// start_time: '10.5',
-// location: 'B107',
-// lesson_type: 'P',
-// teacher_acronym: 'PNFRCD',
-// course_unit_id: 484379,
-// last_updated: '2022-05-17T21:45:51Z',
-// class_name: '3LEIC05',
-// composed_class_name: null,
-// },
-// {
-// day: 3,
-// duration: '2.0',
-// start_time: '8.5',
-// location: 'B202',
-// lesson_type: 'P',
-// teacher_acronym: 'PNFRCD',
-// course_unit_id: 484379,
-// last_updated: '2022-05-17T21:45:51Z',
-// class_name: '3LEIC06',
-// composed_class_name: null,
-// },
-// {
-// day: 3,
-// duration: '2.0',
-// start_time: '8.5',
-// location: 'B306',
-// lesson_type: 'P',
-// teacher_acronym: 'LGBC',
-// course_unit_id: 484379,
-// last_updated: '2022-05-17T21:45:51Z',
-// class_name: '3LEIC07',
-// composed_class_name: null,
-// },
-// {
-// day: 2,
-// duration: '2.0',
-// start_time: '10.5',
-// location: 'B302',
-// lesson_type: 'P',
-// teacher_acronym: 'JBispo',
-// course_unit_id: 484379,
-// last_updated: '2022-05-17T21:45:51Z',
-// class_name: '3LEIC08',
-// composed_class_name: null,
-// },
-// {
-// day: 2,
-// duration: '2.0',
-// start_time: '8.5',
-// location: 'B204',
-// lesson_type: 'P',
-// teacher_acronym: 'TDRC',
-// course_unit_id: 484379,
-// last_updated: '2022-05-17T21:45:51Z',
-// class_name: null,
-// composed_class_name: 'COMP_2771',
-// },
-// ],
-// [
-// {
-// day: 1,
-// duration: '2.0',
-// start_time: '11',
-// location: 'B011',
-// lesson_type: 'T',
-// teacher_acronym: 'AAS',
-// course_unit_id: 484380,
-// last_updated: '2022-05-17T21:45:51Z',
-// class_name: null,
-// composed_class_name: 'COMP_2599',
-// },
-// {
-// day: 2,
-// duration: '2.0',
-// start_time: '14',
-// location: 'B306',
-// lesson_type: 'PL',
-// teacher_acronym: 'RPR',
-// course_unit_id: 484380,
-// last_updated: '2022-05-17T21:45:51Z',
-// class_name: null,
-// composed_class_name: 'COMP_2598',
-// },
-// {
-// day: 3,
-// duration: '2.0',
-// start_time: '8.5',
-// location: 'B103',
-// lesson_type: 'PL',
-// teacher_acronym: 'TCCM',
-// course_unit_id: 484380,
-// last_updated: '2022-05-17T21:45:51Z',
-// class_name: '3LEIC09',
-// composed_class_name: null,
-// },
-// {
-// day: 3,
-// duration: '2.0',
-// start_time: '10.5',
-// location: 'B302',
-// lesson_type: 'PL',
-// teacher_acronym: 'TCCM',
-// course_unit_id: 484380,
-// last_updated: '2022-05-17T21:45:51Z',
-// class_name: '3LEIC10',
-// composed_class_name: null,
-// },
-// ],
-// [
-// {
-// day: 4,
-// duration: '2.0',
-// start_time: '10.5',
-// location: 'B007',
-// lesson_type: 'T',
-// teacher_acronym: 'JGB+PF',
-// course_unit_id: 484381,
-// last_updated: '2022-05-17T21:45:51Z',
-// class_name: null,
-// composed_class_name: 'COMP_3110',
-// },
-// {
-// day: 4,
-// duration: '2.0',
-// start_time: '14',
-// location: 'B020',
-// lesson_type: 'T',
-// teacher_acronym: 'JGB+PF',
-// course_unit_id: 484381,
-// last_updated: '2022-05-17T21:45:51Z',
-// class_name: null,
-// composed_class_name: 'COMP_3112',
-// },
-// {
-// day: 2,
-// duration: '2.0',
-// start_time: '8.5',
-// location: 'B342',
-// lesson_type: 'L',
-// teacher_acronym: 'PFS+JGB',
-// course_unit_id: 484381,
-// last_updated: '2022-05-17T21:45:51Z',
-// class_name: '3LEIC01',
-// composed_class_name: null,
-// },
-// {
-// day: 2,
-// duration: '2.0',
-// start_time: '8.5',
-// location: 'B343',
-// lesson_type: 'L',
-// teacher_acronym: 'SCS1',
-// course_unit_id: 484381,
-// last_updated: '2022-05-17T21:45:51Z',
-// class_name: '3LEIC02',
-// composed_class_name: null,
-// },
-// {
-// day: 3,
-// duration: '2.0',
-// start_time: '8.5',
-// location: 'B205',
-// lesson_type: 'L',
-// teacher_acronym: 'PMAADO',
-// course_unit_id: 484381,
-// last_updated: '2022-05-17T21:45:51Z',
-// class_name: '3LEIC03',
-// composed_class_name: null,
-// },
-// {
-// day: 2,
-// duration: '2.0',
-// start_time: '10.5',
-// location: 'B202',
-// lesson_type: 'L',
-// teacher_acronym: 'AJMC',
-// course_unit_id: 484381,
-// last_updated: '2022-05-17T21:45:51Z',
-// class_name: '3LEIC04',
-// composed_class_name: null,
-// },
-// {
-// day: 2,
-// duration: '2.0',
-// start_time: '8.5',
-// location: 'B107',
-// lesson_type: 'L',
-// teacher_acronym: 'AJMC',
-// course_unit_id: 484381,
-// last_updated: '2022-05-17T21:45:51Z',
-// class_name: '3LEIC05',
-// composed_class_name: null,
-// },
-// {
-// day: 3,
-// duration: '2.0',
-// start_time: '10.5',
-// location: 'B202',
-// lesson_type: 'L',
-// teacher_acronym: 'AJMC',
-// course_unit_id: 484381,
-// last_updated: '2022-05-17T21:45:51Z',
-// class_name: '3LEIC06',
-// composed_class_name: null,
-// },
-// {
-// day: 3,
-// duration: '2.0',
-// start_time: '10.5',
-// location: 'B309',
-// lesson_type: 'L',
-// teacher_acronym: 'JGB',
-// course_unit_id: 484381,
-// last_updated: '2022-05-17T21:45:51Z',
-// class_name: '3LEIC07',
-// composed_class_name: null,
-// },
-// {
-// day: 3,
-// duration: '2.0',
-// start_time: '10.5',
-// location: 'B204',
-// lesson_type: 'L',
-// teacher_acronym: 'PMAADO',
-// course_unit_id: 484381,
-// last_updated: '2022-05-17T21:45:51Z',
-// class_name: '3LEIC08',
-// composed_class_name: null,
-// },
-// {
-// day: 3,
-// duration: '2.0',
-// start_time: '10.5',
-// location: 'B311',
-// lesson_type: 'L',
-// teacher_acronym: 'JGB',
-// course_unit_id: 484381,
-// last_updated: '2022-05-17T21:45:51Z',
-// class_name: '3LEIC09',
-// composed_class_name: null,
-// },
-// {
-// day: 3,
-// duration: '2.0',
-// start_time: '8.5',
-// location: 'B302',
-// lesson_type: 'L',
-// teacher_acronym: 'SCS1',
-// course_unit_id: 484381,
-// last_updated: '2022-05-17T21:45:51Z',
-// class_name: '3LEIC10',
-// composed_class_name: null,
-// },
-// ],
-]
-
-export const extraCoursesData: Course[] = [
-// {
-// id: 1,
-// course_id: 0,
-// course_unit_id: 484400,
-// course: 'L.EIC007',
-// name: 'Análise Matemática II',
-// acronym: 'AM II',
-// url: 'https://sigarra.up.pt/feup/pt/ucurr_geral.ficha_uc_view?pv_ocorrencia_id=484400',
-// course_unit_year: 1,
-// semester: 2,
-// year: 2021,
-// schedule_url: 'https://sigarra.up.pt/feup/pt/hor_geral.ucurr_view?pv_ocorrencia_id=484400 ',
-// last_updated: '2022-02-19T14:43:27Z',
-// },
-// {
-// id: 2,
-// course_id: 0,
-// course_unit_id: 484401,
-// course: 'L.EIC008',
-// name: 'Física I',
-// acronym: 'F I',
-// url: 'https://sigarra.up.pt/feup/pt/ucurr_geral.ficha_uc_view?pv_ocorrencia_id=484401',
-// course_unit_year: 1,
-// semester: 2,
-// year: 2021,
-// schedule_url: 'https://sigarra.up.pt/feup/pt/hor_geral.ucurr_view?pv_ocorrencia_id=484401 ',
-// last_updated: '2022-02-19T14:43:27Z',
-// },
-// {
-// id: 3,
-// course_id: 0,
-// course_unit_id: 484423,
-// course: 'L.EIC010',
-// name: 'Teoria da Computação',
-// acronym: 'TC',
-// url: 'https://sigarra.up.pt/feup/pt/ucurr_geral.ficha_uc_view?pv_ocorrencia_id=484423',
-// course_unit_year: 1,
-// semester: 2,
-// year: 2021,
-// schedule_url: 'https://sigarra.up.pt/feup/pt/hor_geral.ucurr_view?pv_ocorrencia_id=484423 ',
-// last_updated: '2022-02-19T14:43:27Z',
-// },
-// {
-// id: 4,
-// course_id: 0,
-// course_unit_id: 484399,
-// course: 'L.EIC006',
-// name: 'Arquitetura de Computadores',
-// acronym: 'AC',
-// url: 'https://sigarra.up.pt/feup/pt/ucurr_geral.ficha_uc_view?pv_ocorrencia_id=484399',
-// course_unit_year: 1,
-// semester: 2,
-// year: 2021,
-// schedule_url: 'https://sigarra.up.pt/feup/pt/hor_geral.ucurr_view?pv_ocorrencia_id=484399 ',
-// last_updated: '2022-02-19T14:43:27Z',
-// },
-// {
-// id: 5,
-// course_id: 0,
-// course_unit_id: 484422,
-// course: 'L.EIC009',
-// name: 'Programação',
-// acronym: 'P',
-// url: 'https://sigarra.up.pt/feup/pt/ucurr_geral.ficha_uc_view?pv_ocorrencia_id=484422',
-// course_unit_year: 1,
-// semester: 2,
-// year: 2021,
-// schedule_url: 'https://sigarra.up.pt/feup/pt/hor_geral.ucurr_view?pv_ocorrencia_id=484422 ',
-// last_updated: '2022-02-19T14:43:27Z',
-// },
-// {
-// id: 6,
-// course_id: 0,
-// course_unit_id: 484426,
-// course: 'L.EIC018',
-// name: 'Laboratório de Computadores',
-// acronym: 'LC',
-// url: 'https://sigarra.up.pt/feup/pt/ucurr_geral.ficha_uc_view?pv_ocorrencia_id=484426',
-// course_unit_year: 2,
-// semester: 2,
-// year: 2021,
-// schedule_url: 'https://sigarra.up.pt/feup/pt/hor_geral.ucurr_view?pv_ocorrencia_id=484426 ',
-// last_updated: '2022-02-19T14:43:27Z',
-// },
-// {
-// id: 7,
-// course_id: 0,
-// course_unit_id: 484427,
-// course: 'L.EIC019',
-// name: 'Linguagens e Tecnologias Web',
-// acronym: 'LTW',
-// url: 'https://sigarra.up.pt/feup/pt/ucurr_geral.ficha_uc_view?pv_ocorrencia_id=484427',
-// course_unit_year: 2,
-// semester: 2,
-// year: 2021,
-// schedule_url: 'https://sigarra.up.pt/feup/pt/hor_geral.ucurr_view?pv_ocorrencia_id=484427 ',
-// last_updated: '2022-02-19T14:43:27Z',
-// },
-// {
-// id: 8,
-// course_id: 0,
-// course_unit_id: 484424,
-// course: 'L.EIC016',
-// name: 'Desenho de Algoritmos',
-// acronym: 'DA',
-// url: 'https://sigarra.up.pt/feup/pt/ucurr_geral.ficha_uc_view?pv_ocorrencia_id=484424',
-// course_unit_year: 2,
-// semester: 2,
-// year: 2021,
-// schedule_url: 'https://sigarra.up.pt/feup/pt/hor_geral.ucurr_view?pv_ocorrencia_id=484424 ',
-// last_updated: '2022-02-19T14:43:27Z',
-// },
-// {
-// id: 9,
-// course_id: 0,
-// course_unit_id: 484425,
-// course: 'L.EIC017',
-// name: 'Engenharia de Software',
-// acronym: 'ES',
-// url: 'https://sigarra.up.pt/feup/pt/ucurr_geral.ficha_uc_view?pv_ocorrencia_id=484425',
-// course_unit_year: 2,
-// semester: 2,
-// year: 2021,
-// schedule_url: 'https://sigarra.up.pt/feup/pt/hor_geral.ucurr_view?pv_ocorrencia_id=484425 ',
-// last_updated: '2022-02-19T14:43:27Z',
-// },
-// {
-// id: 10,
-// course_id: 0,
-// course_unit_id: 484428,
-// course: 'L.EIC020',
-// name: 'Métodos Estatísticos',
-// acronym: 'ME',
-// url: 'https://sigarra.up.pt/feup/pt/ucurr_geral.ficha_uc_view?pv_ocorrencia_id=484428',
-// course_unit_year: 2,
-// semester: 2,
-// year: 2021,
-// schedule_url: 'https://sigarra.up.pt/feup/pt/hor_geral.ucurr_view?pv_ocorrencia_id=484428 ',
-// last_updated: '2022-02-19T14:43:27Z',
-// },
-// {
-// id: 11,
-// course_id: 0,
-// course_unit_id: 484381,
-// course: 'L.EIC028',
-// name: 'Computação Paralela e Distribuída',
-// acronym: 'CPD',
-// url: 'https://sigarra.up.pt/feup/pt/ucurr_geral.ficha_uc_view?pv_ocorrencia_id=484381',
-// course_unit_year: 3,
-// semester: 2,
-// year: 2021,
-// schedule_url: 'https://sigarra.up.pt/feup/pt/hor_geral.ucurr_view?pv_ocorrencia_id=484381 ',
-// last_updated: '2022-02-19T14:43:27Z',
-// },
-// {
-// id: 12,
-// course_id: 0,
-// course_unit_id: 484379,
-// course: 'L.EIC026',
-// name: 'Compiladores',
-// acronym: 'C',
-// url: 'https://sigarra.up.pt/feup/pt/ucurr_geral.ficha_uc_view?pv_ocorrencia_id=484379',
-// course_unit_year: 3,
-// semester: 2,
-// year: 2021,
-// schedule_url: 'https://sigarra.up.pt/feup/pt/hor_geral.ucurr_view?pv_ocorrencia_id=484379 ',
-// last_updated: '2022-02-19T14:43:27Z',
-// },
-// {
-// id: 13,
-// course_id: 0,
-// course_unit_id: 484380,
-// course: 'L.EIC027',
-// name: 'Computação Gráfica',
-// acronym: 'CG',
-// url: 'https://sigarra.up.pt/feup/pt/ucurr_geral.ficha_uc_view?pv_ocorrencia_id=484380',
-// course_unit_year: 3,
-// semester: 2,
-// year: 2021,
-// schedule_url: 'https://sigarra.up.pt/feup/pt/hor_geral.ucurr_view?pv_ocorrencia_id=484380 ',
-// last_updated: '2022-02-19T14:43:27Z',
-// },
-// {
-// id: 14,
-// course_id: 0,
-// course_unit_id: 484443,
-// course: 'L.EIC030',
-// name: 'Projeto Integrador',
-// acronym: 'PI',
-// url: 'https://sigarra.up.pt/feup/pt/ucurr_geral.ficha_uc_view?pv_ocorrencia_id=484443',
-// course_unit_year: 3,
-// semester: 2,
-// year: 2021,
-// schedule_url: 'https://sigarra.up.pt/feup/pt/hor_geral.ucurr_view?pv_ocorrencia_id=484443 ',
-// last_updated: '2022-02-19T14:43:27Z',
-// },
-// {
-// id: 15,
-// course_id: 0,
-// course_unit_id: 484442,
-// course: 'L.EIC029',
-// name: 'Inteligência Artificial',
-// acronym: 'IA',
-// url: 'https://sigarra.up.pt/feup/pt/ucurr_geral.ficha_uc_view?pv_ocorrencia_id=484442',
-// course_unit_year: 3,
-// semester: 2,
-// year: 2021,
-// schedule_url: 'https://sigarra.up.pt/feup/pt/hor_geral.ucurr_view?pv_ocorrencia_id=484442 ',
-// last_updated: '2022-02-19T14:43:27Z',
-// },
-]
diff --git a/src/utils/index.ts b/src/utils/index.ts
new file mode 100644
index 00000000..643bdc82
--- /dev/null
+++ b/src/utils/index.ts
@@ -0,0 +1,396 @@
+import config from '../config/prod.json'
+import dev_config from '../config/local.json'
+import { CourseInfo, CourseOption, SlotInfo, MultipleOptions, Option, PickedCourses, ProfessorInfo } from '../@types'
+import { type ClassValue, clsx } from 'clsx'
+import { twMerge } from 'tailwind-merge'
+import Plausible from 'plausible-tracker'
+const minHour = 8
+const maxHour = 23
+const dayNames = ['Dom', 'Seg', 'Ter', 'Qua', 'Qui', 'Sex', 'Sab']
+const monthNames = ['Jan', 'Fev', 'Mar', 'Abr', 'Mai', 'Jun', 'Jul', 'Ago', 'Set', 'Out', 'Nov', 'Dez']
+
+function cn(...inputs: ClassValue[]) {
+ return twMerge(clsx(inputs))
+}
+
+/**
+ * Get's the complete for a page.
+ * @param simplePath Path withot a prefix.
+ * @returns The complete path with the prefix.
+ */
+const getPath = (simplePath: string) => {
+ return config.pathPrefix + simplePath
+}
+
+const getDisplayDate = () => {
+ const date = new Date()
+ return `${dayNames[date.getDay()]}, ${date.getDate() + 1} ${monthNames[date.getMonth()]}`
+}
+
+const getSemester = () => {
+ //jan-jul --> 2º Semestre
+ const date = new Date()
+ const month = date.getMonth()
+
+ return month >= 0 && month <= 6 ? 2 : 1
+}
+
+const getSchoolYear = () => {
+ const date = new Date()
+ const month = date.getMonth()
+ const year = date.getFullYear()
+
+ return month >= 0 && month <= 6
+ ? `${year - 1}/${year.toString().slice(2, 4)}`
+ : `${year}/${(year + 1).toString().slice(2, 4)}`
+}
+
+const convertWeekday = (dayNumber: number) => {
+ if (dayNumber < 0 || dayNumber > 7) return null
+
+ const weekdays = ['2ªf', '3ªf', '4ªf', '5ªf', '6ªf', 'Sáb', 'Dom']
+ return weekdays[dayNumber]
+}
+
+const convertWeekdayLong = (dayNumber: number) => {
+ if (dayNumber < 0 || dayNumber > 7) return null
+
+ const weekdays = ['Segunda', 'Terça', 'Quarta', 'Quinta', 'Sexta', 'Sábado', 'Domingo']
+ return weekdays[dayNumber]
+}
+
+const convertHour = (hourNumber: string) => {
+ if (parseFloat(hourNumber) < 0 || parseFloat(hourNumber) > 24) return null
+
+ const split = hourNumber.split('.')
+ const hour = split[0].padStart(2, '0')
+ const minutes = split[1] === '0' || !split[1] ? '00' : '30'
+
+ return `${hour}:${minutes}`
+}
+
+const conflictsSeverity = (first: SlotInfo, second: SlotInfo) => {
+ return first.lesson_type === "TP" && second.lesson_type === "TP"
+}
+
+const schedulesConflict = (first: SlotInfo, second: SlotInfo) => {
+ if (first.day !== second.day) return false
+
+ const firstStart = first.start_time
+ const secondStart = second.start_time
+ const firstDuration = first.duration
+ const secondDuration = second.duration
+ const firstEnd = firstStart + firstDuration
+ const secondEnd = secondStart + secondDuration
+
+ return firstEnd > secondStart && firstStart < secondEnd;
+}
+
+const getClassDisplayText = (course: CourseInfo, picked_class_id: number) => {
+ const classInfo = course.classes && course.classes.find((classInfo) => classInfo.id === picked_class_id)
+ if (!classInfo) return 'Selecionar Opção...'
+
+ const classTitle = classInfo.name
+ //const professor_acronyms = classInfo.slots.flatMap((slot) => slot.professors.map((prof) => prof.acronym))
+ //const classTypes = classInfo.slots.map((slot) => slot.lesson_type)
+ //const weekdays = classInfo.slots.map((slot) => convertWeekday(slot.day))
+
+ return [classTitle].join(', ')
+}
+
+const getLessonBoxTime = (slot: SlotInfo) => {
+ return [convertHour(slot.start_time.toString()), convertHour(addHour(slot.start_time.toString(), slot.duration.toString()))].join('-')
+}
+
+const addHour = (hour1: string, hour2: string): string => {
+ return (parseFloat(hour1) + parseFloat(hour2)).toString()
+}
+
+const getLessonBoxStyles = (slotInfo: SlotInfo, maxHour: number, minHour: number) => {
+ const step = (maxHour - minHour) * 2
+ const top = (slotInfo.start_time - minHour) * 2
+ const length = slotInfo.duration * 2
+
+ return {
+ top: `${(top * 100) / step}%`,
+ left: `${(slotInfo.day * 100) / 6}%`,
+ height: `${length * (100 / step)}%`,
+ }
+}
+
+const getLessonTypeLongName = (type: string) => {
+ switch (type) {
+ case 'T':
+ return 'Aula Teórica'
+
+ case 'P':
+ return 'Aula Prática'
+
+ case 'TP':
+ return 'Aula Teórico-Prática'
+
+ case 'S':
+ return 'Seminário'
+
+ case 'TC':
+ return 'Teórica de Campo'
+
+ case 'PL':
+ return 'Aula Prática Laboratorial'
+
+ case 'OT':
+ return 'Aula de Orientação'
+
+ default:
+ return 'Aula Desconhecida'
+ }
+}
+
+const getClassTypeClassName = (type: string) => {
+ switch (type) {
+ case 'T':
+ return 'schedule-class-t'
+
+ case 'P':
+ return 'schedule-class-p'
+
+ case 'TP':
+ return 'schedule-class-tp'
+
+ case 'S':
+ return 'schedule-class-s'
+
+ case 'PL':
+ return 'schedule-class-pl'
+
+ case 'OT':
+ return 'schedule-class-ot'
+
+ case 'TC':
+ return 'schedule-class-tc'
+
+ default:
+ return 'schedule-class-o'
+ }
+}
+
+const getClassType = (type: string) => {
+ switch (type) {
+ case 'T': return 'Teórica';
+ case 'TP': return 'Teórico-Prática';
+ case 'PL': return 'Prática Laboratorial';
+ case 'OT': return 'Orientação Tutorial';
+ case 'S': return 'Seminário';
+ case 'P': return 'Prática';
+ case 'TC': return 'Teórica de Campo';
+ case 'O': return 'Outros';
+ case 'Teórica': return 'T';
+ case 'Teórico-Prática': return 'TP';
+ case 'Prática Laboratorial': return 'PL';
+ case 'Orientação Tutorial': return 'OT';
+ case 'Seminário': return 'S';
+ case 'Prática': return 'P';
+ case 'Teórica de Campo': return 'TC';
+ case 'Outros': return 'O';
+ }
+}
+
+const getCourseTeachers = (courseInfo: CourseInfo) => {
+ return courseInfo.classes.reduce((acc, classInfo) =>
+ [...acc, ...classInfo.slots.map(slot => slot.professors)],
+ []);
+}
+
+const convertCourseInfoToCourseOption = (course: CourseInfo): CourseOption => {
+ return {
+ course_id: course.id,
+ picked_class_id: null,
+ locked: false,
+ filteredTeachers: [],
+ hide: []
+ }
+}
+
+/**
+ * Considering that the yearCourses is sorted by the course_unit_year field in ascending order, the function groups the major courses by year.
+ * @param yearCourses All the courses in a major.
+ * @returns The courses grouped by year.
+ * @example input: [{ course: 1, year: 1 }, { course: 3, year: 1 }, { course: 2, year: 2 }]
+ * @example output: [[{ course: 1, year: 1 }, { course: 3, year: 1 }], [{ course: 2, year: 2 }]]
+ */
+const groupCoursesByYear = (yearCourses: CourseInfo[]): CourseInfo[][] => {
+ let majorCourses: CourseInfo[][] = []
+ let currYear = 0
+ for (let i = 0; i < yearCourses.length; i++) {
+ if (yearCourses[i].course_unit_year !== currYear) {
+ currYear += 1
+ majorCourses.push([yearCourses[i]])
+ } else {
+ majorCourses[currYear - 1].push(yearCourses[i])
+ }
+ }
+ return majorCourses
+}
+
+const isSubset = (set1, set2, same) => {
+ for (let elem1 of set1) {
+ let found = false
+ for (let elem2 of set2) {
+ if (same(elem1, elem2)) {
+ found = true
+ break
+ }
+ }
+ if (!found) return false
+ }
+ return true
+}
+
+const createDefaultCourseOption = (course: CourseInfo): CourseOption => {
+ return {
+ course_id: course.id,
+ picked_class_id: null,
+ locked: false,
+ filteredTeachers: [],
+ hide: []
+ }
+}
+
+const addCourseOption = (course: CourseInfo, multipleOptions: MultipleOptions): MultipleOptions => {
+ return multipleOptions.map((option) => {
+ const currentOption = createDefaultCourseOption(course);
+ currentOption.filteredTeachers = teacherIdsFromCourseInfo(course);
+ option.course_options.push(currentOption)
+ return option
+ })
+}
+
+const removeCourseOption = (course: CourseInfo, multipleOptions: MultipleOptions): MultipleOptions => (
+ multipleOptions.map((option) => {
+ option.course_options = option.course_options.filter((courseOption) => courseOption.course_id !== course.id)
+ return option
+ })
+)
+
+const removeAllCourseOptions = (multipleOptions: MultipleOptions): MultipleOptions => (
+ multipleOptions.map((option) => {
+ option.course_options = []
+ return option
+ })
+)
+
+const courseHasClassPicked = (course: CourseInfo, option: Option): CourseOption | null => {
+ const candidateOption = option.course_options.filter((courseOption) => courseOption.picked_class_id && (courseOption.course_id === course.course_unit_id));
+
+ if (!candidateOption) return null;
+
+ return candidateOption[0];
+}
+
+const replaceCourseOptions = (courses: CourseInfo[], multipleOptions: MultipleOptions): MultipleOptions => {
+ // const courseOptions = courses.map((course) => createDefaultCourseOption(course))
+
+ return multipleOptions.map((option) => {
+ const newCourseOptions = [];
+ for (const course of courses) {
+ const existingOption = courseHasClassPicked(course, option);
+ if (existingOption) {
+ newCourseOptions.push({ ...existingOption });
+ } else {
+ newCourseOptions.push(createDefaultCourseOption(course));
+ }
+ }
+ // We have to use JSON.parse as well as JSON.stringify in order to create a copy for each option. Otherwise, they would
+ // all have the same reference to the same object
+ option.course_options = [...JSON.parse(JSON.stringify(newCourseOptions))]
+ return option
+ })
+}
+
+const getAllPickedSlots = (selected_courses: PickedCourses, option: Option) => {
+ return option.course_options.flatMap((course) => {
+ if (!course.picked_class_id) return []
+ const courseInfo = selected_courses.find((selected_course) => selected_course.id === course.course_id)
+ const classInfo = courseInfo.classes.find((classInfo) => classInfo.id === course.picked_class_id)
+
+ return classInfo.slots
+ })
+}
+
+const teachersFromCourseInfo = (courseInfo: CourseInfo): ProfessorInfo[] => {
+ const classes = courseInfo.classes;
+ if (!classes) return [];
+
+ return courseInfo.classes.flatMap((c) => c.slots.flatMap((s) => s.professors));
+}
+
+const uniqueTeachersFromCourseInfo = (courseInfo: CourseInfo): ProfessorInfo[] => {
+ const uniqueIds = new Set();
+ return teachersFromCourseInfo(courseInfo).filter(item => {
+ if (!uniqueIds.has(item.id)) {
+ uniqueIds.add(item.id);
+ return true;
+ }
+ return false;
+ });
+}
+
+const teacherIdsFromCourseInfo = (courseInfo: CourseInfo): number[] => {
+ const teacherIds = [];
+ const uniqueTeachers = uniqueTeachersFromCourseInfo(courseInfo);
+
+ uniqueTeachers.forEach((teacher: ProfessorInfo) => {
+ teacherIds.push(teacher.id);
+ });
+
+ return teacherIds;
+}
+
+const scrollToTop = () => {
+ if (!window.location.href.split('#')[1]) document.getElementById('layout').scrollIntoView();
+}
+
+const plausible = Plausible({
+ domain: import.meta.env.VITE_APP_PLAUSIBLE_DOMAIN,
+ apiHost: import.meta.env.VITE_APP_PLAUSIBLE_HOST,
+ trackLocalhost: !Number(import.meta.env.VITE_APP_PROD),
+})
+
+export {
+ config,
+ dev_config,
+ getPath,
+ minHour,
+ maxHour,
+ dayNames,
+ monthNames,
+ getDisplayDate,
+ getSemester,
+ getSchoolYear,
+ convertWeekday,
+ convertWeekdayLong,
+ convertHour,
+ schedulesConflict,
+ getClassDisplayText,
+ getLessonBoxTime,
+ getLessonBoxStyles,
+ getClassTypeClassName,
+ getLessonTypeLongName,
+ getCourseTeachers,
+ cn,
+ groupCoursesByYear,
+ isSubset,
+ addCourseOption,
+ removeCourseOption,
+ replaceCourseOptions,
+ getAllPickedSlots,
+ getClassType,
+ removeAllCourseOptions,
+ convertCourseInfoToCourseOption,
+ conflictsSeverity,
+ teachersFromCourseInfo,
+ uniqueTeachersFromCourseInfo,
+ teacherIdsFromCourseInfo,
+ scrollToTop,
+ plausible
+}
diff --git a/src/utils/utils.ts b/src/utils/utils.ts
deleted file mode 100644
index 21ad2099..00000000
--- a/src/utils/utils.ts
+++ /dev/null
@@ -1,230 +0,0 @@
-import config from '../config/prod.json'
-import dev_config from '../config/local.json'
-import { CourseOption, CourseSchedule, Lesson } from '../@types'
-import { type ClassValue, clsx } from "clsx"
-import { twMerge } from "tailwind-merge"
-const minHour = 8
-const maxHour = 23
-const dayNames = ['Dom', 'Seg', 'Ter', 'Qua', 'Qui', 'Sex', 'Sab']
-const monthNames = ['Jan', 'Fev', 'Mar', 'Abr', 'Mai', 'Jun', 'Jul', 'Ago', 'Set', 'Out', 'Nov', 'Dez']
-
-function cn(...inputs: ClassValue[]) {
- return twMerge(clsx(inputs))
-}
-
-/**
- * Get's the complete for a page.
- * @param simplePath Path withot a prefix.
- * @returns The complete path with the prefix.
- */
-const getPath = (simplePath: string) => {
-
- return config.pathPrefix + simplePath
-}
-
-const getDisplayDate = () => {
- const date = new Date()
- return `${dayNames[date.getDay()]}, ${date.getDate() + 1} ${monthNames[date.getMonth()]}`
-}
-
-const getSemester = () => {
- //jan-jul --> 2º Semestre
- const date = new Date()
- const month = date.getMonth()
-
- return month >= 0 && month <= 6 ? 2 : 1
-}
-
-const getSchoolYear = () => {
- const date = new Date()
- const month = date.getMonth()
- const year = date.getFullYear()
-
- return month >= 0 && month <= 6
- ? `${year - 1}/${year.toString().slice(2, 4)}`
- : `${year}/${(year + 1).toString().slice(2, 4)}`
-}
-
-const convertWeekday = (dayNumber: number) => {
- if (dayNumber < 0 || dayNumber > 7) return null
-
- const weekdays = ['2ªf', '3ªf', '4ªf', '5ªf', '6ªf', 'Sab', 'Dom']
- return weekdays[dayNumber]
-}
-
-const convertWeekdayLong = (dayNumber: number) => {
- if (dayNumber < 0 || dayNumber > 7) return null
-
- const weekdays = ['Segunda', 'Terça', 'Quarta', 'Quinta', 'Sexta', 'Sábado', 'Domingo']
- return weekdays[dayNumber]
-}
-
-const convertHour = (hourNumber: string) => {
- if (parseFloat(hourNumber) < 0 || parseFloat(hourNumber) > 24) return null
-
- const split = hourNumber.split('.')
- const hour = split[0].padStart(2, '0')
- const minutes = split[1] === '0' || !split[1] ? '00' : '30'
-
- return `${hour}:${minutes}`
-}
-
-const timesCollide = (first: CourseSchedule, second: CourseSchedule) => {
- if (first.day !== second.day) return false
- return parseFloat(second.start_time) < parseFloat(first.start_time) + parseFloat(first.duration)
-}
-
-const schedulesConflict = (first, second) => {
- if (first.day !== second.day) return false;
-
- const firstStart = parseFloat(first.start_time);
- const secondStart = parseFloat(second.start_time);
- const firstDuration = parseFloat(first.duration);
- const secondDuration = parseFloat(second.duration);
- const firstEnd = firstStart + firstDuration;
- const secondEnd = secondStart + secondDuration;
-
- return (firstStart < secondStart && firstEnd > secondStart) || (firstStart >= secondStart && firstStart < secondEnd);
-}
-
-const getScheduleOptionDisplayText = (option: CourseSchedule | null) => {
- // prioritize single class name
- const classTitle = option.class_name !== null ? option.class_name : option.composed_class_name
- const professor_acronyms = option.professor_information.map(prof_info => prof_info.acronym)
- return [classTitle, professor_acronyms, convertWeekday(option.day), getLessonBoxTime(option)].join(', ')
-}
-
-const getLessonBoxTime = (schedule: CourseSchedule) => {
- return [convertHour(schedule.start_time), convertHour(addHour(schedule.start_time, schedule.duration))].join('-')
-}
-
-const addHour = (hour1: string, hour2: string): string => {
- return (parseFloat(hour1) + parseFloat(hour2)).toString()
-}
-
-const getLessonBoxStyles = (lesson: Lesson, maxHour: number, minHour: number) => {
- const step = (maxHour - minHour) * 2
- const top = (parseFloat(lesson.schedule.start_time) - minHour) * 2
- const length = parseFloat(lesson.schedule.duration) * 2
-
- return {
- top: `${(top * 100) / step}%`,
- left: `${(lesson.schedule.day * 100) / 6}%`,
- height: `${length * (100 / step)}%`,
- }
-}
-
-const getLessonTypeLongName = (type: string) => {
- switch (type) {
- case 'T':
- return 'Aula Teórica'
-
- case 'P':
- return 'Aula Prática'
-
- case 'TP':
- return 'Aula Teórico-Prática'
-
- case 'S':
- return 'Seminário'
-
- case 'TC':
- return 'Teórica de Campo'
-
- case 'PL':
- return 'Aula Prática Laboratorial'
-
- case 'OT':
- return 'Aula de Orientação'
-
- default:
- return 'Aula Desconhecida'
- }
-}
-
-const getClassTypeClassName = (type: string) => {
- switch (type) {
- case 'T':
- return 'schedule-class-t'
-
- case 'P':
- return 'schedule-class-p'
-
- case 'TP':
- return 'schedule-class-tp'
-
- case 'S':
- return 'schedule-class-s'
-
- case 'PL':
- return 'schedule-class-pl'
-
- case 'OT':
- return 'schedule-class-ot'
-
- case 'TC':
- return 'schedule-class-tc'
-
- default:
- return 'schedule-class-o'
- }
-}
-
-const getCourseTeachers = (courseOption: CourseOption) => {
- let teachers = []
- courseOption.schedules.forEach((schedule, idx) => {
- if (schedule.lesson_type !== 'T') {
- schedule.professor_information.forEach(prof_info => {
- if (!teachers.some(other => other.acronym === prof_info.acronym)) {
- teachers.push(prof_info);
- }
- });
- }
- })
-
- return teachers
-}
-
-
-const removeDuplicatesFromCourseOption = (courses: CourseOption[]): CourseOption[] => {
- console.log(courses)
- if (!courses) return []
-
- let frequency: Map
= new Map()
- let newCourseOptions: CourseOption[] = []
-
- for (let courseOption of courses) {
- if (!frequency.has(courseOption.course.info.id)) {
- newCourseOptions.push(courseOption)
- frequency.set(courseOption.course.info.id, 1)
- }
- }
-
- return newCourseOptions
-}
-
-export {
- config,
- dev_config,
- getPath,
- minHour,
- maxHour,
- dayNames,
- monthNames,
- getDisplayDate,
- getSemester,
- getSchoolYear,
- convertWeekday,
- convertWeekdayLong,
- convertHour,
- timesCollide,
- schedulesConflict,
- getScheduleOptionDisplayText,
- getLessonBoxTime,
- getLessonBoxStyles,
- getClassTypeClassName,
- getLessonTypeLongName,
- getCourseTeachers,
- cn,
- removeDuplicatesFromCourseOption
-}
diff --git a/tailwind.config.js b/tailwind.config.js
index adc5af0c..52d258bb 100644
--- a/tailwind.config.js
+++ b/tailwind.config.js
@@ -3,7 +3,7 @@ const colors = require('tailwindcss/colors')
module.exports = {
darkMode : 'class',
- content : ['./src/**/*.{js,jsx,ts,tsx}', './src/styles/safelist.txt'],
+ content : ['./index.html', './src/**/*.{js,jsx,ts,tsx}', './src/styles/safelist.txt'],
theme : {
extend : {
colors : {
@@ -87,12 +87,16 @@ module.exports = {
from : {height : 'var(--radix-accordion-content-height)'},
to : {height : '0'},
},
+ shine : {
+ '100%' : {left : '125%'},
+ },
},
animation : {
'accordion-down' : 'accordion-down 0.2s ease-out',
'accordion-up' : 'accordion-up 0.2s ease-out',
fade : 'fade 1000ms ease-in-out infinite',
wiggle : 'wiggle 700ms ease-in-out',
+ shine : 'shine 1s',
'wiggle-infinity' : 'wiggle 700ms infinite ease-in-out',
},
backgroundSize : {
diff --git a/tsconfig.json b/tsconfig.json
index 4b1a1b54..273a2e03 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -12,9 +12,14 @@
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
+ "types": ["vite/client"],
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx"
},
- "include": ["./src/declaration.d.ts", "./src/**/*.ts", "./src/**/*.tsx"]
+ "include": [
+ "./src/declaration.d.ts",
+ "./src/**/*.ts",
+ "./src/**/*.tsx",
+ ],
}
diff --git a/vite.config.ts b/vite.config.ts
new file mode 100644
index 00000000..d8d7cafe
--- /dev/null
+++ b/vite.config.ts
@@ -0,0 +1,13 @@
+import { defineConfig } from 'vite'
+import react from '@vitejs/plugin-react'
+import viteTsconfigPaths from 'vite-tsconfig-paths'
+
+export default defineConfig({
+ plugins: [react(), viteTsconfigPaths()],
+ server: {
+ port: 3100,
+ },
+ build: {
+ outDir: 'build'
+ }
+})