-
Notifications
You must be signed in to change notification settings - Fork 15
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
TNO-2195: Split view for managing folders and new configure page #1449
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,6 +15,7 @@ $bk-main: #dedede; | |
$highlightPrimary: #e8e9f1; | ||
$highlightSecondary: #f8f7f8; | ||
$highlightTertiary: #d6d9e7; | ||
$highlight-active: #03bfdc; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. will also be used on side nav bar when updated (to highlight active menu item) |
||
|
||
// Shadows | ||
$drop-shadow: drop-shadow(0 2px 6px 1px rgba(0, 0, 0, 25%)); | ||
|
@@ -51,6 +52,9 @@ $btn-bk-primary: #6750a4; | |
$btn-primary-color: #fff; | ||
$btn-gray-color: #9f9196; | ||
$btn-red-color: #971d29; | ||
$btn-red-bk-color: #fef2f3; | ||
$btn-yellow-color: #876503; | ||
$btn-yellow-bk-color: #fff7e1; | ||
|
||
// Lines | ||
$line-primary-color: #807e9b; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,11 @@ | ||
import * as React from 'react'; | ||
import { FaArrowLeft } from 'react-icons/fa6'; | ||
import { FaGear } from 'react-icons/fa6'; | ||
import { useNavigate, useParams } from 'react-router-dom'; | ||
import { toast } from 'react-toastify'; | ||
import { useContent, useFilters, useFolders } from 'store/hooks'; | ||
import { | ||
Button, | ||
Col, | ||
Checkbox, | ||
FieldSize, | ||
getDistinct, | ||
IContentModel, | ||
|
@@ -14,25 +14,38 @@ import { | |
IFolderModel, | ||
IFolderScheduleModel, | ||
IOptionItem, | ||
Modal, | ||
Row, | ||
Select, | ||
Show, | ||
sortObject, | ||
useModal, | ||
} from 'tno-core'; | ||
|
||
import { getFilterOptions } from './constants'; | ||
import { Schedule } from './Schedule'; | ||
import * as styled from './styled'; | ||
import { createSchedule } from './utils'; | ||
|
||
export const ConfigureFolder: React.FC = () => { | ||
export interface IConfigureFolderProps { | ||
active?: IFolderModel; | ||
myFolders: IFolderModel[]; | ||
setMyFolders: React.Dispatch<React.SetStateAction<IFolderModel[]>>; | ||
} | ||
|
||
export const ConfigureFolder: React.FC<IConfigureFolderProps> = ({ | ||
active, | ||
myFolders, | ||
setMyFolders, | ||
}) => { | ||
const [{ myFilters }, { findMyFilters }] = useFilters(); | ||
const [, { findContentWithElasticsearch }] = useContent(); | ||
const [, { getFolder, updateFolder }] = useFolders(); | ||
const [, { getFolder, updateFolder, deleteFolder }] = useFolders(); | ||
const { id } = useParams(); | ||
const { toggle, isShowing } = useModal(); | ||
const navigate = useNavigate(); | ||
|
||
const [activeFilter, setActiveFilter] = React.useState<IFilterModel>(); | ||
const [actionName, setActionName] = React.useState<'delete' | 'empty'>(); | ||
const [currentFolder, setCurrentFolder] = React.useState<IFolderModel>(); | ||
const [filterOptions, setFilterOptions] = React.useState<IOptionItem[]>( | ||
getFilterOptions(myFilters, activeFilter?.id ?? 0), | ||
|
@@ -49,13 +62,28 @@ export const ConfigureFolder: React.FC = () => { | |
}, []); | ||
|
||
React.useEffect(() => { | ||
if (!currentFolder && id) { | ||
getFolder(Number(id)).then((data) => { | ||
setCurrentFolder(data); | ||
if (data.filter) setActiveFilter(data.filter); | ||
currentFolder && | ||
!currentFolder.events.length && | ||
setCurrentFolder({ | ||
...currentFolder, | ||
events: [createSchedule(currentFolder.name, currentFolder.description)], | ||
}); | ||
}, [currentFolder]); | ||
|
||
React.useEffect(() => { | ||
if ((!currentFolder && id) || currentFolder?.id !== Number(id)) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. when user changes selected item on left side, or when folder is not set There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If the folder doesn't exist, won't this infinite loop? |
||
getFolder(Number(id)) | ||
.then((data) => { | ||
setCurrentFolder(data); | ||
if (data.filter) setActiveFilter(data.filter); | ||
}) | ||
.catch(() => { | ||
toast.error('Failed to load folder.'); | ||
}); | ||
} | ||
}, [currentFolder, getFolder, id]); | ||
// Only do when id / currentFolder changes. | ||
// eslint-disable-next-line react-hooks/exhaustive-deps | ||
}, [currentFolder, id]); | ||
|
||
const handleRun = React.useCallback( | ||
async (filter: IFilterModel) => { | ||
|
@@ -108,16 +136,23 @@ export const ConfigureFolder: React.FC = () => { | |
ignoreLastChildGap | ||
header={ | ||
<Row width={FieldSize.Stretch}> | ||
<span className="back-to-folders" onClick={() => navigate(-1)}> | ||
<FaArrowLeft /> Back to folders | ||
</span> | ||
<span className="name">Configuring folder: "{currentFolder?.name}"</span> | ||
<FaGear className="gear" /> {currentFolder?.name} | ||
</Row> | ||
} | ||
> | ||
<div className="main-container"> | ||
<h2>Folder automation settings</h2> | ||
<Row> | ||
<FaGear className="small-gear" /> <h3>Content collection</h3> | ||
</Row> | ||
<div className="add-filter"> | ||
<div className="choose-text">Choose a filter to apply to this folder.</div> | ||
<p> | ||
A folder can be set up here to populate stories automatically based on one of your Saved | ||
Searches. Choose your Saved Search first and then setup your preferred scheduling | ||
options. | ||
</p> | ||
<Checkbox name="auto-pop" label="Auto-populate this folder" defaultChecked /> | ||
<label>Choose one of your Saved Searches to apply to this folder</label> | ||
<Row className="choose-filter"> | ||
<Select | ||
options={filterOptions} | ||
|
@@ -133,50 +168,86 @@ export const ConfigureFolder: React.FC = () => { | |
}} | ||
/> | ||
<Button className="run" onClick={() => !!activeFilter && handleRun(activeFilter)}> | ||
Run | ||
Apply | ||
</Button> | ||
</Row> | ||
</div> | ||
<Col className="add-schedule"> | ||
<Schedule | ||
folderSchedule={currentFolder?.events[0] ?? undefined} | ||
onScheduleChange={async (value: IFolderScheduleModel) => { | ||
setCurrentFolder({ | ||
...(currentFolder as IFolderModel), | ||
events: [value], | ||
}); | ||
}} | ||
/> | ||
<Row className="action-buttons"> | ||
<Button className="cancel" onClick={() => navigate(`/folders`)}> | ||
Cancel | ||
</Button> | ||
<Button | ||
onClick={() => { | ||
handleSaveSchedule(currentFolder as IFolderModel); | ||
}} | ||
className="save" | ||
> | ||
Save | ||
</Button> | ||
</Row> | ||
<div className="remove-container"> | ||
<Row> | ||
<span className="schedule-text"> | ||
Configure when you would like to have content removed automatically. | ||
</span> | ||
<Show visible={!currentFolder?.events?.length}> | ||
<Button | ||
className="add-schedule-btn" | ||
onClick={() => | ||
currentFolder && | ||
setCurrentFolder({ | ||
...currentFolder, | ||
events: [createSchedule(currentFolder.name, currentFolder.description)], | ||
}) | ||
} | ||
> | ||
Add Clearance Schedule | ||
</Button> | ||
</Show> | ||
<FaGear className="small-gear" /> | ||
<h3>Remove content</h3> | ||
</Row> | ||
<Schedule | ||
folderSchedule={currentFolder?.events[0] ?? undefined} | ||
onScheduleChange={async (value: IFolderScheduleModel) => { | ||
setCurrentFolder({ | ||
...(currentFolder as IFolderModel), | ||
events: [value], | ||
}); | ||
}} | ||
/> | ||
<Show visible={!!currentFolder?.events?.length}> | ||
<div className="remove-action-buttons"> | ||
<p>Proceed with caution as these actions may not be undone.</p> | ||
<Button | ||
className="warning" | ||
onClick={() => { | ||
handleSaveSchedule(currentFolder as IFolderModel); | ||
setActionName('empty'); | ||
toggle(); | ||
}} | ||
> | ||
Save | ||
Empty folder | ||
</Button> | ||
</Show> | ||
</Col> | ||
<Button | ||
className="danger" | ||
onClick={() => { | ||
setActionName('delete'); | ||
toggle(); | ||
}} | ||
> | ||
Delete folder | ||
</Button> | ||
</div> | ||
</div> | ||
</div> | ||
|
||
<Modal | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just moved Modal to different component, same code. |
||
headerText="Confirm Removal" | ||
body={`Are you sure you wish to ${actionName} this folder?`} | ||
isShowing={isShowing} | ||
hide={toggle} | ||
type="delete" | ||
confirmText="Yes, Remove It" | ||
onConfirm={() => { | ||
try { | ||
if (actionName === 'empty' && !!active) { | ||
updateFolder({ ...active, content: [] }).then((data) => { | ||
toast.success(`${active.name} updated successfully`); | ||
setMyFolders(myFolders.map((item) => (item.id === active.id ? data : item))); | ||
}); | ||
} else if (actionName === 'delete' && !!active) { | ||
deleteFolder(active).then(() => { | ||
toast.success(`${active.name} deleted successfully`); | ||
setMyFolders(myFolders.filter((folder) => folder.id !== active.id)); | ||
}); | ||
} | ||
} finally { | ||
toggle(); | ||
} | ||
}} | ||
/> | ||
</styled.ConfigureFolder> | ||
); | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks!