4410-feat(front): Implement Confirmation Prompt for Multiple Record Deletion (#4514)

* feat: implement confirmation prompt

* feat: remove prop drilling and introduce recoil state

* chore: fix eslint issues

* feat: set record text according to length of records

* chore: fix eslint issues

* refactor: made changes according to code review

* fix: show delete according to singular and plural records.

* fix: eslint issues

* feat: show number of selected records

* style: fix positioning of actionbar

* feat: display ConfirmationModal seperately

* chore: remove recoil state and use usestate instead

* chore: minor change

---------

Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
This commit is contained in:
Anchit Sinha 2024-03-29 22:48:21 +05:30 committed by GitHub
parent aaf429a907
commit 7f3623239a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 64 additions and 17 deletions

View File

@ -1,4 +1,4 @@
import { useCallback, useMemo } from 'react';
import { useCallback, useMemo, useState } from 'react';
import { isNonEmptyString } from '@sniptt/guards';
import { useRecoilCallback, useSetRecoilState } from 'recoil';
@ -17,6 +17,7 @@ import {
IconPuzzle,
IconTrash,
} from '@/ui/display/icon';
import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal';
import { actionBarEntriesState } from '@/ui/navigation/action-bar/states/actionBarEntriesState';
import { contextMenuEntriesState } from '@/ui/navigation/context-menu/states/contextMenuEntriesState';
import { ContextMenuEntry } from '@/ui/navigation/context-menu/types/ContextMenuEntry';
@ -36,6 +37,8 @@ export const useRecordActionBar = ({
}: useRecordActionBarProps) => {
const setContextMenuEntries = useSetRecoilState(contextMenuEntriesState);
const setActionBarEntriesState = useSetRecoilState(actionBarEntriesState);
const [isDeleteRecordsModalOpen, setIsDeleteRecordsModalOpen] =
useState(false);
const { createFavorite, favorites, deleteFavorite } = useFavorites();
@ -106,10 +109,26 @@ export const useRecordActionBar = ({
const baseActions: ContextMenuEntry[] = useMemo(
() => [
{
label: `Delete (${selectedRecordIds.length})`,
label: 'Delete',
Icon: IconTrash,
accent: 'danger',
onClick: () => handleDeleteClick(),
onClick: () => setIsDeleteRecordsModalOpen(true),
ConfirmationModal: (
<ConfirmationModal
isOpen={isDeleteRecordsModalOpen}
setIsOpen={setIsDeleteRecordsModalOpen}
title={`Delete ${selectedRecordIds.length} ${
selectedRecordIds.length === 1 ? `record` : 'records'
}`}
subtitle={`This action cannot be undone. This will permanently delete ${
selectedRecordIds.length === 1 ? 'this record' : 'these records'
}`}
onConfirmClick={() => handleDeleteClick()}
deleteButtonText={`Delete ${
selectedRecordIds.length > 1 ? 'Records' : 'Record'
}`}
/>
),
},
{
label: `${progress === undefined ? `Export` : `Export (${progress}%)`}`,
@ -118,7 +137,14 @@ export const useRecordActionBar = ({
onClick: () => download(),
},
],
[handleDeleteClick, download, progress, selectedRecordIds],
[
handleDeleteClick,
download,
progress,
selectedRecordIds,
isDeleteRecordsModalOpen,
setIsDeleteRecordsModalOpen,
],
);
const dataExecuteQuickActionOnmentEnabled = useIsFeatureEnabled(

View File

@ -18,5 +18,5 @@ export const RecordBoardActionBar = ({
return null;
}
return <ActionBar />;
return <ActionBar selectedIds={selectedRecordIds} />;
};

View File

@ -16,5 +16,5 @@ export const RecordTableActionBar = ({
return null;
}
return <ActionBar />;
return <ActionBar selectedIds={selectedRowIds} />;
};

View File

@ -1,4 +1,4 @@
import React, { useRef } from 'react';
import { useRef } from 'react';
import styled from '@emotion/styled';
import { useRecoilValue } from 'recoil';
@ -7,6 +7,10 @@ import { contextMenuIsOpenState } from '@/ui/navigation/context-menu/states/cont
import { ActionBarItem } from './ActionBarItem';
type ActionBarProps = {
selectedIds?: string[];
};
const StyledContainerActionBar = styled.div`
align-items: center;
background: ${({ theme }) => theme.background.secondary};
@ -27,7 +31,15 @@ const StyledContainerActionBar = styled.div`
z-index: 1;
`;
export const ActionBar = () => {
const StyledLabel = styled.div`
color: ${({ theme }) => theme.font.color.tertiary};
font-size: ${({ theme }) => theme.font.size.md};
font-weight: ${({ theme }) => theme.font.weight.medium};
padding-left: ${({ theme }) => theme.spacing(2)};
padding-right: ${({ theme }) => theme.spacing(2)};
`;
export const ActionBar = ({ selectedIds }: ActionBarProps) => {
const contextMenuIsOpen = useRecoilValue(contextMenuIsOpenState);
const actionBarEntries = useRecoilValue(actionBarEntriesState);
const wrapperRef = useRef<HTMLDivElement>(null);
@ -37,14 +49,22 @@ export const ActionBar = () => {
}
return (
<StyledContainerActionBar
data-select-disable
className="action-bar"
ref={wrapperRef}
>
{actionBarEntries.map((item, index) => (
<ActionBarItem key={index} item={item} />
))}
</StyledContainerActionBar>
<>
<StyledContainerActionBar
data-select-disable
className="action-bar"
ref={wrapperRef}
>
{selectedIds && (
<StyledLabel>{selectedIds.length} selected:</StyledLabel>
)}
{actionBarEntries.map((item, index) => (
<ActionBarItem key={index} item={item} />
))}
</StyledContainerActionBar>
<div data-select-disable className="action-bar">
{actionBarEntries[0]?.ConfirmationModal}
</div>
</>
);
};

View File

@ -7,4 +7,5 @@ export type ActionBarEntry = {
accent?: MenuItemAccent;
onClick?: () => void;
subActions?: ActionBarEntry[];
ConfirmationModal?: JSX.Element;
};