diff --git a/src/api/dto/course.ts b/src/api/dto/course.ts new file mode 100644 index 0000000..8b13f1f --- /dev/null +++ b/src/api/dto/course.ts @@ -0,0 +1,23 @@ +import { Course, Identifiable } from "@/data"; +import { Transformer } from "@/serialization"; + +export interface CourseDTO extends Identifiable { + name: string; +} + +export const courseDtoTransformer: Transformer = { + reverseTransform(subject: Course, context: undefined): CourseDTO { + return { + id: subject.id, + name: subject.name, + }; + }, + transform(subject: CourseDTO, context: undefined): Course { + return { + id: subject.id, + name: subject.name, + desiredSemesters: [], + possibleProgramEntries: [], // todo + }; + } +} diff --git a/src/api/dto/edition.ts b/src/api/dto/edition.ts new file mode 100644 index 0000000..94c3101 --- /dev/null +++ b/src/api/dto/edition.ts @@ -0,0 +1,57 @@ +import { Identifiable } from "@/data"; +import { CourseDTO, courseDtoTransformer } from "@/api/dto/course"; +import { OneWayTransformer, Transformer } from "@/serialization"; +import { Edition } from "@/data/edition"; +import moment from "moment"; +import { Subset } from "@/helpers"; + +export interface EditionDTO extends Identifiable { + editionStart: string, + editionFinish: string, + reportingStart: string, + course: CourseDTO, +} + +export interface EditionTeaserDTO extends Identifiable { + editionStart: string, + editionFinish: string, + courseName: string, +} + +export const editionTeaserDtoTransformer: OneWayTransformer> = { + transform(subject: EditionTeaserDTO, context?: undefined): Subset { + return { + id: subject.id, + startDate: moment(subject.editionStart), + endDate: moment(subject.editionFinish), + course: { + name: subject.courseName, + } + } + } +} + +export const editionDtoTransformer: Transformer = { + reverseTransform(subject: Edition, context: undefined): EditionDTO { + return { + id: subject.id, + editionFinish: subject.endDate.toISOString(), + editionStart: subject.startDate.toISOString(), + course: courseDtoTransformer.reverseTransform(subject.course), + reportingStart: subject.reportingStart.toISOString(), + }; + }, + transform(subject: EditionDTO, context: undefined): Edition { + return { + id: subject.id, + course: courseDtoTransformer.transform(subject.course), + startDate: moment(subject.editionStart), + endDate: moment(subject.editionFinish), + minimumInternshipHours: 40, + maximumInternshipHours: 160, + proposalDeadline: moment(subject.reportingStart), + reportingStart: moment(subject.reportingStart), + reportingEnd: moment(subject.reportingStart).add(1, 'month'), + }; + } +} diff --git a/src/api/dto/page.ts b/src/api/dto/page.ts new file mode 100644 index 0000000..390fa03 --- /dev/null +++ b/src/api/dto/page.ts @@ -0,0 +1,40 @@ +import { Identifiable } from "@/data"; +import { Page } from "@/data/page"; +import { Transformer } from "@/serialization"; + +export interface PageDTO extends Identifiable { + accessName: string; + title: string; + titleEng: string; + content: string; + contentEng: string; +} + +export const pageDtoTransformer: Transformer = { + reverseTransform(subject: Page, context: undefined): PageDTO { + return { + id: subject.id, + accessName: subject.slug, + content: subject.content.pl, + contentEng: subject.content.en, + title: subject.title.pl, + titleEng: subject.title.en, + } + }, + transform(subject: PageDTO, context: undefined): Page { + return { + slug: subject.accessName, + id: subject.id, + content: { + pl: subject.content, + en: subject.contentEng + }, + title: { + pl: subject.title, + en: subject.titleEng + }, + }; + } +} + +export default pageDtoTransformer; diff --git a/src/api/dto/student.ts b/src/api/dto/student.ts new file mode 100644 index 0000000..269e1aa --- /dev/null +++ b/src/api/dto/student.ts @@ -0,0 +1,34 @@ +import { Identifiable, Student } from "@/data"; +import { Transformer } from "@/serialization"; + +export interface StudentDTO extends Identifiable { + albumNumber: number, + course: any, + email: string, + firstName: string, + lastName: string, + semester: number, +} + +export const studentDtoTransfer: Transformer = { + reverseTransform(subject: Student, context: undefined): StudentDTO { + return { + albumNumber: subject.albumNumber, + course: subject.course, + email: subject.email, + firstName: subject.name, + lastName: subject.surname, + semester: subject.semester + }; + }, + transform(subject: StudentDTO, context: undefined): Student { + return { + albumNumber: subject.albumNumber, + course: subject.course, + email: subject.email, + name: subject.firstName, + semester: subject.semester, + surname: subject.lastName + }; + } +} diff --git a/src/api/edition.ts b/src/api/edition.ts index bce8982..6164634 100644 --- a/src/api/edition.ts +++ b/src/api/edition.ts @@ -1,16 +1,16 @@ import { axios } from "@/api/index"; import { Edition } from "@/data/edition"; -import { sampleEdition } from "@/provider/dummy"; -import { delay } from "@/helpers"; +import { prepare } from "@/routing"; +import { EditionDTO, editionDtoTransformer, editionTeaserDtoTransformer } from "@/api/dto/edition"; const EDITIONS_ENDPOINT = "/editions"; const EDITION_INFO_ENDPOINT = "/editions/:key"; const REGISTER_ENDPOINT = "/register"; -export async function editions() { +export async function available() { const response = await axios.get(EDITIONS_ENDPOINT); - return response.data; + return (response.data || []).map(editionTeaserDtoTransformer.transform); } export async function join(key: string): Promise { @@ -23,13 +23,9 @@ export async function join(key: string): Promise { } } -// MOCK export async function get(key: string): Promise { - await delay(Math.random() * 200 + 100); + const response = await axios.get(prepare(EDITION_INFO_ENDPOINT, { key })); + const dto = response.data; - if (key == "inf2020") { - return sampleEdition; - } - - return null; + return editionDtoTransformer.transform(dto); } diff --git a/src/api/index.ts b/src/api/index.ts index 6d9942d..3432330 100644 --- a/src/api/index.ts +++ b/src/api/index.ts @@ -6,6 +6,7 @@ import { UserState } from "@/state/reducer/user"; import * as user from "./user"; import * as edition from "./edition"; import * as page from "./page" +import * as student from "./student" export const axios = Axios.create({ baseURL: process.env.API_BASE_URL || "https://system-praktyk.stg.kadet.net/api/", @@ -31,7 +32,8 @@ axios.interceptors.request.use(config => { const api = { user, edition, - page + page, + student } export default api; diff --git a/src/api/page.tsx b/src/api/page.tsx index f1c69ee..1a5cd02 100644 --- a/src/api/page.tsx +++ b/src/api/page.tsx @@ -1,27 +1,13 @@ -// MOCK import { Page } from "@/data/page"; +import { PageDTO, pageDtoTransformer } from "./dto/page" +import { axios } from "@/api/index"; +import { prepare } from "@/routing"; -const tos = `

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Bestiarum vero nullum iudicium puto. Quare ad ea primum, si videtur; Duo Reges: constructio interrete. Eam tum adesse, cum dolor omnis absit; Sed ad bona praeterita redeamus. Facillimum id quidem est, inquam. Apud ceteros autem philosophos, qui quaesivit aliquid, tacet;

- -

Quorum altera prosunt, nocent altera. Eam stabilem appellas. Sed nimis multa. Quo plebiscito decreta a senatu est consuli quaestio Cn. Sin laboramus, quis est, qui alienae modum statuat industriae? Quod quidem nobis non saepe contingit. Si autem id non concedatur, non continuo vita beata tollitur. Illum mallem levares, quo optimum atque humanissimum virum, Cn. Id est enim, de quo quaerimus.

- -

Ille vero, si insipiens-quo certe, quoniam tyrannus -, numquam beatus; Sin dicit obscurari quaedam nec apparere, quia valde parva sint, nos quoque concedimus; Et quod est munus, quod opus sapientiae? Ab hoc autem quaedam non melius quam veteres, quaedam omnino relicta.

-` +const STATIC_PAGE_ENDPOINT = "/staticPage/:slug" export async function get(slug: string): Promise { - if (slug === "/regulamin" || slug === "/rules") { - return { - id: "tak", - content: { - pl: tos, - en: tos, - }, - title: { - pl: "Regulamin Praktyk", - en: "Terms of Internship", - }, - } - } + const response = await axios.get(prepare(STATIC_PAGE_ENDPOINT, { slug })) + const page = response.data; - throw new Error(); + return pageDtoTransformer.transform(page); } diff --git a/src/api/student.ts b/src/api/student.ts new file mode 100644 index 0000000..e93a861 --- /dev/null +++ b/src/api/student.ts @@ -0,0 +1,13 @@ +import { axios } from "@/api/index"; +import { Student } from "@/data/student"; +import { StudentDTO, studentDtoTransfer } from "@/api/dto/student"; + +export const CURRENT_STUDENT_ENDPOINT = '/students/current'; + +export async function current(): Promise { + const response = await axios.get(CURRENT_STUDENT_ENDPOINT); + const dto = response.data; + + return studentDtoTransfer.transform(dto); +} + diff --git a/src/api/user.ts b/src/api/user.ts index ba70d5f..e930190 100644 --- a/src/api/user.ts +++ b/src/api/user.ts @@ -1,9 +1,22 @@ import { axios } from "@/api/index"; +import { query, route } from "@/routing"; -const AUTHORIZE_ENDPOINT = "/access/login" +const LOGIN_ENDPOINT = "/access/login" -export async function authorize(code: string): Promise { - const response = await axios.get(AUTHORIZE_ENDPOINT, { params: { code }}); +const CLIENT_ID = process.env.LOGIN_CLIENT_ID || "PraktykiClientId"; +const AUTHORIZE_URL = process.env.AUTHORIZE || "https://logowanie.pg.edu.pl/oauth2.0/authorize"; + +export async function login(code: string): Promise { + const response = await axios.get(LOGIN_ENDPOINT, { params: { code }}); return response.data; } + +export function getAuthorizeUrl() { + return query(AUTHORIZE_URL, { + response_type: "code", + scope: "user_details", + client_id: CLIENT_ID, + redirect_uri: window.location.origin + route("user_login") + "/check/pg", + }) +} diff --git a/src/app.tsx b/src/app.tsx index c05b38c..a3bb940 100644 --- a/src/app.tsx +++ b/src/app.tsx @@ -1,16 +1,14 @@ import React, { HTMLProps, useEffect } from 'react'; import { Link, Route, Switch } from "react-router-dom" -import { route, routes } from "@/routing"; +import { processMiddlewares, route, routes } from "@/routing"; import { useSelector } from "react-redux"; -import { AppState, isReady } from "@/state/reducer"; +import { AppState } from "@/state/reducer"; import { Trans, useTranslation } from "react-i18next"; import { Student } from "@/data"; import '@/styles/overrides.scss' import '@/styles/header.scss' import '@/styles/footer.scss' import classNames from "classnames"; -import { EditionActions } from "@/state/actions/edition"; -import { sampleEdition } from "@/provider/dummy/edition"; import { Edition } from "@/data/edition"; import { SettingActions } from "@/state/actions/settings"; import { useDispatch, UserActions } from "@/state/actions"; @@ -68,20 +66,12 @@ function App() { const { t } = useTranslation(); const locale = useSelector(state => getLocale(state.settings)); - useEffect(() => { - if (!edition) { - dispatch({ type: EditionActions.Set, edition: sampleEdition }); - } - }) - useEffect(() => { i18n.changeLanguage(locale); document.documentElement.lang = locale; moment.locale(locale) }, [ locale ]) - const ready = useSelector(isReady); - return <>
- { ready && { routes.map(({ name, content, ...route }) => { content() }) } } + { + { routes.map(({ name, content, middlewares = [], ...route }) => + { processMiddlewares([ ...middlewares, content ]) } + ) } + }