diff --git a/src/components/Board/gridstack/useResizeGridItem.ts b/src/components/Board/gridstack/useResizeGridItem.ts new file mode 100644 index 000000000..3e5504337 --- /dev/null +++ b/src/components/Board/gridstack/useResizeGridItem.ts @@ -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); + }; +}; diff --git a/src/components/Board/item-actions.ts b/src/components/Board/item-actions.tsx similarity index 68% rename from src/components/Board/item-actions.ts rename to src/components/Board/item-actions.tsx index 5e854e631..512df7602 100644 --- a/src/components/Board/item-actions.ts +++ b/src/components/Board/item-actions.tsx @@ -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: ( + + <Trans i18nKey="common:remove" /> + + ), + children: ( + ]} + values={{ item: name }} + /> + ), + labels: { + cancel: , + confirm: , + }, + cancelProps: { + variant: 'light', + }, + onConfirm, + }); +}; + /* - Add category (on top, below, above) - Rename category diff --git a/src/components/Dashboard/Modals/ChangePosition/ChangeAppPositionModal.tsx b/src/components/Dashboard/Modals/ChangePosition/ChangeAppPositionModal.tsx index 52bec9c64..bb92b3618 100644 --- a/src/components/Dashboard/Modals/ChangePosition/ChangeAppPositionModal.tsx +++ b/src/components/Dashboard/Modals/ChangePosition/ChangeAppPositionModal.tsx @@ -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; }; export const ChangeAppPositionModal = ({ @@ -16,34 +18,17 @@ export const ChangeAppPositionModal = ({ context, innerProps, }: ContextModalProps) => { - 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} /> ); }; diff --git a/src/components/Dashboard/Modals/ChangePosition/ChangePositionModal.tsx b/src/components/Dashboard/Modals/ChangePosition/ChangePositionModal.tsx index 2db58b823..c559df621 100644 --- a/src/components/Dashboard/Modals/ChangePosition/ChangePositionModal.tsx +++ b/src/components/Dashboard/Modals/ChangePosition/ChangePositionModal.tsx @@ -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; diff --git a/src/components/Dashboard/Modals/ChangePosition/ChangeWidgetPositionModal.tsx b/src/components/Dashboard/Modals/ChangePosition/ChangeWidgetPositionModal.tsx index 334fbf1fc..315ec673e 100644 --- a/src/components/Dashboard/Modals/ChangePosition/ChangeWidgetPositionModal.tsx +++ b/src/components/Dashboard/Modals/ChangePosition/ChangeWidgetPositionModal.tsx @@ -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; +}; + 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); }; diff --git a/src/components/Dashboard/Tiles/Apps/AppMenu.tsx b/src/components/Dashboard/Tiles/Apps/AppMenu.tsx index 9764ea8cb..580ab9552 100644 --- a/src/components/Dashboard/Tiles/Apps/AppMenu.tsx +++ b/src/components/Dashboard/Tiles/Apps/AppMenu.tsx @@ -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 ( diff --git a/src/components/Dashboard/Tiles/Widgets/WidgetsMenu.tsx b/src/components/Dashboard/Tiles/Widgets/WidgetsMenu.tsx index ece5b1e7c..6dff83f89 100644 --- a/src/components/Dashboard/Tiles/Widgets/WidgetsMenu.tsx +++ b/src/components/Dashboard/Tiles/Widgets/WidgetsMenu.tsx @@ -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({ - modal: 'integrationRemove', - title: {t('common:remove')}, - innerProps: { - widgetId: widget.id, - widgetType: type, + openRemoveItemModal({ + name: widget.sort, + onConfirm() { + removeItem({ + itemId: widget.id, + }); }, }); }; const handleChangeSizeClick = () => { openContextModalGeneric({ - modal: 'changeIntegrationPositionModal', + modal: 'changeWidgetPositionModal', size: 'xl', title: null, innerProps: { diff --git a/src/components/Dashboard/Tiles/Widgets/WidgetsRemoveModal.tsx b/src/components/Dashboard/Tiles/Widgets/WidgetsRemoveModal.tsx deleted file mode 100644 index ea66fb511..000000000 --- a/src/components/Dashboard/Tiles/Widgets/WidgetsRemoveModal.tsx +++ /dev/null @@ -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) => { - 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 ( - - ]} - values={{ item: innerProps.widgetType }} - /> - - - - - - ); -}; diff --git a/src/modals.ts b/src/modals.ts index 4faea9bd3..c8f4d3233 100644 --- a/src/modals.ts +++ b/src/modals.ts @@ -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,