polish up internship proposal preview

This commit is contained in:
Kacper Donat 2020-08-10 20:11:30 +02:00
parent 5316630a29
commit fb03b892a2
9 changed files with 84 additions and 43 deletions

View File

@ -1,14 +1,8 @@
import React, { HTMLProps } from "react"; import React, { HTMLProps } from "react";
import { makeStyles } from "@material-ui/core/styles"; import { useHorizontalSpacing } from "@/styles";
export const Actions = (props: HTMLProps<HTMLDivElement>) => { export const Actions = (props: HTMLProps<HTMLDivElement>) => {
const classes = makeStyles(theme => ({ const classes = useHorizontalSpacing(1);
root: {
"& > *": {
marginRight: theme.spacing(1)
}
}
}))();
return <div className={ classes.root } { ...props }/> return <div className={ classes.root } { ...props }/>
} }

View File

@ -1,9 +1,14 @@
import { Internship } from "@/data"; import { Internship, internshipTypeLabels } from "@/data";
import React from "react"; import React from "react";
import { Paper, PaperProps, Typography, TypographyProps } from "@material-ui/core"; import { Button, Paper, PaperProps, Typography, TypographyProps } from "@material-ui/core";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { createStyles, makeStyles } from "@material-ui/core/styles"; import { createStyles, makeStyles } from "@material-ui/core/styles";
import classNames from "classnames"; import classNames from "classnames";
import { Link as RouterLink } from "react-router-dom";
import { route } from "@/routing";
import { Actions } from "@/components/actions";
import { useVerticalSpacing } from "@/styles";
import moment from "moment";
export type ProposalPreviewProps = { export type ProposalPreviewProps = {
proposal: Internship; proposal: Internship;
@ -16,7 +21,6 @@ const Label = ({ children }: TypographyProps) => {
const useSectionStyles = makeStyles(theme => createStyles({ const useSectionStyles = makeStyles(theme => createStyles({
root: { root: {
padding: theme.spacing(2), padding: theme.spacing(2),
marginTop: theme.spacing(3)
} }
})) }))
@ -31,30 +35,19 @@ const Section = ({ children, ...props }: PaperProps) => {
export const ProposalPreview = ({ proposal }: ProposalPreviewProps) => { export const ProposalPreview = ({ proposal }: ProposalPreviewProps) => {
const { t } = useTranslation(); const { t } = useTranslation();
return <div className="proposal"> const classes = useVerticalSpacing(3);
const duration = moment.duration(proposal.endDate.diff(proposal.startDate));
return <div className={ classNames("proposal", classes.root) }>
<div>
<Typography className="proposal__primary">{ proposal.intern.name } { proposal.intern.surname }</Typography> <Typography className="proposal__primary">{ proposal.intern.name } { proposal.intern.surname }</Typography>
<Typography className="proposal__secondary"> <Typography className="proposal__secondary">
{ t('internship.intern.semester', { semester: proposal.intern.semester }) } { t('internship.intern.semester', { semester: proposal.intern.semester }) }
{ ", " } { ", " }
{ t('internship.intern.album', { album: proposal.intern.albumNumber }) } { t('internship.intern.album', { album: proposal.intern.albumNumber }) }
</Typography> </Typography>
</div>
<Section>
<Label>{ t('internship.sections.kind') }</Label>
<Typography className="proposal__primary">{ proposal.type }</Typography>
</Section>
<Section>
<Label>{ t('internship.sections.duration') }</Label>
<Typography className="proposal__primary">
{ t('internship.date-range', { start: proposal.startDate, end: proposal.endDate }) }
</Typography>
<Typography className="proposal__secondary">
{ t('internship.duration', { duration: 0 })}
{ ", " }
{ t('internship.hours', { hours: proposal.hours })}
</Typography>
</Section>
<Section> <Section>
<Label>{ t('internship.sections.place') }</Label> <Label>{ t('internship.sections.place') }</Label>
@ -64,12 +57,39 @@ export const ProposalPreview = ({ proposal }: ProposalPreviewProps) => {
<Typography className="proposal__secondary"> <Typography className="proposal__secondary">
NIP: { proposal.company.nip } NIP: { proposal.company.nip }
</Typography> </Typography>
</Section>
<Section>
<Label>{ t('internship.office') }</Label> <Label>{ t('internship.office') }</Label>
<Typography className="proposal__primary">{ t('internship.address.city', proposal.office.address) }</Typography> <Typography className="proposal__primary">{ t('internship.address.city', proposal.office.address) }</Typography>
<Typography className="proposal__secondary">{ t('internship.address.street', proposal.office.address) }</Typography> <Typography className="proposal__secondary">{ t('internship.address.street', proposal.office.address) }</Typography>
</Section> </Section>
<Section>
<Label>{ t('internship.sections.kind') }</Label>
<Typography className="proposal__primary">{ internshipTypeLabels[proposal.type].label }</Typography>
</Section>
<Section>
<Label>{ t('internship.sections.duration') }</Label>
<Typography className="proposal__primary">
{ t('internship.date-range', { start: proposal.startDate, end: proposal.endDate }) }
</Typography>
<Typography className="proposal__secondary">
{ t('internship.duration', { duration }) }
{ ", " }
{ t('internship.hours', { hours: proposal.hours }) }
</Typography>
</Section>
<Section>
<Label>{ t('internship.sections.mentor') }</Label>
<Typography className="proposal__primary">{ proposal.mentor.name } { proposal.mentor.surname }</Typography>
<Typography className="proposal__secondary">{ proposal.mentor.email }, { proposal.mentor.phone }</Typography>
</Section>
<Actions>
<Button component={ RouterLink } to={ route("home") } variant="contained" color="primary">
{ t('go-back') }
</Button>
</Actions>
</div> </div>
} }

View File

@ -182,13 +182,13 @@ export const InternshipForm: React.FunctionComponent<InternshipFormProps> = prop
return ( return (
<div className="internship-form"> <div className="internship-form">
<Typography variant="h3" className="section-header">{ t('internship.intern-info') }</Typography> <Typography variant="h3" className="section-header">{ t('internship.sections.intern-info') }</Typography>
<StudentForm student={ sampleStudent }/> <StudentForm student={ sampleStudent }/>
<Typography variant="h3" className="section-header">{ t('internship.kind' )}</Typography> <Typography variant="h3" className="section-header">{ t('internship.sections.kind' )}</Typography>
<InternshipProgramForm internship={ internship } onChange={ setInternship }/> <InternshipProgramForm internship={ internship } onChange={ setInternship }/>
<Typography variant="h3" className="section-header">{ t('internship.duration') }</Typography> <Typography variant="h3" className="section-header">{ t('internship.sections.duration') }</Typography>
<InternshipDurationForm internship={ internship } onChange={ setInternship }/> <InternshipDurationForm internship={ internship } onChange={ setInternship }/>
<Typography variant="h3" className="section-header">{ t('internship.place') }</Typography> <Typography variant="h3" className="section-header">{ t('internship.sections.place') }</Typography>
<CompanyForm internship={ internship } onChange={ setInternship }/> <CompanyForm internship={ internship } onChange={ setInternship }/>
<Actions> <Actions>
<Button variant="contained" color="primary" onClick={ handleSubmitConfirmation }>{ t("confirm") }</Button> <Button variant="contained" color="primary" onClick={ handleSubmitConfirmation }>{ t("confirm") }</Button>

View File

@ -1,9 +1,10 @@
import { Dispatch, SetStateAction, useEffect, useState } from "react"; import { Dispatch, SetStateAction, useState } from "react";
export function useProxyState<T>(initial: T, setter: (value: T) => void): [T, Dispatch<SetStateAction<T>>] { export function useProxyState<T>(initial: T, setter: (value: T) => void): [T, Dispatch<SetStateAction<T>>] {
const [value, proxy] = useState<T>(initial); const [value, proxy] = useState<T>(initial);
useEffect(() => setter(value), [ value ]); return [value, (newValue: SetStateAction<T>) => {
proxy(newValue);
return [value, proxy]; setter(typeof newValue === "function" ? (newValue as any)(value) : newValue);
}];
} }

View File

@ -1,6 +1,7 @@
import { Internship, InternshipType } from "@/data"; import { Internship, InternshipType } from "@/data";
import { Serializable, SerializationTransformer } from "@/serialization/types"; import { Serializable, SerializationTransformer } from "@/serialization/types";
import { momentSerializationTransformer } from "@/serialization/moment"; import { momentSerializationTransformer } from "@/serialization/moment";
import { Moment } from "moment";
export const internshipSerializationTransformer: SerializationTransformer<Internship> = { export const internshipSerializationTransformer: SerializationTransformer<Internship> = {
transform: (internship: Internship): Serializable<Internship> => ({ transform: (internship: Internship): Serializable<Internship> => ({
@ -10,8 +11,8 @@ export const internshipSerializationTransformer: SerializationTransformer<Intern
}), }),
reverseTransform: (serialized: Serializable<Internship>): Internship => ({ reverseTransform: (serialized: Serializable<Internship>): Internship => ({
...serialized, ...serialized,
startDate: momentSerializationTransformer.reverseTransform(serialized.startDate), startDate: momentSerializationTransformer.reverseTransform(serialized.startDate) as Moment,
endDate: momentSerializationTransformer.reverseTransform(serialized.endDate), endDate: momentSerializationTransformer.reverseTransform(serialized.endDate) as Moment,
type: serialized.type as InternshipType, type: serialized.type as InternshipType,
}), }),
} }

1
src/styles/index.ts Normal file
View File

@ -0,0 +1 @@
export * from "./spacing"

View File

@ -16,3 +16,7 @@
.proposal__primary { .proposal__primary {
font-size: 1.675rem; font-size: 1.675rem;
} }
.proposal__header:not(:first-child) {
margin-top: 1rem;
}

19
src/styles/spacing.ts Normal file
View File

@ -0,0 +1,19 @@
import { createStyles, makeStyles } from "@material-ui/core/styles";
const defaultSpacing: number = 3;
export const useVerticalSpacing = makeStyles(theme => createStyles({
root: {
"& > *:not(:last-child)": {
marginBottom: (spacing: number = defaultSpacing) => theme.spacing(spacing)
}
}
}))
export const useHorizontalSpacing = makeStyles(theme => createStyles({
root: {
"& > *:not(:last-child)": {
marginRight: (spacing: number = defaultSpacing) => theme.spacing(spacing)
}
}
}))

View File

@ -57,7 +57,7 @@ internship:
semester: semestr {{ semester, roman }} semester: semestr {{ semester, roman }}
album: "numer albumu {{ album }}" album: "numer albumu {{ album }}"
date-range: "{{ start, DD MMMM YYYY }} - {{ end, DD MMMM YYYY }}" date-range: "{{ start, DD MMMM YYYY }} - {{ end, DD MMMM YYYY }}"
duration: "{{ duration, humanize }} tygodni" duration: "{{ duration, humanize }}"
hours: "{{ hours }} godzin" hours: "{{ hours }} godzin"
office: "Oddział / adres" office: "Oddział / adres"
address: address:
@ -68,6 +68,7 @@ internship:
duration: "Czas trwania praktyki" duration: "Czas trwania praktyki"
place: "Miejsce odbywania praktyki" place: "Miejsce odbywania praktyki"
kind: "Rodzaj i program praktyki" kind: "Rodzaj i program praktyki"
mentor: "Zakładowy opiekun praktyki"
steps: steps: