Skip to content

Commit

Permalink
delete unique cost surface
Browse files Browse the repository at this point in the history
  • Loading branch information
anamontiaga committed Aug 31, 2023
1 parent 98fdd9e commit bb287a8
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 107 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import { useCallback, useState } from 'react';

import Icon from 'components/icon';
import Modal from 'components/modal/component';
import DeleteModal from 'layout/project/sidebar/project/inventory-panel/cost-surfaces/modals/delete';
import EditModal from 'layout/project/sidebar/project/inventory-panel/cost-surfaces/modals/edit';
import { cn } from 'utils/cn';

import DELETE_SVG from 'svgs/ui/new-layout/delete.svg?sprite';
import TAG_SVG from 'svgs/ui/tag.svg?sprite';

const BUTTON_CLASSES =
'flex items-center px-4 py-2 w-full text-sm cursor-pointer bg-gray-700 hover:bg-gray-500 transition transition-colors space-x-2 group';

const ICON_CLASSES = 'h-5 w-5 text-gray-400 group-hover:text-white';

const ActionsMenu = ({
item,
}: {
item: {
id: string;
name: string;
scenarios: number;
tag: string;
custom: boolean;
};
}): JSX.Element => {
const isDeletable = !item.custom && !item.scenarios;

// item.isCustom && !item.scenarioUsageCount
const [modalState, setModalState] = useState<{ edit: boolean; delete: boolean }>({
edit: false,
delete: false,
});

const handleModal = useCallback((modalKey: keyof typeof modalState, isVisible: boolean) => {
setModalState((prevState) => ({ ...prevState, [modalKey]: isVisible }));
}, []);

return (
<ul className="rounded-2xl border-gray-500">
<li>
<button
type="button"
onClick={() => handleModal('edit', true)}
className={cn({
[BUTTON_CLASSES]: true,
'rounded-t-2xl': true,
'last:rounded-b-2xl': !isDeletable,
})}
>
<Icon icon={TAG_SVG} className={ICON_CLASSES} />
<span>Edit</span>
</button>
<Modal
id="edit-feature-modal"
title="All features"
open={modalState.edit}
size="narrow"
onDismiss={() => handleModal('edit', false)}
>
<EditModal featureId={item.id} handleModal={handleModal} />
</Modal>
</li>
{isDeletable && (
<li>
<button
type="button"
onClick={() => {
handleModal('delete', true);
}}
className={cn({
[BUTTON_CLASSES]: true,
'rounded-b-2xl': true,
})}
>
<Icon icon={DELETE_SVG} className={ICON_CLASSES} />
<span>Delete</span>
</button>
<Modal
id="delete-feature-modal"
dismissable
open={modalState.delete}
size="narrow"
onDismiss={() => {
handleModal('delete', false);
}}
>
<DeleteModal selectedCostSurfacesIds={[item.id]} />
</Modal>
</li>
)}
</ul>
);
};

export default ActionsMenu;
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import { setSelectedCostSurfaces as setVisibleCostSurfaces } from 'store/slices/

import { useProjectCostSurfaces } from 'hooks/cost-surface';

import ActionsMenu from 'layout/project/sidebar/project/inventory-panel/cost-surfaces/actions-menu';
import CostSurfacesBulkActionMenu from 'layout/project/sidebar/project/inventory-panel/cost-surfaces/bulk-action-menu';
import ActionsMenu from 'layout/project/sidebar/project/inventory-panel/features/actions-menu';
import { CostSurface } from 'types/api/cost-surface';

import InventoryTable, { type DataItem } from '../components/inventory-table';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,15 @@ const DeleteModal = ({
}, [allProjectCostSurfacesQuery.data, selectedCostSurfacesIds]);

const costSurfaceNames = selectedCostSurfaces.map(({ name }) => name);
// ? the user will be able to delete the features only if they are not being used by any scenario.
// ? the user will be able to delete the cost surfaces only if they are not being used by any scenario.
const haveScenarioAssociated = selectedCostSurfaces.some(({ scenarioUsageCount }) =>
Boolean(scenarioUsageCount)
);

