mirror of
https://github.com/usebruno/bruno.git
synced 2025-03-20 10:16:42 +01:00
Refact: single modal component for saving requests
This commit is contained in:
parent
453dc4d6dc
commit
bc07087028
@ -1,49 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import { IconAlertTriangle } from '@tabler/icons';
|
|
||||||
import Modal from 'components/Modal';
|
|
||||||
|
|
||||||
const ConfirmRequestClose = ({ item, onCancel, onCloseWithoutSave, onSaveAndClose }) => {
|
|
||||||
return (
|
|
||||||
<Modal
|
|
||||||
size="md"
|
|
||||||
title="Unsaved changes"
|
|
||||||
confirmText="Save and Close"
|
|
||||||
cancelText="Close without saving"
|
|
||||||
disableEscapeKey={true}
|
|
||||||
disableCloseOnOutsideClick={true}
|
|
||||||
closeModalFadeTimeout={150}
|
|
||||||
handleCancel={onCancel}
|
|
||||||
onClick={(e) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
e.preventDefault();
|
|
||||||
}}
|
|
||||||
hideFooter={true}
|
|
||||||
>
|
|
||||||
<div className="flex items-center font-normal">
|
|
||||||
<IconAlertTriangle size={32} strokeWidth={1.5} className="text-yellow-600" />
|
|
||||||
<h1 className="ml-2 text-lg font-semibold">Hold on..</h1>
|
|
||||||
</div>
|
|
||||||
<div className="font-normal mt-4">
|
|
||||||
You have unsaved changes in request <span className="font-semibold">{item.name}</span>.
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex justify-between mt-6">
|
|
||||||
<div>
|
|
||||||
<button className="btn btn-sm btn-danger" onClick={onCloseWithoutSave}>
|
|
||||||
Don't Save
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<button className="btn btn-close btn-sm mr-2" onClick={onCancel}>
|
|
||||||
Cancel
|
|
||||||
</button>
|
|
||||||
<button className="btn btn-secondary btn-sm" onClick={onSaveAndClose}>
|
|
||||||
Save
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Modal>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default ConfirmRequestClose;
|
|
@ -1,15 +1,13 @@
|
|||||||
import React, { useState, useRef, Fragment } from 'react';
|
import React, { useState, useRef, Fragment } from 'react';
|
||||||
import get from 'lodash/get';
|
import get from 'lodash/get';
|
||||||
import { closeTabs } from 'providers/ReduxStore/slices/tabs';
|
import { closeTabs } from 'providers/ReduxStore/slices/tabs';
|
||||||
import { saveMultipleRequests, saveRequest } from 'providers/ReduxStore/slices/collections/actions';
|
import SaveRequestsModal from 'components/SaveRequestsModal';
|
||||||
import SaveRequestsModal from 'providers/App/ConfirmAppClose/SaveRequestsModal';
|
|
||||||
import { deleteRequestDraft } from 'providers/ReduxStore/slices/collections';
|
import { deleteRequestDraft } from 'providers/ReduxStore/slices/collections';
|
||||||
import { useTheme } from 'providers/Theme';
|
import { useTheme } from 'providers/Theme';
|
||||||
import { useDispatch, useSelector } from 'react-redux';
|
import { useDispatch, useSelector } from 'react-redux';
|
||||||
import darkTheme from 'themes/dark';
|
import darkTheme from 'themes/dark';
|
||||||
import lightTheme from 'themes/light';
|
import lightTheme from 'themes/light';
|
||||||
import { findItemInCollection } from 'utils/collections';
|
import { findItemInCollection } from 'utils/collections';
|
||||||
import ConfirmRequestClose from './ConfirmRequestClose';
|
|
||||||
import RequestTabNotFound from './RequestTabNotFound';
|
import RequestTabNotFound from './RequestTabNotFound';
|
||||||
import SpecialTab from './SpecialTab';
|
import SpecialTab from './SpecialTab';
|
||||||
import StyledWrapper from './StyledWrapper';
|
import StyledWrapper from './StyledWrapper';
|
||||||
@ -194,38 +192,23 @@ function SaveModal ({ tabsUidsToClose, collection, onCloseModal }) {
|
|||||||
onCloseModal();
|
onCloseModal();
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleSaveAndClose = async itemsToSave => {
|
const handleSaveAndClose = async () => {
|
||||||
await dispatch(saveMultipleRequests(itemsToSave.map(item => ({ ...item, collectionUid: collection.uid }))));
|
|
||||||
handleCloseTabs();
|
handleCloseTabs();
|
||||||
onCloseModal();
|
onCloseModal();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!tabsUidsToClose.some(tabUid => tabUids.includes(tabUid))) return null;
|
if (!tabsUidsToClose.some(tabUid => tabUids.includes(tabUid))) return null;
|
||||||
|
|
||||||
const tabsAndItemsToShowSaveModal = tabsUidsToClose.reduce((acc, tabUid) => {
|
const itemsPendingSave = tabsUidsToClose.reduce((acc, tabUid) => {
|
||||||
const item = findItemInCollection(collection, tabUid);
|
const item = findItemInCollection(collection, tabUid);
|
||||||
if (item && item.draft) acc[tabUid] = item;
|
if (item && item.draft) acc.push({ ...item, collectionUid: collection.uid });
|
||||||
return acc;
|
return acc;
|
||||||
}, {});
|
}, []);
|
||||||
|
|
||||||
const pendingSaveCount = Object.keys(tabsAndItemsToShowSaveModal).length;
|
if (!itemsPendingSave.length) return null;
|
||||||
if (pendingSaveCount === 0) return null;
|
|
||||||
|
|
||||||
if (pendingSaveCount === 1) {
|
|
||||||
const tabUid = Object.keys(tabsAndItemsToShowSaveModal)[0];
|
|
||||||
const item = tabsAndItemsToShowSaveModal[tabUid];
|
|
||||||
return (
|
|
||||||
<ConfirmRequestClose
|
|
||||||
item={item}
|
|
||||||
onCancel={onCloseModal}
|
|
||||||
onCloseWithoutSave={() => handleCloseWithoutSave([item])}
|
|
||||||
onSaveAndClose={() => handleSaveAndClose([item])}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SaveRequestsModal items={Object.values(tabsAndItemsToShowSaveModal)}
|
<SaveRequestsModal items={itemsPendingSave}
|
||||||
onCancel={onCloseModal}
|
onCancel={onCloseModal}
|
||||||
onCloseWithoutSave={handleCloseWithoutSave}
|
onCloseWithoutSave={handleCloseWithoutSave}
|
||||||
onSaveAndClose={handleSaveAndClose} />
|
onSaveAndClose={handleSaveAndClose} />
|
||||||
|
@ -1,11 +1,61 @@
|
|||||||
import React, { useEffect } from 'react';
|
import React, { useEffect } from 'react';
|
||||||
|
import { useDispatch } from 'react-redux';
|
||||||
import { pluralizeWord } from 'utils/common';
|
import { pluralizeWord } from 'utils/common';
|
||||||
import { IconAlertTriangle } from '@tabler/icons';
|
import { IconAlertTriangle } from '@tabler/icons';
|
||||||
import Modal from 'components/Modal';
|
import Modal from 'components/Modal';
|
||||||
|
import { saveMultipleRequests } from 'providers/ReduxStore/slices/collections/actions';
|
||||||
|
|
||||||
|
const SingleRequestMessage = ({ item }) => {
|
||||||
|
return (
|
||||||
|
<div className="font-normal mt-4">
|
||||||
|
You have unsaved changes in request <span className="font-semibold">{item.name}</span>.
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const MultipleRequestsMessage = ({ items, maxItems }) => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<p className="mt-4">
|
||||||
|
Do you want to save the changes you made to the following{' '}
|
||||||
|
<span className="font-medium">{items.length}</span> {pluralizeWord('request', items.length)}?
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<ul className="mt-4">
|
||||||
|
{items.slice(0, maxItems).map((item) => {
|
||||||
|
return (
|
||||||
|
<li key={item.uid} className="mt-1 text-xs">
|
||||||
|
{item.filename}
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
{items.length > maxItems && (
|
||||||
|
<p className="mt-1 text-xs">
|
||||||
|
...{items.length - maxItems} additional{' '}
|
||||||
|
{pluralizeWord('request', items.length - maxItems)} not shown
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
const SaveRequestsModal = ({ onSaveAndClose, onCloseWithoutSave, onCancel, items = [] }) => {
|
const SaveRequestsModal = ({ onSaveAndClose, onCloseWithoutSave, onCancel, items = [] }) => {
|
||||||
|
|
||||||
|
const dispatch = useDispatch();
|
||||||
const MAX_UNSAVED_REQUESTS_TO_SHOW = 5;
|
const MAX_UNSAVED_REQUESTS_TO_SHOW = 5;
|
||||||
|
|
||||||
|
const handleSaveAndClose = async () => {
|
||||||
|
await dispatch(saveMultipleRequests(items));
|
||||||
|
onSaveAndClose(items);
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleCloseWithoutSave = async () => {
|
||||||
|
onCloseWithoutSave(items);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (items.length === 0) {
|
if (items.length === 0) {
|
||||||
return onCloseWithoutSave([]);
|
return onCloseWithoutSave([]);
|
||||||
@ -32,31 +82,13 @@ const SaveRequestsModal = ({ onSaveAndClose, onCloseWithoutSave, onCancel, items
|
|||||||
<IconAlertTriangle size={32} strokeWidth={1.5} className="text-yellow-600" />
|
<IconAlertTriangle size={32} strokeWidth={1.5} className="text-yellow-600" />
|
||||||
<h1 className="ml-2 text-lg font-semibold">Hold on..</h1>
|
<h1 className="ml-2 text-lg font-semibold">Hold on..</h1>
|
||||||
</div>
|
</div>
|
||||||
<p className="mt-4">
|
{items.length > 1 ?
|
||||||
Do you want to save the changes you made to the following{' '}
|
<MultipleRequestsMessage items={items} maxItems={MAX_UNSAVED_REQUESTS_TO_SHOW} /> :
|
||||||
<span className="font-medium">{items.length}</span> {pluralizeWord('request', items.length)}?
|
<SingleRequestMessage item={items[0]} />
|
||||||
</p>
|
}
|
||||||
|
|
||||||
<ul className="mt-4">
|
|
||||||
{items.slice(0, MAX_UNSAVED_REQUESTS_TO_SHOW).map((item) => {
|
|
||||||
return (
|
|
||||||
<li key={item.uid} className="mt-1 text-xs">
|
|
||||||
{item.filename}
|
|
||||||
</li>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
{items.length > MAX_UNSAVED_REQUESTS_TO_SHOW && (
|
|
||||||
<p className="mt-1 text-xs">
|
|
||||||
...{items.length - MAX_UNSAVED_REQUESTS_TO_SHOW} additional{' '}
|
|
||||||
{pluralizeWord('request', items.length - MAX_UNSAVED_REQUESTS_TO_SHOW)} not shown
|
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<div className="flex justify-between mt-6">
|
<div className="flex justify-between mt-6">
|
||||||
<div>
|
<div>
|
||||||
<button className="btn btn-sm btn-danger" onClick={() => onCloseWithoutSave(items)}>
|
<button className="btn btn-sm btn-danger" onClick={handleCloseWithoutSave}>
|
||||||
Don't Save
|
Don't Save
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@ -64,7 +96,7 @@ const SaveRequestsModal = ({ onSaveAndClose, onCloseWithoutSave, onCancel, items
|
|||||||
<button className="btn btn-close btn-sm mr-2" onClick={onCancel}>
|
<button className="btn btn-close btn-sm mr-2" onClick={onCancel}>
|
||||||
Cancel
|
Cancel
|
||||||
</button>
|
</button>
|
||||||
<button className="btn btn-secondary btn-sm" onClick={() => onSaveAndClose(items)}>
|
<button className="btn btn-secondary btn-sm" onClick={handleSaveAndClose}>
|
||||||
{items.length > 1 ? 'Save All' : 'Save'}
|
{items.length > 1 ? 'Save All' : 'Save'}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
@ -5,9 +5,8 @@ import { findCollectionByUid, flattenItems, isItemARequest } from 'utils/collect
|
|||||||
import each from 'lodash/each';
|
import each from 'lodash/each';
|
||||||
import filter from 'lodash/filter';
|
import filter from 'lodash/filter';
|
||||||
import groupBy from 'lodash/groupBy';
|
import groupBy from 'lodash/groupBy';
|
||||||
import SaveRequestsModal from './SaveRequestsModal';
|
import SaveRequestsModal from 'components/SaveRequestsModal';
|
||||||
import { isElectron } from 'utils/common/platform';
|
import { isElectron } from 'utils/common/platform';
|
||||||
import { saveMultipleRequests } from 'providers/ReduxStore/slices/collections/actions';
|
|
||||||
import { completeQuitFlow } from 'providers/ReduxStore/slices/app';
|
import { completeQuitFlow } from 'providers/ReduxStore/slices/app';
|
||||||
|
|
||||||
const ConfirmAppClose = () => {
|
const ConfirmAppClose = () => {
|
||||||
@ -56,15 +55,10 @@ const ConfirmAppClose = () => {
|
|||||||
|
|
||||||
const quit = () => dispatch(completeQuitFlow());
|
const quit = () => dispatch(completeQuitFlow());
|
||||||
|
|
||||||
const handleSaveAndClose = async items => {
|
|
||||||
await dispatch(saveMultipleRequests(items));
|
|
||||||
quit();
|
|
||||||
}
|
|
||||||
|
|
||||||
return <SaveRequestsModal items={getAllDraftRequests()}
|
return <SaveRequestsModal items={getAllDraftRequests()}
|
||||||
onCancel={() => setShowConfirmClose(false)}
|
onCancel={() => setShowConfirmClose(false)}
|
||||||
onCloseWithoutSave={quit}
|
onCloseWithoutSave={quit}
|
||||||
onSaveAndClose={handleSaveAndClose} />;
|
onSaveAndClose={quit} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ConfirmAppClose;
|
export default ConfirmAppClose;
|
||||||
|
Loading…
Reference in New Issue
Block a user