Files
twenty/packages/twenty-front/src/modules/page-layout/widgets/components/WidgetRenderer.tsx
T
Baptiste Devessier f2df456588 Refactor Widget components (#15996)
## Demo

All components look the same as before.


https://github.com/user-attachments/assets/ddaf49f7-0e78-4755-af88-19d43b349078

## Catalog of all states of WidgetRenderer

Went really complete on all the states of the component.


https://github.com/user-attachments/assets/303f773a-254d-4469-b904-f5cd9831a823
2025-11-24 11:51:32 +01:00

137 lines
5.0 KiB
TypeScript

import { usePageLayoutContentContext } from '@/page-layout/contexts/PageLayoutContentContext';
import { useCurrentPageLayoutOrThrow } from '@/page-layout/hooks/useCurrentPageLayoutOrThrow';
import { useDeletePageLayoutWidget } from '@/page-layout/hooks/useDeletePageLayoutWidget';
import { useEditPageLayoutWidget } from '@/page-layout/hooks/useEditPageLayoutWidget';
import { isPageLayoutInEditModeComponentState } from '@/page-layout/states/isPageLayoutInEditModeComponentState';
import { pageLayoutDraggingWidgetIdComponentState } from '@/page-layout/states/pageLayoutDraggingWidgetIdComponentState';
import { pageLayoutEditingWidgetIdComponentState } from '@/page-layout/states/pageLayoutEditingWidgetIdComponentState';
import { pageLayoutResizingWidgetIdComponentState } from '@/page-layout/states/pageLayoutResizingWidgetIdComponentState';
import { PageLayoutWidgetForbiddenDisplay } from '@/page-layout/widgets/components/PageLayoutWidgetForbiddenDisplay';
import { WidgetContentRenderer } from '@/page-layout/widgets/components/WidgetContentRenderer';
import { useIsInPinnedTab } from '@/page-layout/widgets/hooks/useIsInPinnedTab';
import { useWidgetPermissions } from '@/page-layout/widgets/hooks/useWidgetPermissions';
import { widgetCardHoveredComponentFamilyState } from '@/page-layout/widgets/states/widgetCardHoveredComponentFamilyState';
import { getWidgetCardVariant } from '@/page-layout/widgets/utils/getWidgetCardVariant';
import { WidgetCard } from '@/page-layout/widgets/widget-card/components/WidgetCard';
import { WidgetCardContent } from '@/page-layout/widgets/widget-card/components/WidgetCardContent';
import { WidgetCardHeader } from '@/page-layout/widgets/widget-card/components/WidgetCardHeader';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { useSetRecoilComponentFamilyState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentFamilyState';
import { useTheme } from '@emotion/react';
import { type MouseEvent } from 'react';
import { IconLock } from 'twenty-ui/display';
import { type PageLayoutWidget } from '~/generated/graphql';
type WidgetRendererProps = {
widget: PageLayoutWidget;
};
export const WidgetRenderer = ({ widget }: WidgetRendererProps) => {
const theme = useTheme();
const { deletePageLayoutWidget } = useDeletePageLayoutWidget();
const { handleEditWidget } = useEditPageLayoutWidget();
const isPageLayoutInEditMode = useRecoilComponentValue(
isPageLayoutInEditModeComponentState,
);
const draggingWidgetId = useRecoilComponentValue(
pageLayoutDraggingWidgetIdComponentState,
);
const resizingWidgetId = useRecoilComponentValue(
pageLayoutResizingWidgetIdComponentState,
);
const currentlyEditingWidgetId = useRecoilComponentValue(
pageLayoutEditingWidgetIdComponentState,
);
const isEditing = currentlyEditingWidgetId === widget.id;
const isDragging = draggingWidgetId === widget.id;
const isResizing = resizingWidgetId === widget.id;
const { hasAccess, restriction } = useWidgetPermissions(widget);
const { layoutMode } = usePageLayoutContentContext();
const { isInPinnedTab } = useIsInPinnedTab();
const { currentPageLayout } = useCurrentPageLayoutOrThrow();
const showHeader = layoutMode !== 'canvas' && !isInPinnedTab;
const handleClick = () => {
handleEditWidget({
widgetId: widget.id,
widgetType: widget.type,
});
};
const handleRemove = (e?: MouseEvent) => {
e?.stopPropagation();
deletePageLayoutWidget(widget.id);
};
const setIsHovered = useSetRecoilComponentFamilyState(
widgetCardHoveredComponentFamilyState,
widget.id,
);
const handleMouseEnter = () => {
setIsHovered(true);
};
const handleMouseLeave = () => {
setIsHovered(false);
};
const variant = getWidgetCardVariant({
layoutMode,
isInPinnedTab,
pageLayoutType: currentPageLayout.type,
});
return (
<WidgetCard
variant={variant}
isEditable={isPageLayoutInEditMode}
onClick={isPageLayoutInEditMode ? handleClick : undefined}
isEditing={isEditing}
isDragging={isDragging}
isResizing={isResizing}
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
>
{showHeader && (
<WidgetCardHeader
widgetId={widget.id}
isInEditMode={isPageLayoutInEditMode}
isResizing={isResizing}
title={widget.title}
onRemove={handleRemove}
forbiddenDisplay={
!hasAccess && (
<PageLayoutWidgetForbiddenDisplay
widgetId={widget.id}
restriction={restriction}
/>
)
}
/>
)}
<WidgetCardContent variant={variant}>
{hasAccess && <WidgetContentRenderer widget={widget} />}
{!hasAccess && (
<IconLock
color={theme.font.color.tertiary}
stroke={theme.icon.stroke.sm}
/>
)}
</WidgetCardContent>
</WidgetCard>
);
};