diff --git a/met-api/migrations/versions/c2a384ddfe6a_add_widget_location.py b/met-api/migrations/versions/c2a384ddfe6a_add_widget_location.py new file mode 100644 index 000000000..4cc74eb39 --- /dev/null +++ b/met-api/migrations/versions/c2a384ddfe6a_add_widget_location.py @@ -0,0 +1,24 @@ +"""Add locations to widgets + +Revision ID: c2a384ddfe6a +Revises: 901a6724bca2 +Create Date: 2024-08-21 16:04:25.726651 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'c2a384ddfe6a' +down_revision = '901a6724bca2' +branch_labels = None +depends_on = None + + +def upgrade(): + op.add_column('widget', sa.Column('location', sa.Integer(), nullable=True)) + + +def downgrade(): + op.drop_column('widget', 'location') diff --git a/met-api/src/met_api/models/widget.py b/met-api/src/met_api/models/widget.py index 9c55a0e63..7acd7edab 100644 --- a/met-api/src/met_api/models/widget.py +++ b/met-api/src/met_api/models/widget.py @@ -29,6 +29,7 @@ class Widget(BaseModel): # pylint: disable=too-few-public-methods title = db.Column(db.String(100), comment='Custom title for the widget.') items = db.relationship('WidgetItem', backref='widget', cascade='all, delete', order_by='WidgetItem.sort_index') sort_index = db.Column(db.Integer, nullable=False, default=1) + location = db.Column(db.Integer, nullable=False) @classmethod def get_widget_by_id(cls, widget_id): @@ -67,6 +68,7 @@ def __create_new_widget_entity(widget): created_by=widget.get('created_by', None), updated_by=widget.get('updated_by', None), title=widget.get('title', None), + location=widget.get('location', None), ) @classmethod diff --git a/met-api/src/met_api/schemas/widget.py b/met-api/src/met_api/schemas/widget.py index c2aec64d7..4c736d784 100644 --- a/met-api/src/met_api/schemas/widget.py +++ b/met-api/src/met_api/schemas/widget.py @@ -23,3 +23,4 @@ class Meta: # pylint: disable=too-few-public-methods updated_date = fields.Str(data_key='updated_date') sort_index = fields.Int(data_key='sort_index') items = fields.List(fields.Nested(WidgetItemSchema)) + location = fields.Int(data_key='location') diff --git a/met-web/src/components/engagement/admin/create/widgets/WidgetPickerButton.tsx b/met-web/src/components/engagement/admin/create/widgets/WidgetPickerButton.tsx new file mode 100644 index 000000000..ca255f2a3 --- /dev/null +++ b/met-web/src/components/engagement/admin/create/widgets/WidgetPickerButton.tsx @@ -0,0 +1,82 @@ +import React, { useContext, useEffect } from 'react'; +import { WidgetDrawerContext } from 'components/engagement/form/EngagementWidgets/WidgetDrawerContext'; +import { Grid, Skeleton } from '@mui/material'; +import { If, Else, Then } from 'react-if'; +import { useAppDispatch } from 'hooks'; +import { colors } from 'styles/Theme'; +import { WidgetCardSwitch } from 'components/engagement/form/EngagementWidgets/WidgetCardSwitch'; +import { openNotificationModal } from 'services/notificationModalService/notificationModalSlice'; +import { WidgetLocation } from 'models/widget'; + +export const WidgetPickerButton = ({ location }: { location: WidgetLocation }) => { + const { widgets, deleteWidget, handleWidgetDrawerOpen, isWidgetsLoading, setWidgetLocation } = + useContext(WidgetDrawerContext); + const dispatch = useAppDispatch(); + + useEffect(() => { + setWidgetLocation(location); + return () => setWidgetLocation(0); + }, []); + + const removeWidget = (widgetId: number) => { + dispatch( + openNotificationModal({ + open: true, + data: { + header: 'Remove Widget', + subText: [ + { text: 'You will be removing this widget from the engagement.' }, + { text: 'Do you want to remove this widget?' }, + ], + handleConfirm: () => { + deleteWidget(widgetId); + }, + }, + type: 'confirm', + }), + ); + }; + + return ( + + + + + + + + + + {/* Only ever render the first selected widget. This may change in the future. */} + {widgets.length > 0 ? ( + + ) : ( + + )} + + + + + ); +}; diff --git a/met-web/src/components/engagement/admin/create/widgets/index.tsx b/met-web/src/components/engagement/admin/create/widgets/index.tsx new file mode 100644 index 000000000..b498882b5 --- /dev/null +++ b/met-web/src/components/engagement/admin/create/widgets/index.tsx @@ -0,0 +1,19 @@ +import React from 'react'; +import WidgetDrawer from 'components/engagement/form/EngagementWidgets/WidgetDrawer'; +import { WidgetDrawerProvider } from 'components/engagement/form/EngagementWidgets/WidgetDrawerContext'; +import { WidgetPickerButton } from './WidgetPickerButton'; +import { WidgetLocation } from 'models/widget'; +import { ActionProvider } from 'components/engagement/form/ActionContext'; + +export const WidgetPicker = ({ location }: { location: WidgetLocation }) => { + return ( + + + + + + + ); +}; + +export default WidgetPicker; diff --git a/met-web/src/components/engagement/admin/view/ConfigSummary.tsx b/met-web/src/components/engagement/admin/view/ConfigSummary.tsx index d24a50906..a7e2629fe 100644 --- a/met-web/src/components/engagement/admin/view/ConfigSummary.tsx +++ b/met-web/src/components/engagement/admin/view/ConfigSummary.tsx @@ -15,6 +15,8 @@ import { ENGAGEMENT_MEMBERSHIP_STATUS, EngagementTeamMember } from 'models/engag import { Button } from 'components/common/Input'; import { faPen } from '@fortawesome/pro-regular-svg-icons'; import { LiveAnnouncer, LiveMessage } from 'react-aria-live'; +import { WidgetPicker } from 'components/engagement/admin/create/widgets'; +import { WidgetLocation } from 'models/widget'; export const ConfigSummary = () => { const siteUrl = getBaseUrl(); @@ -178,6 +180,10 @@ export const ConfigSummary = () => { + + + +