Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add styling of edit/add worker component inside drawer #128

Merged
merged 12 commits into from
Jan 5, 2021
8 changes: 8 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
"react-redux": "^7.2.1",
"react-router-dom": "^5.2.0",
"react-scripts": "^3.4.3",
"react-text-mask": "^5.4.3",
"redux": "^4.0.5",
"redux-devtools-extension": "^2.13.8",
"redux-thunk": "^2.1.0",
Expand Down
6 changes: 5 additions & 1 deletion src/assets/styles/styles/custom/_dropdown.scss
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
right: -10px;
padding-bottom: 10px;
padding-top: 25px;
max-width: 119px;
width: calc(100% - 20px);

button {
width: 100%;
Expand All @@ -33,6 +33,10 @@
}
}

.dropdown-buttons-z-index {
z-index: 1300;
}

.display-main-button {
position: relative;
top: -43px;
Expand Down
16 changes: 16 additions & 0 deletions src/common-models/worker-info.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,22 @@ export class WorkerTypeHelper {
}
}

export enum ContractType {
EMPLOYMENT_CONTRACT = "EMPLOYMENT_CONTRACT",
CIVIL_CONTRACT = "CIVIL_CONTRACT",
}

export class ContractTypeHelper {
static translate(type: ContractType): string {
switch (type) {
case ContractType.EMPLOYMENT_CONTRACT:
return "umowa o pracę";
case ContractType.CIVIL_CONTRACT:
return "umowa zlecenie";
}
}
}

