diff --git a/package.json b/package.json index 78023c1..7610207 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,8 @@ "jsonwebtoken": "^8.5.1", "material-ui-dropzone": "^3.3.0", "mdi-material-ui": "^6.17.0", - "moment": "^2.26.0", + "moment-timezone": "^2.26.0", + "moment-timezone": "^0.5.31", "node-sass": "^4.14.1", "optimize-css-assets-webpack-plugin": "5.0.3", "postcss-flexbugs-fixes": "4.1.0", diff --git a/src/api/dto/edition.ts b/src/api/dto/edition.ts index 2753f39..20d47fd 100644 --- a/src/api/dto/edition.ts +++ b/src/api/dto/edition.ts @@ -1,15 +1,21 @@ -import { Identifiable } from "@/data"; +import { Identifiable, InternshipProgramEntry } from "@/data"; import { CourseDTO, courseDtoTransformer } from "@/api/dto/course"; import { OneWayTransformer, Transformer } from "@/serialization"; import { Edition } from "@/data/edition"; -import moment from "moment"; +import moment from "moment-timezone"; import { Subset } from "@/helpers"; +export interface ProgramEntryDTO extends Identifiable { + description: string; + descriptionEng: string; +} + export interface EditionDTO extends Identifiable { editionStart: string, editionFinish: string, reportingStart: string, course: CourseDTO, + availableSubjects: ProgramEntryDTO[], } export interface EditionTeaserDTO extends Identifiable { @@ -39,6 +45,7 @@ export const editionDtoTransformer: Transformer = { editionStart: subject.startDate.toISOString(), course: courseDtoTransformer.reverseTransform(subject.course), reportingStart: subject.reportingStart.toISOString(), + availableSubjects: [], }; }, transform(subject: EditionDTO, context: undefined): Edition { @@ -55,3 +62,19 @@ export const editionDtoTransformer: Transformer = { }; } } + +export const programEntryDtoTransformer: Transformer = { + transform(subject: ProgramEntryDTO, context: never): InternshipProgramEntry { + return { + id: subject.id, + description: subject.description, + } + }, + reverseTransform(subject: InternshipProgramEntry, context: never): ProgramEntryDTO { + return { + id: subject.id, + description: subject.description, + descriptionEng: "", + } + }, +} diff --git a/src/api/dto/internship-registration.ts b/src/api/dto/internship-registration.ts index 34c61b0..0bb694a 100644 --- a/src/api/dto/internship-registration.ts +++ b/src/api/dto/internship-registration.ts @@ -3,7 +3,7 @@ import { momentSerializationTransformer, OneWayTransformer } from "@/serializati import { Nullable } from "@/helpers"; import { MentorDTO, mentorDtoTransformer } from "@/api/dto/mentor"; import { InternshipTypeDTO, internshipTypeDtoTransformer } from "@/api/dto/type"; -import { Moment } from "moment"; +import { Moment } from "moment-timezone"; import { sampleStudent } from "@/provider/dummy"; import { UploadType } from "@/api/upload"; @@ -36,6 +36,7 @@ export interface InternshipRegistrationUpdate { type: number, mentor: MentorDTO, hours: number, + subjects: string[], } export interface InternshipRegistrationDTO extends Identifiable { @@ -65,8 +66,8 @@ export interface InternshipInfoDTO { export const internshipRegistrationUpdateTransformer: OneWayTransformer, Nullable> = { transform(subject: Nullable, context?: unknown): Nullable { return { - start: subject?.startDate?.toISOString() || null, - end: subject?.endDate?.toISOString() || null, + start: momentSerializationTransformer.transform(subject?.startDate) || null, + end: momentSerializationTransformer.transform(subject?.endDate) || null, type: parseInt(subject?.type?.id || "0"), mentor: mentorDtoTransformer.reverseTransform(subject.mentor as Mentor), company: subject?.company?.id ? { @@ -80,6 +81,7 @@ export const internshipRegistrationUpdateTransformer: OneWayTransformer program.id as string) || [], } } } diff --git a/src/api/edition.ts b/src/api/edition.ts index b420620..62af39c 100644 --- a/src/api/edition.ts +++ b/src/api/edition.ts @@ -1,8 +1,9 @@ import { axios } from "@/api/index"; import { Edition } from "@/data/edition"; import { prepare } from "@/routing"; -import { EditionDTO, editionDtoTransformer, EditionTeaserDTO, editionTeaserDtoTransformer } from "@/api/dto/edition"; +import { EditionDTO, editionDtoTransformer, EditionTeaserDTO, editionTeaserDtoTransformer, programEntryDtoTransformer } from "@/api/dto/edition"; import { Subset } from "@/helpers"; +import { InternshipProgramEntry } from "@/data"; const EDITIONS_ENDPOINT = "/editions"; const EDITION_INFO_ENDPOINT = "/editions/:key"; @@ -41,11 +42,17 @@ export async function get(key: string): Promise | null> { return editionTeaserDtoTransformer.transform(dto); } -export async function current(): Promise { +export async function current(): Promise<{ + edition: Edition, + program: InternshipProgramEntry[], +}> { const response = await axios.get(EDITION_CURRENT_ENDPOINT); const dto = response.data; - return editionDtoTransformer.transform(dto); + return { + edition: editionDtoTransformer.transform(dto), + program: dto.availableSubjects.map(programEntryDtoTransformer.transform as any), + }; } export async function login(key: string): Promise { diff --git a/src/app.tsx b/src/app.tsx index 79092b4..3179805 100644 --- a/src/app.tsx +++ b/src/app.tsx @@ -9,12 +9,11 @@ import '@/styles/overrides.scss' import '@/styles/header.scss' import '@/styles/footer.scss' import classNames from "classnames"; -import { Edition } from "@/data/edition"; import { SettingActions } from "@/state/actions/settings"; import { useDispatch, UserActions } from "@/state/actions"; import { getLocale, Locale } from "@/state/reducer/settings"; import i18n from "@/i18n"; -import moment from "moment"; +import moment from "moment-timezone"; import { Container } from "@material-ui/core"; const UserMenu = (props: HTMLProps) => { @@ -61,8 +60,6 @@ const LanguageSwitcher = ({ className, ...props }: HTMLProps) } function App() { - const dispatch = useDispatch(); - const edition = useSelector(state => state.edition as any); const { t } = useTranslation(); const locale = useSelector(state => getLocale(state.settings)); diff --git a/src/components/async.tsx b/src/components/async.tsx index c68d16d..6b90ce6 100644 --- a/src/components/async.tsx +++ b/src/components/async.tsx @@ -2,6 +2,7 @@ import { AsyncResult } from "@/hooks"; import React from "react"; import { CircularProgress } from "@material-ui/core"; import { Alert } from "@material-ui/lab"; +import { Loading } from "@/components/loading"; type AsyncProps = { async: AsyncResult, @@ -10,7 +11,7 @@ type AsyncProps = { error?: (error: TError) => JSX.Element, } -const defaultLoading = () => ; +const defaultLoading = () => ; const defaultError = (error: any) => { error.message }; export function Async( diff --git a/src/components/loading.tsx b/src/components/loading.tsx new file mode 100644 index 0000000..e791e42 --- /dev/null +++ b/src/components/loading.tsx @@ -0,0 +1,28 @@ +import React from "react"; +import { createStyles, makeStyles } from "@material-ui/core/styles"; +import { CircularProgress, Typography } from "@material-ui/core"; + +const useStyles = makeStyles(theme => createStyles({ + root: { + display: "flex", + flexDirection: "column", + alignItems: "center", + "& > :not(:last-child)": { + marginBottom: theme.spacing(2), + } + } +})) + +export type LoadingProps = { + size?: string | number; + label?: string; +}; + +export function Loading({ size, label, ...props }: LoadingProps) { + const classes = useStyles(); + + return
+ + { label && { label } } +
+} diff --git a/src/components/proposalPreview.tsx b/src/components/proposalPreview.tsx index b452875..d11ea6f 100644 --- a/src/components/proposalPreview.tsx +++ b/src/components/proposalPreview.tsx @@ -4,7 +4,7 @@ import { Typography } from "@material-ui/core"; import { useTranslation } from "react-i18next"; import classNames from "classnames"; import { useVerticalSpacing } from "@/styles"; -import moment from "moment"; +import moment from "moment-timezone"; import { Label, Section } from "@/components/section"; import { StudentPreview } from "@/pages/user/profile"; diff --git a/src/components/step.tsx b/src/components/step.tsx index fa08903..60b2622 100644 --- a/src/components/step.tsx +++ b/src/components/step.tsx @@ -1,4 +1,4 @@ -import moment, { Moment } from "moment"; +import moment, { Moment } from "moment-timezone"; import { Box, Step as StepperStep, StepContent, StepLabel, StepProps as StepperStepProps, Typography } from "@material-ui/core"; import { useTranslation } from "react-i18next"; import React, { ReactChild, useMemo } from "react"; diff --git a/src/data/course.ts b/src/data/course.ts index 6bcb065..568fa37 100644 --- a/src/data/course.ts +++ b/src/data/course.ts @@ -5,5 +5,4 @@ import { Identifiable } from "./common"; export interface Course extends Identifiable { name: string, desiredSemesters: Semester[], - possibleProgramEntries: InternshipProgramEntry[]; } diff --git a/src/data/edition.ts b/src/data/edition.ts index 6ca8725..4e11994 100644 --- a/src/data/edition.ts +++ b/src/data/edition.ts @@ -1,4 +1,4 @@ -import { Moment } from "moment"; +import { Moment } from "moment-timezone"; import { Course } from "@/data/course"; import { Identifiable } from "@/data/common"; diff --git a/src/data/internship.ts b/src/data/internship.ts index d3e946e..b819581 100644 --- a/src/data/internship.ts +++ b/src/data/internship.ts @@ -1,4 +1,4 @@ -import { Moment } from "moment"; +import { Moment } from "moment-timezone"; import { Identifiable, Multilingual } from "./common"; import { Student } from "@/data/student"; import { Company, Office } from "@/data/company"; diff --git a/src/forms/internship.tsx b/src/forms/internship.tsx index 9f591dc..781a2e4 100644 --- a/src/forms/internship.tsx +++ b/src/forms/internship.tsx @@ -1,12 +1,24 @@ -import React, { HTMLProps, useMemo, useState } from "react"; -import { Button, Dialog, DialogActions, DialogContent, DialogContentText, Grid, TextField, Typography } from "@material-ui/core"; +import React, { HTMLProps, useEffect, useMemo, useState } from "react"; +import { + Button, + Dialog, + DialogActions, + DialogContent, + DialogContentText, + Grid, + TextField, + Typography, + FormGroup, + FormControlLabel, + Checkbox +} from "@material-ui/core"; import { KeyboardDatePicker as DatePicker } from "@material-ui/pickers"; import { CompanyForm } from "@/forms/company"; import { StudentForm } from "@/forms/student"; import { sampleStudent } from "@/provider/dummy/student"; -import { Company, Internship, InternshipType, Office, Student } from "@/data"; +import { Company, Internship, InternshipProgramEntry, InternshipType, Office, Student } from "@/data"; import { Nullable } from "@/helpers"; -import moment, { Moment } from "moment"; +import moment, { Moment } from "moment-timezone"; import { computeWorkingHours } from "@/utils/date"; import { Autocomplete } from "@material-ui/lab"; import { emptyInternship } from "@/provider/dummy/internship"; @@ -25,6 +37,8 @@ import { TextField as TextFieldFormik } from "formik-material-ui" import { useCurrentEdition, useCurrentStudent, useInternshipTypes, useUpdateEffect } from "@/hooks"; import { internshipRegistrationUpdateTransformer } from "@/api/dto/internship-registration"; import api from "@/api"; +import FormLabel from "@material-ui/core/FormLabel"; +import { CheckBox } from "@material-ui/icons"; export type InternshipFormValues = { startDate: Moment | null; @@ -43,6 +57,7 @@ export type InternshipFormValues = { mentorEmail: string; mentorPhone: string; kindOther: string | null; + program: InternshipProgramEntry[]; // relations kind: InternshipType | null; @@ -72,6 +87,7 @@ const emptyInternshipValues: InternshipFormValues = { startDate: null, student: sampleStudent, workingHours: 40, + program: [], } export const InternshipTypeItem = ({ internshipType: type, ...props }: { internshipType: InternshipType } & HTMLProps) => { @@ -86,9 +102,24 @@ export const InternshipTypeItem = ({ internshipType: type, ...props }: { interns const InternshipProgramForm = () => { const { t } = useTranslation(); const { values, handleBlur, setFieldValue, errors } = useFormikContext(); + const [ selectedProgramEntries, setSelectedProgramEntries ] = useState(values.program); + + const possibleProgramEntries = useSelector(state => state.edition.program); const types = useInternshipTypes(); + const handleProgramEntryChange = (entry: InternshipProgramEntry) => (ev: any) => { + if (ev.target.checked) { + setSelectedProgramEntries([ ...selectedProgramEntries, entry ]); + } else { + setSelectedProgramEntries(selectedProgramEntries.filter(cur => cur != entry)); + } + } + + useEffect(() => { + setFieldValue("program", selectedProgramEntries); + }, [ selectedProgramEntries ]) + return ( @@ -108,6 +139,20 @@ const InternshipProgramForm = () => { {/* */} {/* }*/} {/**/} + + + { t('forms.internship.fields.program', { count: 3 }) } + { possibleProgramEntries.map( + entry => } + checked={ selectedProgramEntries.includes(entry) } + onChange={ handleProgramEntryChange(entry) } + label={ entry.description } + key={ entry.id } + /> + ) } + + ) } @@ -206,6 +251,7 @@ const converter: Transformer, InternshipFormValues, Interns mentorLastName: internship.mentor?.surname || "", mentorPhone: internship.mentor?.phone || "", workingHours: 40, + program: internship.program || [], } }, reverseTransform(form: InternshipFormValues, context: InternshipConverterContext): Nullable { @@ -235,6 +281,7 @@ const converter: Transformer, InternshipFormValues, Interns }, hours: form.hours ? form.hours : 0, type: form.kind as InternshipType, + program: form.program, } } } @@ -280,6 +327,7 @@ export const InternshipForm: React.FunctionComponent = () => { city: Yup.string().required(t("validation.required")), postalCode: Yup.string().required(t("validation.required")), building: Yup.string().required(t("validation.required")), + program: Yup.array() as any, // kindOther: Yup.string().when("kind", { // is: (values: InternshipFormValues) => values?.kind === InternshipType.Other, // then: Yup.string().required(t("validation.required")) diff --git a/src/hooks/state.ts b/src/hooks/state.ts index d024dcd..9fc52a6 100644 --- a/src/hooks/state.ts +++ b/src/hooks/state.ts @@ -9,7 +9,7 @@ export const useCurrentStudent = () => useSelector( ) export const useCurrentEdition = () => useSelector( - state => state.edition && editionSerializationTransformer.reverseTransform(state.edition) + state => state.edition?.edition && editionSerializationTransformer.reverseTransform(state.edition.edition) ) export const useDeadlines = () => { diff --git a/src/i18n.ts b/src/i18n.ts index 84cc091..a5e47ec 100644 --- a/src/i18n.ts +++ b/src/i18n.ts @@ -4,7 +4,7 @@ import I18nextBrowserLanguageDetector from "i18next-browser-languagedetector"; import "moment/locale/pl" import "moment/locale/en-gb" -import moment, { isDuration, isMoment, unitOfTime } from "moment"; +import moment, { isDuration, isMoment, unitOfTime } from "moment-timezone"; import { convertToRoman } from "@/utils/numbers"; const resources = { diff --git a/src/index.tsx b/src/index.tsx index 2c53768..6df4691 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -7,7 +7,7 @@ import store, { persistor } from "@/state/store"; import { PersistGate } from "redux-persist/integration/react"; import { MuiThemeProvider as ThemeProvider, StylesProvider } from "@material-ui/core/styles"; import { MuiPickersUtilsProvider } from "@material-ui/pickers"; -import moment, { Moment } from "moment"; +import moment, { Moment } from "moment-timezone"; import { studentTheme } from "@/ui/theme"; import { BrowserRouter } from "react-router-dom"; import MomentUtils from "@date-io/moment"; diff --git a/src/pages/edition/pick.tsx b/src/pages/edition/pick.tsx index 635d225..2047368 100644 --- a/src/pages/edition/pick.tsx +++ b/src/pages/edition/pick.tsx @@ -25,11 +25,12 @@ export const loginToEdition = (id: string) => async (dispatch: AppDispatch) => { token, }) - const edition = await api.edition.current(); + const { edition, program } = await api.edition.current(); dispatch({ type: EditionActions.Set, - edition + edition, + program, }) } diff --git a/src/pages/user/login.tsx b/src/pages/user/login.tsx index c7dd466..ffdd9c9 100644 --- a/src/pages/user/login.tsx +++ b/src/pages/user/login.tsx @@ -1,6 +1,6 @@ import React, { Dispatch, useEffect } from "react"; import { Page } from "@/pages/base"; -import { Button, Container } from "@material-ui/core"; +import { Button, CircularProgress, Container, Typography } from "@material-ui/core"; import { Action, StudentActions, useDispatch } from "@/state/actions"; import { Route, Switch, useHistory, useLocation, useRouteMatch } from "react-router-dom"; import { route } from "@/routing"; @@ -10,6 +10,8 @@ import { AppState } from "@/state/reducer"; import api from "@/api"; import { UserActions } from "@/state/actions/user"; import { getAuthorizeUrl } from "@/api/user"; +import { useTranslation } from "react-i18next"; +import { Loading } from "@/components/loading"; const authorizeUser = (code?: string) => async (dispatch: Dispatch, getState: () => AppState): Promise => { const token = await api.user.login(code); @@ -32,6 +34,7 @@ export const UserLoginPage = () => { const match = useRouteMatch(); const location = useLocation(); const query = new URLSearchParams(useLocation().search); + const { t } = useTranslation(); const handleSampleLogin = async () => { await dispatch(authorizeUser()); @@ -54,6 +57,8 @@ export const UserLoginPage = () => { })(); }, [ match.path ]); + const inProgress = + return Zaloguj się @@ -66,11 +71,13 @@ export const UserLoginPage = () => { - (window.location.href = getAuthorizeUrl()) - } /> + { + window.location.href = getAuthorizeUrl() + + return inProgress + } } /> - Kod: { query.get("code") } + { inProgress } diff --git a/src/provider/dummy/edition.ts b/src/provider/dummy/edition.ts index 995da58..1c464ff 100644 --- a/src/provider/dummy/edition.ts +++ b/src/provider/dummy/edition.ts @@ -1,5 +1,5 @@ import { Edition } from "@/data/edition"; -import moment from "moment"; +import moment from "moment-timezone"; import { sampleCourse } from "@/provider/dummy/student"; export const sampleEdition: Edition = { diff --git a/src/provider/dummy/internship.ts b/src/provider/dummy/internship.ts index 9f10d5b..31c4011 100644 --- a/src/provider/dummy/internship.ts +++ b/src/provider/dummy/internship.ts @@ -13,7 +13,7 @@ export const emptyInternship: Nullable = { endDate: null, startDate: null, type: null, - program: null, + program: [], isAccepted: false, lengthInWeeks: 0, mentor: emptyMentor, diff --git a/src/provider/dummy/student.ts b/src/provider/dummy/student.ts index 38272d7..9033f53 100644 --- a/src/provider/dummy/student.ts +++ b/src/provider/dummy/student.ts @@ -25,7 +25,6 @@ export const sampleCourse: Course = { id: courseIdSequence(), name: "Informatyka", desiredSemesters: [6], - possibleProgramEntries: sampleProgramEntries, } export const sampleStudent: Student = { diff --git a/src/serialization/edition.ts b/src/serialization/edition.ts index ae4555c..6c1ced6 100644 --- a/src/serialization/edition.ts +++ b/src/serialization/edition.ts @@ -1,7 +1,7 @@ import { Serializable, SerializationTransformer } from "@/serialization/types"; import { Edition } from "@/data/edition"; import { momentSerializationTransformer } from "@/serialization/moment"; -import { Moment } from "moment"; +import { Moment } from "moment-timezone"; export const editionSerializationTransformer: SerializationTransformer = { transform(subject: Edition, context?: unknown): Serializable { diff --git a/src/serialization/internship.ts b/src/serialization/internship.ts index 9a9f628..326091f 100644 --- a/src/serialization/internship.ts +++ b/src/serialization/internship.ts @@ -1,7 +1,7 @@ import { Internship, InternshipType } from "@/data"; import { Serializable, SerializationTransformer } from "@/serialization/types"; import { momentSerializationTransformer } from "@/serialization/moment"; -import { Moment } from "moment"; +import { Moment } from "moment-timezone"; export const internshipSerializationTransformer: SerializationTransformer = { transform: (internship: Internship): Serializable => ({ diff --git a/src/serialization/moment.ts b/src/serialization/moment.ts index ae53d77..50cc164 100644 --- a/src/serialization/moment.ts +++ b/src/serialization/moment.ts @@ -1,7 +1,7 @@ import { SerializationTransformer } from "@/serialization/types"; -import moment, { Moment } from "moment"; +import moment, { Moment } from "moment-timezone"; export const momentSerializationTransformer: SerializationTransformer = { - transform: (subject: Moment) => subject && subject.toISOString(), + transform: (subject: Moment) => subject && subject.clone().utc(false).add(subject.utcOffset(), 'minutes').toISOString(), reverseTransform: (subject: string) => subject ? moment(subject) : null, } diff --git a/src/serialization/types.ts b/src/serialization/types.ts index befd035..424786d 100644 --- a/src/serialization/types.ts +++ b/src/serialization/types.ts @@ -1,4 +1,4 @@ -import { Moment } from "moment"; +import { Moment } from "moment-timezone"; type Simplify = string | T extends string ? string : diff --git a/src/state/actions/edition.ts b/src/state/actions/edition.ts index f25b853..cbb30aa 100644 --- a/src/state/actions/edition.ts +++ b/src/state/actions/edition.ts @@ -1,5 +1,6 @@ import { Action } from "@/state/actions/base"; import { Edition } from "@/data/edition"; +import { InternshipProgramEntry } from "@/data"; export enum EditionActions { Set = 'SET_EDITION', @@ -7,6 +8,7 @@ export enum EditionActions { export interface SetAction extends Action { edition: Edition, + program: InternshipProgramEntry[], } export type EditionAction = SetAction; diff --git a/src/state/reducer/edition.ts b/src/state/reducer/edition.ts index 43084d4..6b970b3 100644 --- a/src/state/reducer/edition.ts +++ b/src/state/reducer/edition.ts @@ -2,15 +2,26 @@ import { Edition } from "@/data/edition"; import { EditionAction, EditionActions } from "@/state/actions/edition"; import { editionSerializationTransformer, Serializable } from "@/serialization"; import { LoginAction, LogoutAction, UserActions } from "@/state/actions"; +import { InternshipProgramEntry } from "@/data"; -export type EditionState = Serializable | null; +export type EditionState = Serializable<{ + edition: Edition | null, + program: InternshipProgramEntry[], +}> -const initialEditionState: EditionState = null; +const initialEditionState: EditionState = { + edition: null, + program: [], +}; const editionReducer = (state: EditionState = initialEditionState, action: EditionAction | LogoutAction | LoginAction): EditionState => { switch (action.type) { case EditionActions.Set: - return editionSerializationTransformer.transform(action.edition); + return { + ...state, + edition: editionSerializationTransformer.transform(action.edition), + program: action.program, + }; case UserActions.Login: case UserActions.Logout: return initialEditionState; diff --git a/src/state/reducer/index.ts b/src/state/reducer/index.ts index 6374056..d57303b 100644 --- a/src/state/reducer/index.ts +++ b/src/state/reducer/index.ts @@ -22,4 +22,4 @@ export type AppState = ReturnType; export default rootReducer; -export const isReady = (state: AppState) => !!state.edition; +export const isReady = (state: AppState) => !!(state.edition?.edition); diff --git a/src/state/reducer/submission.ts b/src/state/reducer/submission.ts index 864cf2f..c63b631 100644 --- a/src/state/reducer/submission.ts +++ b/src/state/reducer/submission.ts @@ -1,7 +1,7 @@ import { DeanApproval } from "@/data/deanApproval"; import { Action } from "@/state/actions"; import { momentSerializationTransformer } from "@/serialization"; -import moment from "moment"; +import moment from "moment-timezone"; import { ReceiveSubmissionApproveAction, ReceiveSubmissionDeclineAction, SubmissionAction } from "@/state/actions/submission"; export type SubmissionStatus = "draft" | "awaiting" | "accepted" | "declined"; diff --git a/src/styles/page.scss b/src/styles/page.scss index f6a1b68..a78af7a 100644 --- a/src/styles/page.scss +++ b/src/styles/page.scss @@ -20,3 +20,14 @@ .proposal__header:not(:first-child) { margin-top: 1rem; } + +.loading-wrapper { + display: flex; + flex-direction: column; + + align-items: center; + + & > *:not(:last-child) { + margin-bottom: 1rem; + } +} diff --git a/src/utils/date.ts b/src/utils/date.ts index b42eadf..054d559 100644 --- a/src/utils/date.ts +++ b/src/utils/date.ts @@ -1,4 +1,4 @@ -import { Moment } from "moment"; +import { Moment } from "moment-timezone"; import Holidays from "date-holidays"; const holidays = new Holidays() diff --git a/translations/pl.yaml b/translations/pl.yaml index e46a78a..86589e0 100644 --- a/translations/pl.yaml +++ b/translations/pl.yaml @@ -2,6 +2,7 @@ copyright: Wydział ETI Politechniki Gdańskiej © {{ date, YYYY }} login: zaloguj się +login-in-progress: Logowanie w toku, proszę czekać... logout: wyloguj się logged-in-as: zalogowany jako <1>{{ name }} @@ -79,6 +80,7 @@ forms: country: Kraj street: Ulica building: Nr budynku + program: Program praktyki (wybierz {{ count }}) help: weeks: Wartość wyliczana automatycznie working-hours: Liczba godzin w tygodniu roboczym @@ -155,7 +157,8 @@ steps: header: "Zgłoszenie praktyki" info: draft: > - Przed podjęciem praktyki należy ją zgłosić. (TODO) + Przed podjęciem praktyki należy ją zgłosić - w tym celu należy elektronicznie wypełnić formularz zgłoszenia + praktyki. awaiting: > Twoje zgłoszenie musi zostać zweryfikowane i zatwierdzone. Po weryfikacji zostaniesz poinformowany o akceptacji bądź konieczności wprowadzenia zmian. @@ -171,7 +174,8 @@ steps: info: draft: > W porozumieniu z firmą w której odbywają się praktyki należy sporządzić Indywidualny Plan Praktyk zgodnie z - załączonym szablonem a następnie wysłać go do weryfikacji. (TODO) + załączonym szablonem a następnie wysłać go do weryfikacji. Indywidualny Plan Praktyk musi zostać zatwierdzony + oraz podpisany przez Twojego zakłądowego opiekuna praktyki. awaiting: > Twój indywidualny program praktyki został poprawnie zapisany w systemie. Musi on jeszcze zostać zweryfikowany i zatwierdzony. Po weryfikacji zostaniesz poinformowany o akceptacji bądź konieczności wprowadzenia zmian.