Add client side removing of items, Add item position modal

This commit is contained in:
Meier Lukas
2023-10-02 20:29:26 +02:00
parent 9c614d8823
commit 076bd94970
9 changed files with 142 additions and 135 deletions

View File

@@ -0,0 +1,24 @@
import { useGridItemRef } from '../item/context';
import { useGridstackRef } from './context';
type ResizeGridItemProps = {
height: number;
width: number;
x: number;
y: number;
};
export const useResizeGridItem = () => {
const itemRef = useGridItemRef();
const gridstackRef = useGridstackRef();
return ({ height, width, ...options }: ResizeGridItemProps) => {
gridstackRef.current?.batchUpdate();
gridstackRef.current?.update(itemRef.current!, {
...options,
h: height,
w: width,
});
gridstackRef.current?.batchUpdate(false);
};
};

View File

@@ -1,4 +1,7 @@
import { Text, Title } from '@mantine/core';
import { openConfirmModal } from '@mantine/modals';
import { useCallback } from 'react';
import { Trans } from 'react-i18next';
import { api } from '~/utils/api';
type MoveAndResizeItem = {
@@ -16,6 +19,9 @@ type MoveItemToSection = {
width: number;
height: number;
};
type RemoveItem = {
itemId: string;
};
export const useItemActions = ({ boardName }: { boardName: string }) => {
const utils = api.useContext();
@@ -33,7 +39,6 @@ export const useItemActions = ({ boardName }: { boardName: string }) => {
items: section.items.map((item) => {
// Return same item if item is not the one we're moving
if (item.id !== itemId) return item;
console.log(positionProps);
return {
...item,
...positionProps,
@@ -87,12 +92,60 @@ export const useItemActions = ({ boardName }: { boardName: string }) => {
[boardName, utils]
);
const removeItem = useCallback(
({ itemId }: RemoveItem) => {
utils.boards.byName.setData({ boardName }, (prev) => {
if (!prev) return prev;
return {
...prev,
// Filter removed item out of items array
sections: prev.sections.map((section) => ({
...section,
items: section.items.filter((item) => item.id !== itemId),
})),
};
});
},
[boardName, utils]
);
return {
moveAndResizeItem,
moveItemToSection,
removeItem,
};
};
type OpenRemoveItemModalProps = {
name: string;
onConfirm: () => void;
};
export const openRemoveItemModal = ({ name, onConfirm }: OpenRemoveItemModalProps) => {
openConfirmModal({
title: (
<Title order={4}>
<Trans i18nKey="common:remove" />
</Title>
),
children: (
<Trans
i18nKey="common:removeConfirm"
components={[<Text weight={500} />]}
values={{ item: name }}
/>
),
labels: {
cancel: <Trans i18nKey="common:cancel" />,
confirm: <Trans i18nKey="common:ok" />,
},
cancelProps: {
variant: 'light',
},
onConfirm,
});
};
/*
- Add category (on top, below, above)
- Rename category

View File

@@ -1,14 +1,16 @@
import { SelectItem } from '@mantine/core';
import { ContextModalProps, closeModal } from '@mantine/modals';
import { type SelectItem } from '@mantine/core';
import { type ContextModalProps, closeModal } from '@mantine/modals';
import { type AppItem } from '~/components/Board/context';
import { type useResizeGridItem } from '~/components/Board/gridstack/useResizeGridItem';
import { useItemActions } from '~/components/Board/item-actions';
import { useConfigContext } from '~/config/provider';
import { useConfigStore } from '~/config/store';
import { AppType } from '~/types/app';
import { useGridstackStore, useWrapperColumnCount } from '../../Wrappers/gridstack/store';
import { ChangePositionModal } from './ChangePositionModal';
type ChangeAppPositionModalInnerProps = {
app: AppType;
app: AppItem;
boardName: string;
resizeGridItem: ReturnType<typeof useResizeGridItem>;
};
export const ChangeAppPositionModal = ({
@@ -16,34 +18,17 @@ export const ChangeAppPositionModal = ({
context,
innerProps,
}: ContextModalProps<ChangeAppPositionModalInnerProps>) => {
const { name: configName } = useConfigContext();
const updateConfig = useConfigStore((x) => x.updateConfig);
const shapeSize = useGridstackStore((x) => x.currentShapeSize);
if (!shapeSize) return null;
const { moveAndResizeItem } = useItemActions({ boardName: innerProps.boardName });
const handleSubmit = (x: number, y: number, width: number, height: number) => {
if (!configName) {
return;
}
updateConfig(
configName,
(previousConfig) => ({
...previousConfig,
apps: [
...previousConfig.apps.filter((x) => x.id !== innerProps.app.id),
{
...innerProps.app,
shape: {
...innerProps.app.shape,
[shapeSize]: { location: { x, y }, size: { width, height } },
},
},
],
}),
true
);
moveAndResizeItem({
itemId: innerProps.app.id,
x,
y,
width,
height,
});
innerProps.resizeGridItem({ x, y, width, height });
context.closeModal(id);
};
@@ -60,10 +45,10 @@ export const ChangeAppPositionModal = ({
onCancel={handleCancel}
widthData={widthData}
heightData={heightData}
initialX={innerProps.app.shape[shapeSize]?.location.x}
initialY={innerProps.app.shape[shapeSize]?.location.y}
initialWidth={innerProps.app.shape[shapeSize]?.size.width}
initialHeight={innerProps.app.shape[shapeSize]?.size.height}
initialX={innerProps.app.x}
initialY={innerProps.app.y}
initialWidth={innerProps.app.width}
initialHeight={innerProps.app.height}
/>
);
};

View File

@@ -1,7 +1,6 @@
import { Button, Flex, Grid, NumberInput, Select, SelectItem } from '@mantine/core';
import { useForm } from '@mantine/form';
import { useTranslation } from 'next-i18next';
import { useConfigContext } from '~/config/provider';
interface ChangePositionModalProps {
initialX?: number;

View File

@@ -1,12 +1,20 @@
import { SelectItem } from '@mantine/core';
import { ContextModalProps, closeModal } from '@mantine/modals';
import { type SelectItem } from '@mantine/core';
import { type ContextModalProps, closeModal } from '@mantine/modals';
import { type WidgetItem } from '~/components/Board/context';
import { type useResizeGridItem } from '~/components/Board/gridstack/useResizeGridItem';
import { useItemActions } from '~/components/Board/item-actions';
import widgets from '../../../../widgets';
import { WidgetChangePositionModalInnerProps } from '../../Tiles/Widgets/WidgetsMenu';
import { useGridstackStore, useWrapperColumnCount } from '../../Wrappers/gridstack/store';
import { ChangePositionModal } from './ChangePositionModal';
export type WidgetChangePositionModalInnerProps = {
widget: WidgetItem;
boardName: string;
wrapperColumnCount: number;
resizeGridItem: ReturnType<typeof useResizeGridItem>;
};
export const ChangeWidgetPositionModal = ({
context,
id,
@@ -22,7 +30,7 @@ export const ChangeWidgetPositionModal = ({
width,
height,
});
innerProps.resizeGridItem({ x: x, y: y, w: width, h: height });
innerProps.resizeGridItem({ x, y, width, height });
context.closeModal(id);
};

View File

@@ -1,8 +1,7 @@
import { AppItem } from '~/components/Board/context';
import { useConfigContext } from '~/config/provider';
import { useConfigStore } from '~/config/store';
import { type AppItem, useRequiredBoard } from '~/components/Board/context';
import { useResizeGridItem } from '~/components/Board/gridstack/useResizeGridItem';
import { openRemoveItemModal, useItemActions } from '~/components/Board/item-actions';
import { openContextModalGeneric } from '~/tools/mantineModalManagerExtensions';
import { AppType } from '~/types/app';
import { GenericTileMenu } from '../GenericTileMenu';
@@ -11,8 +10,9 @@ interface TileMenuProps {
}
export const AppMenu = ({ app }: TileMenuProps) => {
const { config, name: configName } = useConfigContext();
const { updateConfig } = useConfigStore();
const board = useRequiredBoard();
const { removeItem } = useItemActions({ boardName: board.name });
const resizeGridItem = useResizeGridItem();
const handleClickEdit = () => {
openContextModalGeneric<{ app: AppItem; allowAppNamePropagation: boolean }>({
@@ -35,6 +35,8 @@ export const AppMenu = ({ app }: TileMenuProps) => {
modal: 'changeAppPositionModal',
innerProps: {
app,
boardName: board.name,
resizeGridItem,
},
styles: {
root: {
@@ -45,14 +47,14 @@ export const AppMenu = ({ app }: TileMenuProps) => {
};
const handleClickDelete = () => {
if (configName === undefined) {
return;
}
updateConfig(configName, (previousConfig) => ({
...previousConfig,
apps: previousConfig.apps.filter((a) => a.id !== app.id),
}));
openRemoveItemModal({
name: app.name,
onConfirm() {
removeItem({
itemId: app.id,
});
},
});
};
return (

View File

@@ -1,22 +1,15 @@
import { Title } from '@mantine/core';
import { useTranslation } from 'next-i18next';
import { WidgetItem, useRequiredBoard } from '~/components/Board/context';
import { useGridstackRef } from '~/components/Board/gridstack/context';
import { useGridItemRef } from '~/components/Board/item/context';
import { type WidgetItem, useRequiredBoard } from '~/components/Board/context';
import { useResizeGridItem } from '~/components/Board/gridstack/useResizeGridItem';
import { openRemoveItemModal, useItemActions } from '~/components/Board/item-actions';
import { openContextModalGeneric } from '~/tools/mantineModalManagerExtensions';
import WidgetsDefinitions from '../../../../widgets';
import { type WidgetChangePositionModalInnerProps } from '../../Modals/ChangePosition/ChangeWidgetPositionModal';
import { useWrapperColumnCount } from '../../Wrappers/gridstack/store';
import { GenericTileMenu } from '../GenericTileMenu';
import { WidgetEditModalInnerProps } from './WidgetsEditModal';
import { WidgetsRemoveModalInnerProps } from './WidgetsRemoveModal';
export type WidgetChangePositionModalInnerProps = {
widget: WidgetItem;
boardName: string;
wrapperColumnCount: number;
resizeGridItem: (options: { h: number; w: number; x: number; y: number }) => void;
};
import { type WidgetEditModalInnerProps } from './WidgetsEditModal';
interface WidgetsMenuProps {
type: string;
@@ -27,33 +20,27 @@ export const WidgetsMenu = ({ type, widget }: WidgetsMenuProps) => {
const { t } = useTranslation(`modules/${type}`);
const board = useRequiredBoard();
const wrapperColumnCount = useWrapperColumnCount();
const itemRef = useGridItemRef();
const gridstackRef = useGridstackRef();
const resizeGridItem = (options: { h: number; w: number; x: number; y: number }) => {
gridstackRef.current?.batchUpdate();
gridstackRef.current?.update(itemRef.current!, options);
gridstackRef.current?.batchUpdate(false);
};
const resizeGridItem = useResizeGridItem();
const { removeItem } = useItemActions({ boardName: board.name });
if (!widget || !wrapperColumnCount) return null;
// Then get the widget definition
const widgetDefinitionObject = WidgetsDefinitions[widget.sort as keyof typeof WidgetsDefinitions];
const handleDeleteClick = () => {
openContextModalGeneric<WidgetsRemoveModalInnerProps>({
modal: 'integrationRemove',
title: <Title order={4}>{t('common:remove')}</Title>,
innerProps: {
widgetId: widget.id,
widgetType: type,
openRemoveItemModal({
name: widget.sort,
onConfirm() {
removeItem({
itemId: widget.id,
});
},
});
};
const handleChangeSizeClick = () => {
openContextModalGeneric<WidgetChangePositionModalInnerProps>({
modal: 'changeIntegrationPositionModal',
modal: 'changeWidgetPositionModal',
size: 'xl',
title: null,
innerProps: {

View File

@@ -1,49 +0,0 @@
import { Button, Group, Stack, Text } from '@mantine/core';
import { ContextModalProps } from '@mantine/modals';
import { Trans, useTranslation } from 'next-i18next';
import { useConfigContext } from '~/config/provider';
import { useConfigStore } from '~/config/store';
export type WidgetsRemoveModalInnerProps = {
widgetId: string;
widgetType: string;
};
export const WidgetsRemoveModal = ({
context,
id,
innerProps,
}: ContextModalProps<WidgetsRemoveModalInnerProps>) => {
const { t } = useTranslation([`modules/${innerProps.widgetType}`, 'common']);
const { name: configName } = useConfigContext();
if (!configName) return null;
const updateConfig = useConfigStore((x) => x.updateConfig);
const handleDeletion = () => {
updateConfig(
configName,
(prev) => ({
...prev,
widgets: prev.widgets.filter((w) => w.id !== innerProps.widgetId),
}),
true
);
context.closeModal(id);
};
return (
<Stack>
<Trans
i18nKey="common:removeConfirm"
components={[<Text weight={500} />]}
values={{ item: innerProps.widgetType }}
/>
<Group position="right">
<Button onClick={() => context.closeModal(id)} variant="light">
{t('common:cancel')}
</Button>
<Button onClick={() => handleDeletion()}>{t('common:ok')}</Button>
</Group>
</Stack>
);
};

View File

@@ -3,7 +3,6 @@ import { ChangeWidgetPositionModal } from '~/components/Dashboard/Modals/ChangeP
import { EditAppModal } from '~/components/Dashboard/Modals/EditAppModal/EditAppModal';
import { SelectElementModal } from '~/components/Dashboard/Modals/SelectElement/SelectElementModal';
import { WidgetsEditModal } from '~/components/Dashboard/Tiles/Widgets/WidgetsEditModal';
import { WidgetsRemoveModal } from '~/components/Dashboard/Tiles/Widgets/WidgetsRemoveModal';
import { CategoryEditModal } from '~/components/Dashboard/Wrappers/Category/CategoryEditModal';
import { CreateBoardModal } from './components/Manage/Board/create-board.modal';
@@ -19,10 +18,9 @@ export const modals = {
editApp: EditAppModal,
selectElement: SelectElementModal,
integrationOptions: WidgetsEditModal,
integrationRemove: WidgetsRemoveModal,
categoryEditModal: CategoryEditModal,
changeAppPositionModal: ChangeAppPositionModal,
changeIntegrationPositionModal: ChangeWidgetPositionModal,
changeWidgetPositionModal: ChangeWidgetPositionModal,
deleteUserModal: DeleteUserModal,
createInviteModal: CreateInviteModal,
deleteInviteModal: DeleteInviteModal,