export interface WorkersInfoModel {
time: { [key: string]: number };
type: { [workerName: string]: WorkerType };
Expand Down
12 changes: 10 additions & 2 deletions src/components/common-components/drawer/drawer.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { MdClose } from "react-icons/md";
import React from "react";
import { makeStyles } from "@material-ui/core/styles";
import ScssVars from "../../../assets/styles/styles/custom/_variables.module.scss";
import classNames from "classnames";

const useStyles = makeStyles({
drawer: {
Expand All @@ -21,6 +22,9 @@ const useStyles = makeStyles({
paddingRight: 24,
paddingBottom: 15,
},
fullHeight: {
height: "100%",
},
exitButton: {
margin: "-7px -8px",
marginTop: -15,
Expand Down Expand Up @@ -57,15 +61,19 @@ export default function Drawer(options: DrawerOptions): JSX.Element {
<h1 className={classes.title}>{title}</h1>
</Grid>
<Grid item>
<IconButton className={classes.exitButton} onClick={(): void => setOpen(false)}>
<IconButton
className={classes.exitButton}
data-cy="exit-drawer"
onClick={(): void => setOpen(false)}
>
<MdClose />
</IconButton>
</Grid>
</Grid>

<Divider />

<Box className={classes.drawerContentMargin}>{children}</Box>
<Box className={classNames(classes.drawerContentMargin, classes.fullHeight)}>{children}</Box>
</MaterialDrawer>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,12 @@ export function DropdownButtons({
{mainLabel}
<ArrowDropDownIcon />
</Button>
<Popper open={open} placement="bottom" anchorEl={anchorRef.current}>
<Popper
className="dropdown-buttons-z-index"
open={open}
placement="bottom"
anchorEl={anchorRef.current}
>
<div
className={`${
variant === "outlined" ? "display-main-button-outlined" : "display-main-button"
Expand Down
162 changes: 162 additions & 0 deletions src/components/namestable/worker-edit.component.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
import { ContractType, WorkerInfoModel, WorkerType } from "../../common-models/worker-info.model";
import React, { useState } from "react";
import { makeStyles } from "@material-ui/core/styles";
import { Grid, Input, TextField, Typography } from "@material-ui/core";
import { DropdownButtons } from "../common-components/dropdown-buttons/dropdown-buttons.component";
import {
translateAndCapitalizeContractType,
translateAndCapitalizeWorkerType,
} from "./worker-edit.helper";
import MaskedInput from "react-text-mask";
import { Button } from "../common-components";

const useStyles = makeStyles({
container: {
height: "100%",
},
label: {
fontSize: 16,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Size jest w stałych w plikach scss

fontWeight: 700,
lineHeight: 1.75,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To też bym dał do stałych

},
});

export interface WorkerInfoExtendedInterface {
name: string;
workerType: WorkerType | undefined;
contractType: ContractType | undefined;
employmentTime: string;
civilTime: string;
}

export function WorkerEditComponent(info: WorkerInfoModel): JSX.Element {
const classes = useStyles();

const [workerInfo, setWorkerInfo] = useState<WorkerInfoExtendedInterface>({
name: info.name,
workerType: info.type,
contractType: undefined,
employmentTime: " / ",
civilTime: "0",
});

function handleUpdate(event) {
const { target } = event;
updateWorkerInfo(target.name, target.value);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Imo tak jest ładniej

 function handleUpdate(event) {
    const { name, value } = event.target;
    updateWorkerInfo(name, value);
  }

}

function updateWorkerInfo(key, value) {
setWorkerInfo({ ...workerInfo, [key]: value });
}

const positionOptions = Object.keys(WorkerType).map((workerTypeName) => {
const workerType = WorkerType[workerTypeName];
return {
label: translateAndCapitalizeWorkerType(workerType),
action: () => updateWorkerInfo("workerType", workerType),
};
});

const contractOptions = Object.keys(ContractType).map((contractTypeName) => {
const contractType = ContractType[contractTypeName];
return {
label: translateAndCapitalizeContractType(contractType),
action: () => updateWorkerInfo("contractType", contractType),
};
});

return (
<Grid container className={classes.container} direction="column" justify="space-between">
<Grid item>
<Grid container direction="column" spacing={5}>
<Grid item xs={9}>
<Typography className={classes.label}>Imię i nazwisko</Typography>
<TextField
fullWidth
name="name"
data-cy="name"
value={workerInfo.name}
onChange={handleUpdate}
color="primary"
/>
</Grid>
<Grid item xs={6}>
<Typography className={classes.label}>Stanowisko</Typography>
<DropdownButtons
data-cy="position"
buttons={positionOptions}
mainLabel={
workerInfo.workerType
? translateAndCapitalizeWorkerType(workerInfo.workerType)
: "Stanowisko"
}
variant="outlined"
/>
</Grid>
<Grid item xs={6}>
<Typography className={classes.label}>Wymiar pracy</Typography>
<DropdownButtons
data-cy="contract"
buttons={contractOptions}
mainLabel={
workerInfo.contractType
? translateAndCapitalizeContractType(workerInfo.contractType)
: "Typ umowy"
}
variant="outlined"
/>
</Grid>
{workerInfo.contractType === ContractType.EMPLOYMENT_CONTRACT && (
<Grid item xs={6}>
<Typography className={classes.label}>Wpisz wymiar etatu</Typography>
<TextField
fullWidth
name="civilTime"
data-cy="civilTime"
value={workerInfo.civilTime}
type="number"
onChange={handleUpdate}
color="primary"
/>
</Grid>
)}
{workerInfo.contractType === ContractType.CIVIL_CONTRACT && (
<Grid item xs={6}>
<Typography className={classes.label}>Ilość godzin</Typography>
<Input
fullWidth
name="employmentTime"
value={workerInfo.employmentTime}
onChange={handleUpdate}
data-cy="hours-number"
inputComponent={TextMaskCustom as any}
/>
</Grid>
)}
</Grid>
</Grid>
<Grid item>
<Button>Zapisz pracownika</Button>
</Grid>
</Grid>
);
}

interface TextMaskCustomProps {
inputRef: (ref: HTMLInputElement | null) => void;
}

function TextMaskCustom(props: TextMaskCustomProps) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Taki komponent dałbym do folderu ze wspólnymi komponentami, bo może gdzieś będziemy tego reużywać

const { inputRef, ...other } = props;

return (
<MaskedInput
{...other}
ref={(ref: any) => {
inputRef(ref ? ref.inputElement : null);
}}
mask={[/[1-9]/, "/", /[1-9]/]}
showMask
/>
);
}
17 changes: 17 additions & 0 deletions src/components/namestable/worker-edit.helper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import {
WorkerTypeHelper,
WorkerType,
ContractType,
ContractTypeHelper,
} from "../../common-models/worker-info.model";
import { StringHelper } from "../../helpers/string.helper";

export function translateAndCapitalizeWorkerType(workerType: WorkerType): string {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nie umieszczamy helperów w komponentach. Jeśli kod jest wykorzystywany w jednym komponencie to dodajemy go tylko tam. Jeśli może pojawić się potrzeba ponownego wykorzystania to należy to wrzucić do folderu jakiegoś istniejącego helpera z helpers albo dodać nowego.
Dodatkowo ten kod dla translateAndCapitalizeWorkerType oraz translateAndCapitalizeContractType jest powtórzony. Można stworzyć jedną generyczną funkcję - translateAndCapitalize, która przyjmuje 2 parametry: pierwszy to helper, a drugi coś co helper może przetłumaczyć.

const translation = WorkerTypeHelper.translate(workerType);
return StringHelper.capitalize(translation);
}

export function translateAndCapitalizeContractType(contractType: ContractType): string {
const translation = ContractTypeHelper.translate(contractType);
return StringHelper.capitalize(translation);
}
2 changes: 1 addition & 1 deletion src/components/namestable/worker-info.component.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import classNames from "classnames/bind";
import React from "react";
import {
WorkerInfoModel,
Expand All @@ -8,6 +7,7 @@ import {
import { StringHelper } from "../../helpers/string.helper";
import WorkersCalendar from "../workers-page/workers-calendar/workers-calendar.component";
import { Divider } from "@material-ui/core";
import classNames from "classnames/bind";

export function WorkerInfoComponent(info: WorkerInfoModel): JSX.Element {
return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from "react";
import Drawer, { DrawerOptions } from "../../common-components/drawer/drawer.component";
import { WorkerInfoModel } from "../../../common-models/worker-info.model";
import { WorkerInfoComponent } from "../../namestable/worker-info.component";
import { WorkerEditComponent } from "../../namestable/worker-edit.component";

export enum WorkerDrawerMode {
EDIT,
Expand Down Expand Up @@ -29,9 +30,10 @@ export default function WorkerDrawerComponent(options: WorkerDrawerOptions): JSX
const { mode, worker, setOpen, ...otherOptions } = options;
const title = getTitle(mode);
const isInfo = mode === WorkerDrawerMode.INFO;
const isEdit = mode === WorkerDrawerMode.EDIT;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@maciekb05
Na razie w celach developmentu można ustawić w tym miejscu na sztywno EditMode

https://github.com/Project-Summer-AI-Lab-Glider/nurse-scheduling-problem-frontend/blob/b3cd626e7e08318b7a0c3a3f3433ddb9b6c195c5/src/components/namestable/nametable-section.component.tsx#L19

Ja będę wprowadzać teraz te dwa róźne tryby i dodam jakieś rozrózróźnienie między nimi

return (
<Drawer setOpen={setOpen} title={title} {...otherOptions}>
{worker && <h1>{worker.name}</h1>}
{isEdit && worker && <WorkerEditComponent {...worker} />}

{isInfo && WorkerInfoComponent(worker ?? { name: "", time: 0 })}
</Drawer>
Expand Down