-
-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
3e61ac7
commit 4e0e257
Showing
22 changed files
with
333 additions
and
173 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import { Close } from "@mui/icons-material"; | ||
import { IconButton } from "@mui/material"; | ||
import { CSSProperties, ReactElement } from "react"; | ||
|
||
interface CloseButtonProps { | ||
close: () => void; | ||
} | ||
|
||
export default function CloseButton(props: CloseButtonProps): ReactElement { | ||
const closeButtonStyle: CSSProperties = { | ||
position: "absolute", | ||
top: 0, | ||
...(document.body.dir === "rtl" ? { left: 0 } : { right: 0 }), | ||
}; | ||
|
||
return ( | ||
<IconButton | ||
aria-label="close" | ||
onClick={props.close} | ||
style={closeButtonStyle} | ||
> | ||
<Close /> | ||
</IconButton> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import { Delete } from "@mui/icons-material"; | ||
import { ReactElement, useState } from "react"; | ||
|
||
import { IconButtonWithTooltip } from "components/Buttons"; | ||
import { CancelConfirmDialog } from "components/Dialogs"; | ||
|
||
interface DeleteButtonWithDialogProps { | ||
buttonId: string; | ||
buttonIdCancel?: string; | ||
buttonIdConfirm?: string; | ||
delete: () => void | Promise<void>; | ||
disabled?: boolean; | ||
textId: string; | ||
tooltipTextId?: string; | ||
} | ||
|
||
export default function DeleteButtonWithDialog( | ||
props: DeleteButtonWithDialogProps | ||
): ReactElement { | ||
const [open, setOpen] = useState(false); | ||
|
||
const handleConfirm = async (): Promise<void> => { | ||
await props.delete(); | ||
setOpen(false); | ||
}; | ||
|
||
return ( | ||
<> | ||
<IconButtonWithTooltip | ||
buttonId={props.buttonId} | ||
icon={<Delete />} | ||
onClick={props.disabled ? undefined : () => setOpen(true)} | ||
textId={props.tooltipTextId || props.textId} | ||
/> | ||
<CancelConfirmDialog | ||
buttonIdCancel={props.buttonIdCancel} | ||
buttonIdConfirm={props.buttonIdConfirm} | ||
handleCancel={() => setOpen(false)} | ||
handleConfirm={handleConfirm} | ||
open={open} | ||
textId={props.textId} | ||
/> | ||
</> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
85 changes: 85 additions & 0 deletions
85
src/components/Buttons/tests/DeleteButtonWithDialog.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
import { ReactTestRenderer, act, create } from "react-test-renderer"; | ||
|
||
import "tests/reactI18nextMock"; | ||
|
||
import DeleteButtonWithDialog from "components/Buttons/DeleteButtonWithDialog"; | ||
import { CancelConfirmDialog } from "components/Dialogs"; | ||
|
||
// Dialog uses portals, which are not supported in react-test-renderer. | ||
jest.mock("@mui/material", () => { | ||
const materialUiCore = jest.requireActual("@mui/material"); | ||
return { | ||
...jest.requireActual("@mui/material"), | ||
Dialog: materialUiCore.Container, | ||
}; | ||
}); | ||
|
||
const mockDelete = jest.fn(); | ||
const buttonId = "button-id"; | ||
const buttonIdCancel = "button-id-cancel"; | ||
const buttonIdConfirm = "button-id-confirm"; | ||
const textId = "text-id"; | ||
|
||
let cellHandle: ReactTestRenderer; | ||
|
||
const renderDeleteCell = async (): Promise<void> => { | ||
await act(async () => { | ||
cellHandle = create( | ||
<DeleteButtonWithDialog | ||
buttonId={buttonId} | ||
buttonIdCancel={buttonIdCancel} | ||
buttonIdConfirm={buttonIdConfirm} | ||
delete={mockDelete} | ||
textId={textId} | ||
/> | ||
); | ||
}); | ||
}; | ||
|
||
beforeEach(async () => { | ||
jest.clearAllMocks(); | ||
await renderDeleteCell(); | ||
}); | ||
|
||
describe("DeleteCell", () => { | ||
it("has working dialog buttons", async () => { | ||
const dialog = cellHandle.root.findByType(CancelConfirmDialog); | ||
const deleteButton = cellHandle.root.findByProps({ id: buttonId }); | ||
|
||
expect(dialog.props.open).toBeFalsy(); | ||
await act(async () => { | ||
deleteButton.props.onClick(); | ||
}); | ||
expect(dialog.props.open).toBeTruthy(); | ||
const cancelButton = cellHandle.root.findByProps({ id: buttonIdCancel }); | ||
await act(async () => { | ||
cancelButton.props.onClick(); | ||
}); | ||
expect(dialog.props.open).toBeFalsy(); | ||
await act(async () => { | ||
deleteButton.props.onClick(); | ||
}); | ||
expect(dialog.props.open).toBeTruthy(); | ||
const confButton = cellHandle.root.findByProps({ id: buttonIdConfirm }); | ||
await act(async () => { | ||
await confButton.props.onClick(); | ||
}); | ||
expect(dialog.props.open).toBeFalsy(); | ||
}); | ||
|
||
it("only deletes after confirmation", async () => { | ||
const deleteButton = cellHandle.root.findByProps({ id: buttonId }); | ||
|
||
await act(async () => { | ||
deleteButton.props.onClick(); | ||
cellHandle.root.findByProps({ id: buttonIdCancel }).props.onClick(); | ||
deleteButton.props.onClick(); | ||
}); | ||
expect(mockDelete).not.toHaveBeenCalled(); | ||
const confButton = cellHandle.root.findByProps({ id: buttonIdConfirm }); | ||
await act(async () => { | ||
await confButton.props.onClick(); | ||
}); | ||
expect(mockDelete).toHaveBeenCalled(); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
import { Grid, Typography } from "@mui/material"; | ||
import { FormEvent, ReactElement, useState } from "react"; | ||
import { useTranslation } from "react-i18next"; | ||
|
||
import { FileInputButton, LoadingDoneButton } from "components/Buttons"; | ||
|
||
interface ImageUploadProps { | ||
doneCallback?: () => void; | ||
uploadImage: (imgFile: File) => Promise<void>; | ||
} | ||
|
||
/** | ||
* Allows the current user to select an image and upload it | ||
*/ | ||
export default function ImageUpload(props: ImageUploadProps): ReactElement { | ||
const [file, setFile] = useState<File>(); | ||
const [filename, setFilename] = useState<string>(); | ||
const [loading, setLoading] = useState<boolean>(false); | ||
const [done, setDone] = useState<boolean>(false); | ||
const { t } = useTranslation(); | ||
|
||
function updateFile(file: File): void { | ||
if (file) { | ||
setFile(file); | ||
setFilename(file.name); | ||
} | ||
} | ||
|
||
async function upload(e: FormEvent<EventTarget>): Promise<void> { | ||
e.preventDefault(); | ||
e.stopPropagation(); | ||
if (file) { | ||
setLoading(true); | ||
await props | ||
.uploadImage(file) | ||
.then(onDone) | ||
.catch(() => setLoading(false)); | ||
} | ||
} | ||
|
||
async function onDone(): Promise<void> { | ||
setDone(true); | ||
if (props.doneCallback) { | ||
setTimeout(props.doneCallback, 500); | ||
} | ||
} | ||
|
||
return ( | ||
<form onSubmit={(e) => upload(e)}> | ||
{/* Displays the name of the selected file */} | ||
{filename && ( | ||
<Typography variant="body1" noWrap> | ||
{t("createProject.fileSelected")}: {filename} | ||
</Typography> | ||
)} | ||
<Grid container spacing={1} justifyContent="flex-start"> | ||
<Grid item> | ||
<FileInputButton | ||
updateFile={(file) => updateFile(file)} | ||
accept="image/*" | ||
> | ||
{t("buttons.browse")} | ||
</FileInputButton> | ||
</Grid> | ||
<Grid item> | ||
<LoadingDoneButton | ||
loading={loading} | ||
done={done} | ||
buttonProps={{ type: "submit", id: "image-upload-save" }} | ||
> | ||
{t("buttons.save")} | ||
</LoadingDoneButton> | ||
</Grid> | ||
</Grid> | ||
</form> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import { Dialog, DialogContent, DialogTitle } from "@mui/material"; | ||
import { ReactElement } from "react"; | ||
import { useTranslation } from "react-i18next"; | ||
|
||
import UploadImage from "components/Dialogs/UploadImage"; | ||
|
||
interface UploadImageDialogProps { | ||
close: () => void; | ||
open: boolean; | ||
titleId: string; | ||
uploadImage: (imageFile: File) => Promise<void>; | ||
} | ||
|
||
export default function UploadImageDialog( | ||
props: UploadImageDialogProps | ||
): ReactElement { | ||
const { t } = useTranslation(); | ||
|
||
return ( | ||
<Dialog onClose={props.close} open={props.open}> | ||
<DialogTitle>{t(props.titleId)}</DialogTitle> | ||
<DialogContent> | ||
<UploadImage | ||
doneCallback={props.close} | ||
uploadImage={props.uploadImage} | ||
/> | ||
</DialogContent> | ||
</Dialog> | ||
); | ||
} |
Oops, something went wrong.