;
+
+ console.log('passed basket');
+ console.log(basket);
+ console.log(`basketgroups`);
+ console.log(basketGroups);
+ const groupsMapped = basketGroups.map(({ id, day, lecturer, room, time }) => ({
+ id,
+ day,
+ lecturer,
+ room,
+ eventRow: groupTimeToEventRowMapping[time],
+ }));
+ setChoosenGroupsMappedToEvents(groupsMapped);
+ }
+ mapGroupTimeToEventRow(basket);
+ }, [basket]);
+
+ return (
+
+ {[...Array(6)].map((_, index) => (
+ {
+ return group.eventRow === index;
+ })}
+ indexRow={index}
+ cellTop={
+ index == 3
+ ? cellTop + (25 + 80 * index)
+ : index < 3
+ ? cellTop + (12 + 80 * index)
+ : cellTop + (25 + 80 * index)
+ }
+ cellWidth={cellWidth}
+ />
+ ))}
+
+ );
+};
diff --git a/src/components/SchedulerRow.tsx b/src/components/SchedulerRow.tsx
new file mode 100644
index 0000000..42fd6d6
--- /dev/null
+++ b/src/components/SchedulerRow.tsx
@@ -0,0 +1,48 @@
+import React from 'react';
+import { Group } from '../types';
+import styled from 'styled-components';
+
+interface SchedulerEventProps {
+ eventIndex: number;
+ cellTop: number;
+ cellWidth: number;
+}
+
+const SchedulerEvent = styled.div`
+ position: absolute;
+ top: ${(props) => props.cellTop}px;
+ left: ${(props) => props.cellWidth + 5 + props.cellWidth * props.eventIndex}px;
+ width: ${(props) => (props.cellWidth * 2) / 3}px;
+ height: 69px;
+ background-color: lightblue;
+ z-index: 2;
+`;
+
+interface SchedulerRowProps {
+ groups: Array;
+ indexRow: number;
+ cellTop: number;
+ cellWidth: number;
+}
+
+export const SchedulerRow = ({ groups, indexRow, cellTop, cellWidth }: SchedulerRowProps) => {
+
+
+ return (
+ <>
+ {[...Array(5)].map((_, eventIndex) => (
+
+ {groups.map((group, index) =>
+ group.day === eventIndex && {groups[index]?.lecturer}
,
+ )}
+
+ ))}
+ >
+ );
+};
diff --git a/src/components/Topbar.tsx b/src/components/Topbar.tsx
new file mode 100644
index 0000000..c7cfcb7
--- /dev/null
+++ b/src/components/Topbar.tsx
@@ -0,0 +1,117 @@
+import React, { useState, MouseEvent } from 'react';
+import Transfer from '../assets/transfer.png';
+import Search from '../assets/search.svg';
+import UK from '../assets/UK.png';
+import PL from '../assets/PL.png';
+import User from '../assets/user.png';
+import CloseIcon from '../assets/close.svg';
+import { Profile } from './Profile';
+import { Dropdown } from './Dropdown';
+import styled from 'styled-components';
+
+const TopbarTextStyled = styled.div`
+ @media only screen and (max-width: 670px) {
+ display: none;
+ }
+`;
+
+const Topbar = styled.div`
+ background-color: #ffdc61;
+ height: 80px;
+ padding: 5px;
+ font-family: comic sans MS;
+ font-size: 24px;
+ font-weight: bold;
+ display: flex;
+ justify-content: space-between;
+`;
+
+const TopbarLogoWrapperStyled = styled.div`
+ display: flex;
+ align-items: center;
+ flex-grow: 0.5;
+ justify-content: flex-start;
+`;
+
+const TopbarLogoStyled = styled.img`
+ width: 80px;
+ height: 80px;
+ @media only screen and (max-width: 670px) {
+ width: 60px;
+ height: 60px;
+ }
+`;
+
+const TopbarInputStyled = styled.div`
+ width: 70%;
+ display: flex;
+ flex-grow: 3;
+`;
+
+const TopbarInputFieldStyled = styled.div`
+ width: 96%;
+ margin-top: 10px;
+`;
+
+const TopbarInputIconStyled = styled.img`
+ width: 35px;
+ @media only screen and (max-width: 670px) {
+ width: 25px;
+ }
+ cursor: pointer;
+`;
+
+const TopbarIcon = styled.img`
+ width: 50px;
+ cursor: pointer;
+ @media only screen and (max-width: 670px) {
+ width: 35px;
+ }
+`;
+
+const TopbarIconBox = styled.div`
+ display: flex;
+ align-items: center;
+ justify-content: space-around;
+ flex-grow: 1.5;
+`;
+
+interface TopbarProps {
+ handleTransfer: (e: MouseEvent) => void;
+}
+
+export default function ({ handleTransfer }: TopbarProps) {
+ const [clearInput, setClearInput] = useState(false);
+ const [isPolish, setIsPolish] = useState(false);
+ const [anchorEl, setAnchorEl] = useState(null);
+
+ const onLangChange = () => setIsPolish(!isPolish);
+
+ const handleProfile = (event: MouseEvent) => setAnchorEl(event.currentTarget);
+
+ const handleClose = () => setAnchorEl(null);
+
+ const handleClearInput = () => setClearInput(!clearInput);
+
+ return (
+
+
+
+ plan na plan
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/src/components/Transfer.tsx b/src/components/Transfer.tsx
new file mode 100644
index 0000000..58442b4
--- /dev/null
+++ b/src/components/Transfer.tsx
@@ -0,0 +1,115 @@
+import React from 'react';
+import Modal from '@material-ui/core/Modal';
+import Fade from '@material-ui/core/Fade';
+import Input from '@material-ui/core/Input';
+import { makeStyles } from '@material-ui/core/styles';
+import styled from 'styled-components';
+
+interface TransferProps {
+ handleClose: (e: React.MouseEvent) => void;
+ isOpen: boolean;
+}
+
+const useStyles = makeStyles({
+ wrapper: {
+ display: 'flex',
+ justifyContent: 'center',
+ textAlign: 'center',
+ alignItems: 'center',
+ },
+});
+
+const TransferStyled = styled.div`
+ display: flex;
+
+ flex-direction: row;
+
+ outline: none;
+ min-width: 35%;
+ height: 70%;
+ padding-top: 40px;
+ background: #006b96;
+ box-shadow: 0px 0px 0px 4px #006b96;
+ border: 4px solid #ffc400;
+ margin: 0 auto;
+ border-top-left-radius: 5px;
+ border-bottom-right-radius: 5px;
+ text-transform: uppercase;
+ letter-spacing: 0.3ch;
+`;
+
+const TransferGiveStyled = styled.div`
+ flex-grow: 1;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+`;
+
+const TransferReceiveStyled = styled.div`
+ flex-grow: 1;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+`;
+
+const TransferTextStyled = styled.div`
+ font-family: Lato;
+ font-size: 30px;
+ margin-bottom: 10px;
+`;
+
+const TransferInputStyled = styled.div`
+ width: 250px;
+ height: 25px;
+ padding: 10px;
+ font-size: 24px;
+ transition-duration: 0.3s;
+ input::placeholder {
+ color: black;
+ font-weight: bold;
+ text-align: center;
+ }
+`;
+
+export const Transfer = ({ handleClose, isOpen }: TransferProps) => {
+ const classes = useStyles();
+
+ return (
+
+
+
+
+
+ Oddam
+
+ {' '}
+
+
+
+
+ Przyjmę
+
+ {' '}
+
+
+
+
+
+
+
+ );
+};
diff --git a/src/constants/index.ts b/src/constants/index.ts
new file mode 100644
index 0000000..ad14654
--- /dev/null
+++ b/src/constants/index.ts
@@ -0,0 +1,22 @@
+export const days = [
+ "",
+ "poniedziałek",
+ "wtorek",
+ "środa",
+ "czwartek",
+ "piątek",
+];
+export const hours = [
+ "8:00",
+ "9:00",
+ "10:00",
+ "11:00",
+ "12:00",
+ "13:00",
+ "14:00",
+ "15:00",
+ "16:00",
+ "17:00",
+ "18:00",
+ "19:00",
+];
diff --git a/src/contexts/CASProvider.tsx b/src/contexts/CASProvider.tsx
new file mode 100644
index 0000000..a983aff
--- /dev/null
+++ b/src/contexts/CASProvider.tsx
@@ -0,0 +1,47 @@
+import React, { useState, useEffect } from 'react';
+import { User } from '../types';
+
+export interface CASContext {
+ user: User | null;
+ logout: () => void;
+}
+
+export const CASContext = React.createContext(null);
+
+export interface CASProviderProps {
+ children: React.ReactNode;
+}
+
+export const CASProvider = ({ children }: CASProviderProps) => {
+ const [user, setUser] = useState(null);
+
+ useEffect(() => {
+ login();
+ }, []);
+
+ function login() {
+ const urlParams = new URLSearchParams(window.location.search);
+ const ticket = urlParams.get('ticket');
+
+ if (!ticket) {
+ redirectToCASLoginService();
+ }
+ if (ticket) {
+ setUser({ ...user, ticket: ticket });
+ }
+ }
+
+ function logout() {
+ redirectToCASLogoutService();
+ }
+
+ function redirectToCASLogoutService() {
+ window.location.replace(`https://cas.amu.edu.pl/cas/logout?service=${window.origin}`);
+ }
+
+ function redirectToCASLoginService() {
+ window.location.replace(`https://cas.amu.edu.pl/cas/login?service=${window.origin}&locale=pl`);
+ }
+
+ return {children};
+};
diff --git a/src/contexts/CoursesProvider.tsx b/src/contexts/CoursesProvider.tsx
new file mode 100644
index 0000000..7b49128
--- /dev/null
+++ b/src/contexts/CoursesProvider.tsx
@@ -0,0 +1,63 @@
+import React, { useState, createContext, useEffect } from 'react';
+import { Course, Group, Basket, GroupType } from '../types';
+import axios from 'axios';
+
+interface CourseContext {
+ courses: Array;
+ basket: Array;
+ addToBasket: (courses: Basket) => void;
+ addGroup: (group: Group, id: number) => void;
+}
+export const coursesContext = createContext(null);
+
+interface CoursesProviderProps {
+ children: React.ReactNode;
+}
+
+export const CoursesProvider = ({ children }: CoursesProviderProps) => {
+ //fetch courses with groups
+ const [courses, setCourses] = useState>([]);
+ const [basket, setBasket] = useState>([]);
+
+ const addToBasket = (course: Basket) => setBasket([...basket, course]);
+
+ useEffect(() => {
+ console.log('BASKET');
+ console.log(basket);
+ }, [basket]);
+
+ //immutability
+
+ const addGroup = (choosenGroup: Group, id: number) => {
+ const basketCourse = basket.filter((course) => course.id === id)[0];
+ const type = choosenGroup.type;
+ if (type === GroupType.CLASS) {
+ setBasket(
+ basket.map((basket) => (basket.id === basketCourse.id ? { ...basket, classes: choosenGroup } : basket)),
+ );
+ } else if (type === GroupType.LECTURE) {
+ setBasket(
+ basket.map((basket) => (basket.id === basketCourse.id ? { ...basket, lecture: choosenGroup } : basket)),
+ );
+ }
+ };
+
+ useEffect(() => {
+ const fetchData = async () => {
+ const { data: courses } = await axios.get(`${process.env.REACT_APP_API_URL}/getCourses`);
+
+ for (const course of courses) {
+ const { data: groups } = await axios.get(`${process.env.REACT_APP_API_URL}/getCourseGroups?id=${course.id}`);
+ //porozmawiać z Filipem, żeby odrobinę przerobił endpoint
+ course.groups = groups;
+ }
+
+ setCourses(courses);
+ };
+ fetchData();
+ }, []);
+
+ return (
+ {children}
+ );
+};
diff --git a/src/contexts/reducers.ts b/src/contexts/reducers.ts
new file mode 100644
index 0000000..90bf96a
--- /dev/null
+++ b/src/contexts/reducers.ts
@@ -0,0 +1,29 @@
+// import { Group, Course } from '../types';
+
+export enum Types {
+ addToBasket = 'ADD_CHOOSEN_COURSE',
+ removeChoosenCourse = 'REMOVE_CHOOSEN_COURSE',
+ addGroup = 'ADD_CHOOSEN_GROUP',
+ removeChoosenGroup = 'REMOVE_CHOOSEN_GROUP',
+}
+
+// type ChoosenCoursesPayload = {
+// [Types.addToBasket]: {};
+// };
+
+// type ChoosenGroupsPayload = {
+// [Types.Create]: {
+// id: number;
+// name: string;
+// price: number;
+// };
+// };
+
+// export const choosenGroupsReducer = (state, action) => {
+// switch (action.type) {
+// case Types.addGroup:
+// return add;
+// }
+// };
+
+//https://dev.to/elisealcala/react-context-with-usereducer-and-typescript-4obm
diff --git a/src/index.tsx b/src/index.tsx
new file mode 100644
index 0000000..53cd61e
--- /dev/null
+++ b/src/index.tsx
@@ -0,0 +1,18 @@
+import React from 'react';
+import ReactDOM from 'react-dom';
+import { App } from './components/App';
+import { CASProvider } from './contexts/CASProvider';
+import { CoursesProvider } from './contexts/CoursesProvider';
+import { GlobalStyles } from './styles/GlobalStyles';
+
+ReactDOM.render(
+ <>
+
+
+
+
+
+
+ >,
+ document.getElementById('root'),
+);
diff --git a/src/styles/GlobalStyles.ts b/src/styles/GlobalStyles.ts
new file mode 100644
index 0000000..4f68eaa
--- /dev/null
+++ b/src/styles/GlobalStyles.ts
@@ -0,0 +1,20 @@
+import { createGlobalStyle } from 'styled-components';
+
+export const GlobalStyles = createGlobalStyle`
+ *, *::before, *::after {
+ box-sizing: border-box;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ }
+
+ body {
+ margin: 0;
+ padding: 0;
+ line-height: 24px;
+
+ }
+
+ body::-webkit-scrollbar {
+ display: none;
+ }
+`;
diff --git a/src/types/index.ts b/src/types/index.ts
new file mode 100644
index 0000000..cdec17f
--- /dev/null
+++ b/src/types/index.ts
@@ -0,0 +1,33 @@
+export enum GroupType {
+ LECTURE = 'LECTURE',
+ CLASS = 'CLASS',
+}
+
+export interface Basket {
+ id: number;
+ name: string;
+ lecture: Group | null;
+ classes: Group | null;
+}
+
+export interface Group {
+ id: number;
+ day: number;
+ time: string;
+ lecturer: string;
+ room: string;
+ type: GroupType;
+ capacity?: number;
+}
+
+export interface Course {
+ id: number;
+ name: string;
+ groups: Array;
+}
+
+export interface User {
+ name?: string;
+ surname?: string;
+ ticket: string | null;
+}
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 0000000..af10394
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,19 @@
+{
+ "compilerOptions": {
+ "target": "es5",
+ "lib": ["dom", "dom.iterable", "esnext"],
+ "allowJs": true,
+ "skipLibCheck": true,
+ "esModuleInterop": true,
+ "allowSyntheticDefaultImports": true,
+ "strict": true,
+ "forceConsistentCasingInFileNames": true,
+ "module": "esnext",
+ "moduleResolution": "node",
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "noEmit": true,
+ "jsx": "react"
+ },
+ "include": ["src"]
+}