feat: show confirm dialog when editing case or steps
This commit is contained in:
@@ -216,7 +216,8 @@
|
|||||||
"delete_file": "Delete file",
|
"delete_file": "Delete file",
|
||||||
"click_to_upload": "Click to upload",
|
"click_to_upload": "Click to upload",
|
||||||
"or_drag_and_drop": "or drag and drop",
|
"or_drag_and_drop": "or drag and drop",
|
||||||
"max_file_size": "Max. file size"
|
"max_file_size": "Max. file size",
|
||||||
|
"are_you_sure_leave": "Are you sure you want to leave the page?"
|
||||||
},
|
},
|
||||||
"Runs": {
|
"Runs": {
|
||||||
"run_list": "Test Run List",
|
"run_list": "Test Run List",
|
||||||
|
|||||||
@@ -215,7 +215,8 @@
|
|||||||
"delete_file": "ファイルを削除",
|
"delete_file": "ファイルを削除",
|
||||||
"click_to_upload": "クリックしてアップロード",
|
"click_to_upload": "クリックしてアップロード",
|
||||||
"or_drag_and_drop": "またはドラッグアンドドロップ",
|
"or_drag_and_drop": "またはドラッグアンドドロップ",
|
||||||
"max_file_size": "最大ファイルサイズ"
|
"max_file_size": "最大ファイルサイズ",
|
||||||
|
"are_you_sure_leave": "ページを離れてもよろしいですか?"
|
||||||
},
|
},
|
||||||
"Runs": {
|
"Runs": {
|
||||||
"run_list": "テストラン一覧",
|
"run_list": "テストラン一覧",
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { fetchCase, updateCase } from '@/utils/caseControl';
|
|||||||
import { updateSteps } from './stepControl';
|
import { updateSteps } from './stepControl';
|
||||||
import { fetchCreateAttachments, fetchDownloadAttachment, fetchDeleteAttachment } from './attachmentControl';
|
import { fetchCreateAttachments, fetchDownloadAttachment, fetchDeleteAttachment } from './attachmentControl';
|
||||||
import { TokenContext } from '@/utils/TokenProvider';
|
import { TokenContext } from '@/utils/TokenProvider';
|
||||||
|
import { useFormGuard } from '@/utils/formGuard';
|
||||||
|
|
||||||
const defaultTestCase = {
|
const defaultTestCase = {
|
||||||
id: 0,
|
id: 0,
|
||||||
@@ -44,9 +45,12 @@ export default function CaseEditor({ projectId, folderId, caseId, messages, loca
|
|||||||
const [isTitleInvalid, setIsTitleInvalid] = useState<boolean>(false);
|
const [isTitleInvalid, setIsTitleInvalid] = useState<boolean>(false);
|
||||||
const [isUpdating, setIsUpdating] = useState<boolean>(false);
|
const [isUpdating, setIsUpdating] = useState<boolean>(false);
|
||||||
const [plusCount, setPlusCount] = useState<number>(0);
|
const [plusCount, setPlusCount] = useState<number>(0);
|
||||||
|
const [isDirty, setIsDirty] = useState(false);
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
useFormGuard(isDirty, messages.areYouSureLeave);
|
||||||
|
|
||||||
const onPlusClick = async (newStepNo: number) => {
|
const onPlusClick = async (newStepNo: number) => {
|
||||||
|
setIsDirty(true);
|
||||||
const newStep: StepType = {
|
const newStep: StepType = {
|
||||||
id: plusCount,
|
id: plusCount,
|
||||||
step: '',
|
step: '',
|
||||||
@@ -86,6 +90,8 @@ export default function CaseEditor({ projectId, folderId, caseId, messages, loca
|
|||||||
};
|
};
|
||||||
|
|
||||||
const onDeleteClick = async (stepId: number) => {
|
const onDeleteClick = async (stepId: number) => {
|
||||||
|
setIsDirty(true);
|
||||||
|
|
||||||
// find deletedStep's stepNo
|
// find deletedStep's stepNo
|
||||||
if (testCase.Steps) {
|
if (testCase.Steps) {
|
||||||
const deletedStep = testCase.Steps.find((step) => step.id === stepId);
|
const deletedStep = testCase.Steps.find((step) => step.id === stepId);
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ export default function Page({
|
|||||||
clickToUpload: t('click_to_upload'),
|
clickToUpload: t('click_to_upload'),
|
||||||
orDragAndDrop: t('or_drag_and_drop'),
|
orDragAndDrop: t('or_drag_and_drop'),
|
||||||
maxFileSize: t('max_file_size'),
|
maxFileSize: t('max_file_size'),
|
||||||
|
areYouSureLeave: t('are_you_sure_leave'),
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -131,6 +131,7 @@ export type CaseMessages = {
|
|||||||
clickToUpload: string;
|
clickToUpload: string;
|
||||||
orDragAndDrop: string;
|
orDragAndDrop: string;
|
||||||
maxFileSize: string;
|
maxFileSize: string;
|
||||||
|
areYouSureLeave: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export { CaseType, StepType, AttachmentType, CaseTypeCountType, CasePriorityCountType, CasesMessages, CaseMessages };
|
export { CaseType, StepType, AttachmentType, CaseTypeCountType, CasePriorityCountType, CasesMessages, CaseMessages };
|
||||||
|
|||||||
30
frontend/utils/formGuard.ts
Normal file
30
frontend/utils/formGuard.ts
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import { useEffect } from 'react';
|
||||||
|
|
||||||
|
export const useFormGuard = (isDirty: boolean, confirmText: string) => {
|
||||||
|
useEffect(() => {
|
||||||
|
console.log(isDirty);
|
||||||
|
const handleClick = (event: MouseEvent) => {
|
||||||
|
if (isDirty && event.target instanceof Element && event.target.closest('a:not([target="_blank"]')) {
|
||||||
|
if (!window.confirm(confirmText)) {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleBeforeUnload = (event: BeforeUnloadEvent) => {
|
||||||
|
if (isDirty) {
|
||||||
|
event.preventDefault();
|
||||||
|
return (event.returnValue = '');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
window.addEventListener('beforeunload', handleBeforeUnload);
|
||||||
|
window.addEventListener('click', handleClick, true);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener('beforeunload', handleBeforeUnload);
|
||||||
|
window.removeEventListener('click', handleClick, true);
|
||||||
|
};
|
||||||
|
}, [isDirty]);
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user