const handleBulkDelete = useCallback(() => {
const deletableFeatureIds = selectedCostSurfaces.map(({ id }) => id);
const deletableCostSurfaceIds = selectedCostSurfaces.map(({ id }) => id);

bulkDeleteCostSurfaceFromProject(pid, deletableFeatureIds, session)
bulkDeleteCostSurfaceFromProject(pid, deletableCostSurfaceIds, session)
.then(async () => {
await queryClient.invalidateQueries(['cost-surfaces', pid]);

Expand All @@ -57,7 +57,7 @@ const DeleteModal = ({
'delete-bulk-project-cost-surfaces',
<>
<h2 className="font-medium">Success</h2>
<p className="text-sm">The features were deleted successfully.</p>
<p className="text-sm">The cost surfaces were deleted successfully.</p>
</>,
{
level: 'success',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,29 +45,12 @@ const EditModal = ({
const { pid } = query as { pid: string };

const formRef = useRef<FormProps<FormValues>['form']>(null);
const tagsSectionRef = useRef<ElementRef<'div'>>(null);

const [tagsMenuOpen, setTagsMenuOpen] = useState(false);
const [tagIsDone, setTagIsDone] = useState(false);

const tagsQuery = useProjectTags(pid);
const featureQuery = useProjectFeatures(pid, featureId);
const editFeatureTagMutation = useEditFeatureTag();
const deleteFeatureTagMutation = useDeleteFeatureTag();
const editFeatureMutation = useEditFeature();

useEffect(() => {
const handleClickOutside = (event) => {
if (tagsSectionRef.current && !tagsSectionRef.current.contains(event.target)) {
setTagsMenuOpen(false);
}
};
document.addEventListener('click', handleClickOutside, true);
return () => {
document.removeEventListener('click', handleClickOutside, true);
};
}, []);

const onEditSubmit = useCallback(
(values: FormValues) => {
const { featureClassName, tag } = values;
Expand Down Expand Up @@ -136,32 +119,20 @@ const EditModal = ({
]
);

const handleKeyPress = useCallback(
(event: Parameters<InputHTMLAttributes<HTMLInputElement>['onKeyDown']>[0]) => {
if (event.key === 'Enter') {
setTagIsDone(true);
formRef.current.change('tag', event.currentTarget.value);
setTagsMenuOpen(false);
}
},
[formRef]
);

return (
<FormRFF<FormValues>
initialValues={{
featureClassName: featureQuery.data?.[0]?.featureClassName,
tag: featureQuery.data?.[0]?.tag,
}}
ref={formRef}
onSubmit={onEditSubmit}
render={({ form, handleSubmit, values }) => {
render={({ form, handleSubmit }) => {
formRef.current = form;

return (
<form onSubmit={handleSubmit} className="relative">
<div className="flex flex-col space-y-5 px-8 py-1">
<h2 className="font-heading font-bold text-black">Edit feature</h2>
<h2 className="font-heading font-bold text-black">Edit cost surface</h2>

<div>
<FieldRFF<string>
Expand All @@ -185,77 +156,6 @@ const EditModal = ({
</FieldRFF>
</div>

<div ref={tagsSectionRef}>
<FieldRFF<string> name="tag">
{(fprops) => (
<Field id="tag" {...fprops} className="relative">
<Label
theme="light"
className="mb-3 font-heading text-xs font-semibold uppercase"
>
Add type
</Label>
{(!values.tag || !tagIsDone) && (
<div className="space-y-2">
<input
{...fprops.input}
className="h-10 w-full rounded-md border border-gray-300 px-3 text-gray-800 focus:border-none focus:outline-none focus:ring-1 focus:ring-blue-500"
placeholder="Type to pick or create tag..."
value={fprops.input.value}
onFocus={() => {
setTagsMenuOpen(true);
form.change('tag', '');
}}
onBlur={() => setTagIsDone(true)}
onKeyDown={handleKeyPress}
/>

{tagsMenuOpen && (
<div className="w-full space-y-2.5 rounded-md bg-white p-4 font-sans text-gray-800 shadow-md">
<div className="text-sm text-gray-800">Recent:</div>
<div className="flex flex-wrap gap-2.5">
{tagsQuery.data?.map((tag) => (
<button
key={tag}
className="inline-block rounded-2xl border border-yellow-600 bg-yellow-400/50 px-3 py-0.5"
onClick={() => {
form.change('tag', tag);
setTagIsDone(true);
}}
>
<p className="text-sm text-gray-800">{tag}</p>
</button>
))}
</div>
</div>
)}
</div>
)}

{values.tag && tagIsDone && (
<div className="flex items-center space-x-1">
<div className="inline-block items-center space-x-2 rounded-2xl border border-yellow-600 bg-yellow-400/50 px-3 py-0.5 hover:bg-yellow-600">
<p className="text-sm text-gray-800">{values.tag}</p>
</div>
<button
className="group flex h-6 w-6 cursor-pointer items-center justify-center rounded-full border border-gray-300 hover:bg-gray-500"
onClick={() => {
form.change('tag', null);
setTagIsDone(false);
}}
>
<Icon
icon={CLOSE_SVG}
className="h-2 w-2 text-gray-400 group-hover:text-white"
/>
</button>
</div>
)}
</Field>
)}
</FieldRFF>
</div>

<div className="mt-16 flex justify-center space-x-6">
<Button theme="secondary" size="xl" onClick={() => handleModal('edit', false)}>
Cancel
Expand Down

0 comments on commit bb287a8

Please sign in to comment.