diff --git a/src/components/proposalPreview.tsx b/src/components/proposalPreview.tsx index 1b8a46a..096779e 100644 --- a/src/components/proposalPreview.tsx +++ b/src/components/proposalPreview.tsx @@ -72,7 +72,7 @@ export const ProposalPreview = ({ proposal }: ProposalPreviewProps) => { <Typography className="proposal__secondary"> { t('internship.duration', { duration, count: Math.floor(duration.asWeeks()) }) } { ", " } - { t('internship.hours', { hours: proposal.hours }) } + { t('internship.hours', { hours: proposal.hours, count: proposal.hours }) } </Typography> </Section> diff --git a/src/forms/company.tsx b/src/forms/company.tsx index a728935..d18ddcc 100644 --- a/src/forms/company.tsx +++ b/src/forms/company.tsx @@ -7,6 +7,7 @@ import { BoundProperty, formFieldProps } from "./helpers"; import { InternshipFormSectionProps } from "@/forms/internship"; import { emptyMentor } from "@/provider/dummy/internship"; import { useProxyState } from "@/hooks"; +import { useTranslation } from "react-i18next"; export type CompanyFormProps = {} & InternshipFormSectionProps; @@ -32,6 +33,7 @@ export const OfficeItem = ({ office, ...props }: { office: BranchOffice } & HTML export const BranchForm: React.FC<BranchOfficeProps> = ({ value: office, onChange: setOffice, offices = [], disabled = false }) => { const canEdit = useMemo(() => !office.id && !disabled, [office.id, disabled]); const fieldProps = formFieldProps(office.address, address => setOffice({ ...office, address })) + const { t } = useTranslation(); const handleCityChange = (event: any, value: BranchOffice | string | null) => { if (typeof value === "string") { @@ -68,7 +70,7 @@ export const BranchForm: React.FC<BranchOfficeProps> = ({ value: office, onChang disabled={ disabled } getOptionLabel={ office => typeof office == "string" ? office : office.address.city } renderOption={ office => <OfficeItem office={ office }/> } - renderInput={ props => <TextField { ...props } label={ "Miasto" } fullWidth/> } + renderInput={ props => <TextField { ...props } label={ t("forms.internship.fields.city") } fullWidth/> } onChange={ handleCityChange } onInputChange={ handleCityInput } inputValue={ office.address.city } @@ -77,16 +79,16 @@ export const BranchForm: React.FC<BranchOfficeProps> = ({ value: office, onChang /> </Grid> <Grid item md={ 2 }> - <TextField label={ "Kod pocztowy" } fullWidth disabled={ !canEdit } { ...fieldProps("postalCode") }/> + <TextField label={ t("forms.internship.fields.postal-code") } fullWidth disabled={ !canEdit } { ...fieldProps("postalCode") }/> </Grid> <Grid item md={ 3 }> - <TextField label={ "Kraj" } fullWidth disabled={ !canEdit } { ...fieldProps("country") }/> + <TextField label={ t("forms.internship.fields.country") } fullWidth disabled={ !canEdit } { ...fieldProps("country") }/> </Grid> <Grid item md={ 10 }> - <TextField label={ "Ulica" } fullWidth disabled={ !canEdit } { ...fieldProps("street") }/> + <TextField label={ t("forms.internship.fields.street") } fullWidth disabled={ !canEdit } { ...fieldProps("street") }/> </Grid> <Grid item md={ 2 }> - <TextField label={ "Nr Budynku" } fullWidth disabled={ !canEdit } { ...fieldProps("building") }/> + <TextField label={ t("forms.internship.fields.building") } fullWidth disabled={ !canEdit } { ...fieldProps("building") }/> </Grid> </Grid> </div> @@ -95,21 +97,22 @@ export const BranchForm: React.FC<BranchOfficeProps> = ({ value: office, onChang export const MentorForm = ({ mentor, onMentorChange }: BoundProperty<Mentor, 'onMentorChange', 'mentor'>) => { const fieldProps = formFieldProps(mentor, onMentorChange) + const { t } = useTranslation(); return ( <> <Grid container> <Grid item md={6}> - <TextField label="Imię" fullWidth { ...fieldProps("name") }/> + <TextField label={ t("forms.internship.fields.first-name") } fullWidth { ...fieldProps("name") }/> </Grid> <Grid item md={6}> - <TextField label="Nazwisko" value={ mentor.surname } fullWidth { ...fieldProps("surname") }/> + <TextField label={ t("forms.internship.fields.last-name") } value={ mentor.surname } fullWidth { ...fieldProps("surname") }/> </Grid> <Grid item md={8}> - <TextField label="E-mail" value={ mentor.email } fullWidth { ...fieldProps("email") }/> + <TextField label={ t("forms.internship.fields.e-mail") } value={ mentor.email } fullWidth { ...fieldProps("email") }/> </Grid> <Grid item md={4}> - <TextField label="Nr telefonu" value={ mentor.phone } fullWidth { ...fieldProps("phone") }/> + <TextField label={ t("forms.internship.fields.phone" )} value={ mentor.phone } fullWidth { ...fieldProps("phone") }/> </Grid> </Grid> </> @@ -120,6 +123,7 @@ export const CompanyForm: React.FunctionComponent<CompanyFormProps> = ({ interns const [company, setCompany] = useProxyState<Company>(internship.company || emptyCompany, company => onChange({ ...internship, company })); const [mentor, setMentor] = useProxyState<Mentor>(internship.mentor || emptyMentor, mentor => onChange({ ...internship, mentor })); const [office, setOffice] = useProxyState<BranchOffice>(internship.office || emptyBranchOffice, office => onChange({ ...internship, office })); + const { t } = useTranslation(); const canEdit = useMemo(() => !company.id, [company.id]); @@ -145,21 +149,21 @@ export const CompanyForm: React.FunctionComponent<CompanyFormProps> = ({ interns <Autocomplete options={ sampleCompanies } getOptionLabel={ option => option.name } renderOption={ company => <CompanyItem company={ company }/> } - renderInput={ props => <TextField { ...props } label={ "Nazwa firmy" } fullWidth/> } + renderInput={ props => <TextField { ...props } label={ t("forms.internship.fields.company-name") } fullWidth/> } onChange={ handleCompanyChange } value={ company } freeSolo /> </Grid> <Grid item md={ 4 }> - <TextField label={ "NIP" } fullWidth { ...fieldProps("nip") } disabled={ !canEdit }/> + <TextField label={ t("forms.internship.fields.nip") } fullWidth { ...fieldProps("nip") } disabled={ !canEdit }/> </Grid> {/*<Grid item md={ 8 }>*/} {/* <TextField label={ "Url" } fullWidth { ...fieldProps("url") } disabled={ !canEdit }/>*/} {/*</Grid>*/} </Grid> - <Typography variant="subtitle1" className="subsection-header">Zakładowy opiekun praktyki</Typography> + <Typography variant="subtitle1" className="subsection-header">{ t("internship.mentor") }</Typography> <MentorForm mentor={ mentor } onMentorChange={ setMentor }/> - <Typography variant="subtitle1" className="subsection-header">Oddział</Typography> + <Typography variant="subtitle1" className="subsection-header">{ t("internship.office") }</Typography> <BranchForm value={ office } onChange={ setOffice } offices={ company.offices } /> </> ) diff --git a/src/forms/internship.tsx b/src/forms/internship.tsx index f4d2324..a6c5e3a 100644 --- a/src/forms/internship.tsx +++ b/src/forms/internship.tsx @@ -1,23 +1,10 @@ import React, { HTMLProps, useEffect, useMemo, useState } from "react"; -import { - Button, - Dialog, - DialogActions, - DialogContent, - DialogContentText, - FormControl, - FormHelperText, - Grid, - Input, - InputLabel, - TextField, - Typography -} from "@material-ui/core"; +import { Button, Dialog, DialogActions, DialogContent, DialogContentText, Grid, TextField, Typography } 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 { Course, Internship, InternshipType, internshipTypeLabels } from "@/data"; +import { Internship, InternshipType, internshipTypeLabels } from "@/data"; import { Nullable } from "@/helpers"; import moment, { Moment } from "moment"; import { computeWorkingHours } from "@/utils/date"; @@ -55,12 +42,12 @@ export const InternshipTypeItem = ({ type, ...props }: { type: InternshipType } const InternshipProgramForm = ({ internship, onChange }: InternshipFormSectionProps) => { const fieldProps = formFieldProps(internship, onChange); - const course = internship.intern?.course as Course; + const { t } = useTranslation(); return ( <Grid container> <Grid item md={ 4 }> - <Autocomplete renderInput={ props => <TextField { ...props } label="Rodzaj praktyki/umowy" fullWidth/> } + <Autocomplete renderInput={ props => <TextField { ...props } label={ t("forms.internship.fields.kind") } fullWidth/> } getOptionLabel={ (option: InternshipType) => internshipTypeLabels[option].label } renderOption={ (option: InternshipType) => <InternshipTypeItem type={ option }/> } options={ Object.values(InternshipType) as InternshipType[] } @@ -69,7 +56,7 @@ const InternshipProgramForm = ({ internship, onChange }: InternshipFormSectionPr /> </Grid> <Grid item md={ 8 }> - { internship.type === InternshipType.Other && <TextField label={ "Inny - Wprowadź" } fullWidth/> } + { internship.type === InternshipType.Other && <TextField label={ t("forms.internship.fields.kind") } fullWidth/> } </Grid> {/*<Grid item>*/ } {/* <FormGroup>*/ } @@ -88,6 +75,8 @@ const InternshipProgramForm = ({ internship, onChange }: InternshipFormSectionPr } const InternshipDurationForm = ({ internship, onChange }: InternshipFormSectionProps) => { + const { t } = useTranslation(); + const [startDate, setStartDate] = useProxyState<Moment | null>(internship.startDate, value => onChange({ ...internship, startDate: value })); const [endDate, setEndDate] = useProxyState<Moment | null>(internship.endDate, value => onChange({ ...internship, endDate: value })); @@ -107,45 +96,34 @@ const InternshipDurationForm = ({ internship, onChange }: InternshipFormSectionP <DatePicker value={ startDate } onChange={ setStartDate } format="DD MMMM yyyy" clearable disableToolbar fullWidth - variant="inline" label={ "Data rozpoczęcia praktyki" } + variant="inline" label={ t("forms.internship.fields.start-date") } + minDate={ moment() } /> </Grid> <Grid item md={ 6 }> <DatePicker value={ endDate } onChange={ setEndDate } format="DD MMMM yyyy" clearable disableToolbar fullWidth - variant="inline" label={ "Data zakończenia praktyki" } + variant="inline" label={ t("forms.internship.fields.end-date") } minDate={ startDate || moment() } /> </Grid> <Grid item md={ 4 }> - <FormControl fullWidth> - <InputLabel>Wymiar etatu</InputLabel> - <Input value={ workingHours } - onChange={ ev => setWorkingHours(parseInt(ev.target.value) || 0) } - fullWidth - /> - <FormHelperText>Liczba godzin w tygodniu roboczym</FormHelperText> - </FormControl> + <TextField fullWidth label={ t("forms.internship.fields.working-hours") } + value={ workingHours } onChange={ ev => setWorkingHours(parseInt(ev.target.value) || 0) } + helperText={ t("forms.internship.help.working-hours") } + /> </Grid> <Grid item md={ 4 }> - <FormControl fullWidth> - <InputLabel>Łączna liczba godzin</InputLabel> - <Input value={ hours || "" } - onChange={ ev => setHoursOverride(parseInt(ev.target.value) || 0) } - fullWidth - /> - </FormControl> + <TextField fullWidth label={ t("forms.internship.fields.total-hours") } + value={ hours } onChange={ ev => setHoursOverride(parseInt(ev.target.value) || 0) } + /> </Grid> <Grid item md={ 4 }> - <FormControl fullWidth> - <InputLabel>Liczba tygodni</InputLabel> - <Input value={ weeks || "" } - disabled - fullWidth - /> - <FormHelperText>Wyliczona automatycznie</FormHelperText> - </FormControl> + <TextField fullWidth label={ t("forms.internship.fields.weeks") } + value={ weeks } disabled + helperText={ t("forms.internship.help.weeks") } + /> </Grid> </Grid> ); diff --git a/src/forms/student.tsx b/src/forms/student.tsx index da722e8..db1ec6e 100644 --- a/src/forms/student.tsx +++ b/src/forms/student.tsx @@ -3,42 +3,43 @@ import { Button, Grid, TextField } from "@material-ui/core"; import { Alert, Autocomplete } from "@material-ui/lab"; import React from "react"; import { sampleCourse } from "@/provider/dummy/student"; +import { useTranslation } from "react-i18next"; type StudentFormProps = { student: Student } export const StudentForm = ({ student }: StudentFormProps) => { - return ( - <> - <Grid container> - <Grid item md={4}> - <TextField label="Imię" value={ student.name } disabled fullWidth/> - </Grid> - <Grid item md={4}> - <TextField label="Nazwisko" value={ student.surname } disabled fullWidth/> - </Grid> - <Grid item md={4}> - <TextField label="Nr Indeksu" value={ student.albumNumber } disabled fullWidth/> - </Grid> - <Grid item md={9}> - <Autocomplete - getOptionLabel={ (course: Course) => course.name } - renderInput={ props => <TextField { ...props } label={ "Kierunek" } fullWidth/> } - options={[ sampleCourse ]} - value={ student.course } - disabled - /> - </Grid> - <Grid item md={3}> - <TextField label="Semestr" value={ student.semester } disabled fullWidth/> - </Grid> - <Grid item> - <Alert severity="warning" action={ <Button color="inherit" size="small">skontaktuj się z opiekunem</Button> }> - Powyższe dane nie są poprawne? - </Alert> - </Grid> + const { t } = useTranslation(); + + return <> + <Grid container> + <Grid item md={4}> + <TextField label={ t("forms.internship.fields.first-name") } value={ student.name } disabled fullWidth/> </Grid> - </> - ); + <Grid item md={4}> + <TextField label={ t("forms.internship.fields.last-name") } value={ student.surname } disabled fullWidth/> + </Grid> + <Grid item md={4}> + <TextField label={ t("forms.internship.fields.album") } value={ student.albumNumber } disabled fullWidth/> + </Grid> + <Grid item md={9}> + <Autocomplete + getOptionLabel={ (course: Course) => course.name } + renderInput={ props => <TextField { ...props } label={ t("forms.internship.fields.course") } fullWidth/> } + options={[ sampleCourse ]} + value={ student.course } + disabled + /> + </Grid> + <Grid item md={3}> + <TextField label={ t("forms.internship.fields.semester") } value={ student.semester } disabled fullWidth/> + </Grid> + <Grid item> + <Alert severity="warning" action={ <Button color="inherit" size="small">skontaktuj się z opiekunem</Button> }> + Powyższe dane nie są poprawne? + </Alert> + </Grid> + </Grid> + </>; } diff --git a/src/pages/internship/plan.tsx b/src/pages/internship/plan.tsx index e09a214..5706817 100644 --- a/src/pages/internship/plan.tsx +++ b/src/pages/internship/plan.tsx @@ -12,7 +12,7 @@ export const SubmitPlanPage = () => { return <Page title={ t("steps.plan.submit") }> <Page.Header maxWidth="md"> <Page.Breadcrumbs> - <Link component={ RouterLink } to={ route("home") }>{ t('sections.my-internship.header') }</Link> + <Link component={ RouterLink } to={ route("home") }>{ t('pages.my-internship.header') }</Link> <Typography color="textPrimary">{ t("steps.plan.submit") }</Typography> </Page.Breadcrumbs> <Page.Title>{ t("steps.plan.submit") }</Page.Title> diff --git a/src/pages/internship/proposal.tsx b/src/pages/internship/proposal.tsx index f9767bd..939998b 100644 --- a/src/pages/internship/proposal.tsx +++ b/src/pages/internship/proposal.tsx @@ -30,13 +30,15 @@ import { MenuDown, StickerCheckOutline, StickerRemoveOutline } from "mdi-materia import { useVerticalSpacing } from "@/styles"; export const InternshipProposalFormPage = () => { - return <Page title="Zgłoszenie praktyki"> + const { t } = useTranslation(); + + return <Page title={ t("pages.proposal-form.header") }> <Page.Header maxWidth="md"> <Page.Breadcrumbs> - <Link component={ RouterLink } to={ route("home") }>Moja praktyka</Link> - <Typography color="textPrimary">Zgłoszenie praktyki</Typography> + <Link component={ RouterLink } to={ route("home") }>{ t("pages.my-internship.header") }</Link> + <Typography color="textPrimary">{ t("pages.proposal-form.header") }</Typography> </Page.Breadcrumbs> - <Page.Title>Zgłoszenie praktyki</Page.Title> + <Page.Title>{ t("pages.proposal-form.header") }</Page.Title> </Page.Header> <Container maxWidth={ "md" }> <ProposalComment /> diff --git a/src/pages/main.tsx b/src/pages/main.tsx index 5d2da88..f03e9b3 100644 --- a/src/pages/main.tsx +++ b/src/pages/main.tsx @@ -25,7 +25,7 @@ export const MainPage = () => { return <Page my={ 6 }> <Container> - <Typography variant="h2">{ t("sections.my-internship.header") }</Typography> + <Typography variant="h2">{ t("pages.my-internship.header") }</Typography> <Stepper orientation="vertical" nonLinear> <Step label={ t('steps.personal-data.header') } completed={ missingStudentData.length === 0 } until={ deadlines.personalData }> { missingStudentData.length > 0 && <> diff --git a/src/ui/theme.ts b/src/ui/theme.ts index 0cb8e31..cf65aad 100644 --- a/src/ui/theme.ts +++ b/src/ui/theme.ts @@ -10,7 +10,7 @@ export const studentTheme = responsiveFontSizes(createMuiTheme({ maxWidth: "md" }, MuiTextField: { - variant: "outlined" + variant: "outlined", } }, palette: { diff --git a/translations/en.yaml b/translations/en.yaml index 902dbbd..1fc2920 100644 --- a/translations/en.yaml +++ b/translations/en.yaml @@ -11,6 +11,41 @@ left: '{{ left, humanize }} left' dropzone: "Drag and drop a file here or click to choose" +forms: + internship: + fields: + start-date: Internship start date + end-date: Internship end date + working-hours: Working time + total-hours: Total hours + weeks: Total weeks + first-name: First name + last-name: Last name + album: Album number + course: Course + semester: Semester + kind: Contract type + kind-other: Other - please fill + company-name: Company name + nip: NIP + e-mail: e-mail address + phone: Phone number + city: City + postal-code: Postal code + country: Country + street: Street + building: Building + help: + weeks: Calculated automatically + working-hours: Total working hours in working week + send-confirmation: > + Po wysłaniu zgłoszenia nie będzie możliwości jego zmiany do czasu zweryfikowania go przez pełnomocnika ds. Twojego + kierunku. Czy na pewno chcesz wysłać zgłoszenie praktyki w tej formie? + plan: + instructions: > + Wypełnij i zeskanuj Indywidualny program Praktyk a następnie wyślij go z pomocą tego formularza. <więcej informacji> + dropzone-help: Skan dokumentu w formacie PDF + student: name: first name surname: last name @@ -19,7 +54,41 @@ student: email: e-mail albumNumber: album number -sections: +internship: + intern: + semester: semesetr {{ semester, roman }} + album: "album number {{ album }}" + date-range: "{{ start, DD MMMM YYYY }} - {{ end, DD MMMM YYYY }}" + duration: "{{ duration, weeks }} week" + duration_plural: "{{ duration, weeks }} weeks" + hours: "{{ hours }} hour" + hours_plural: "{{ hours }} hours" + office: "Office / Address" + mentor: "Internship mentor" + address: + city: "{{ city }}, {{ country }}" + street: "{{ postalCode }}, {{ street }} {{ building }}" + sections: + intern-info: "Intern personal data" + duration: "Internship duration" + place: "Internship place" + kind: "Contract and programme" + mentor: "Internship mentor" + discard: + title: "Discard internship proposal" + info: "This comments will be presented to student in order to fix errors." + accept: + title: "Accept internship proposal" + info: "This comments will be presented to student." + +submission: + status: + awaiting: "sent, awaiting verification" + accepted: "accepted" + declined: "needs correction" + draft: "draft" + +pages: my-internship: header: "My internship" @@ -29,10 +98,22 @@ steps: info: > Your profile is incomplete. In order to continue your internship you have to supply information given below. In case of problem with providing those information - please contact with your internship coordinator of your course. + form: "Add missing data" internship-proposal: header: "Internship proposal" form: "Internship proposal form" - info: "" + info: + draft: > + Przed podjęciem praktyki należy ją zgłosić. (TODO) + awaiting: > + Twoje zgłoszenie musi zostać zweryfikowane i zatwierdzone. Po weryfikacji zostaniesz poinformowany o + akceptacji bądź konieczności wprowadzenia zmian. + accepted: > + Twoje zgłoszenie zostało zweryfikowane i zaakceptowane. + declined: > + Twoje zgłoszenie zostało zweryfikowane i odrzucone. Popraw zgłoszone uwagi i wyślij zgłoszenie ponownie. W razie + pytań możesz również skontaktować się z pełnomocnikiem ds. praktyk Twojego kierunku. + action: "Send internship proposal" plan: header: "Individual Internship Plan" info: "" diff --git a/translations/pl.yaml b/translations/pl.yaml index 6547b33..a82d788 100644 --- a/translations/pl.yaml +++ b/translations/pl.yaml @@ -27,12 +27,39 @@ discard: zgłoś uwagi dropzone: "Przeciągnij i upuść plik bądź kliknij, aby wybrać" -sections: +pages: my-internship: header: "Moja praktyka" + proposal-form: + header: "Propose internship" forms: internship: + fields: + start-date: Data rozpoczęcia praktyki + end-date: Data zakończenia praktyki + working-hours: Wymiar etatu + total-hours: Łączna liczba godzin + weeks: Liczba tygodni + first-name: Imię + last-name: Nazwisko + album: Numer albumu + course: Kierunek + semester: Semestr + kind: Rodzaj praktyki/umowy + kind-other: Inny - wprowadź + company-name: Nazwa firmy + nip: NIP + e-mail: Kontaktowy adres e-mail + phone: Numer telefonu + city: Miasto + postal-code: Kod pocztowy + country: Kraj + street: Ulica + building: Nr budynku + help: + weeks: Wartość wyliczana automatycznie + working-hours: Liczba godzin w tygodniu roboczym send-confirmation: > Po wysłaniu zgłoszenia nie będzie możliwości jego zmiany do czasu zweryfikowania go przez pełnomocnika ds. Twojego kierunku. Czy na pewno chcesz wysłać zgłoszenie praktyki w tej formie? @@ -63,9 +90,12 @@ internship: date-range: "{{ start, DD MMMM YYYY }} - {{ end, DD MMMM YYYY }}" duration_2: "{{ duration, weeks }} tygodni" duration_0: "{{ duration, weeks }} tydzień" - duration_1: "{{ count }} tygodnie" - hours: "{{ hours }} godzin" + duration_1: "{{ duration, weeks }} tygodnie" + hours_2: "{{ hours }} godzin" + hours_0: "{{ hours }} godzina" + hours_1: "{{ hours }} godziny" office: "Oddział / adres" + mentor: "Zakładowy opiekun praktyki" address: city: "{{ city }}, {{ country }}" street: "{{ postalCode }}, {{ street }} {{ building }}"