From 13a5eeac8025d990ffdb1ee64c76efa6396036d4 Mon Sep 17 00:00:00 2001 From: jadmsaadaot <91914654+jadmsaadaot@users.noreply.github.com> Date: Thu, 13 Jul 2023 15:22:35 -0700 Subject: [PATCH] Add video widget display component in public page (#1837) * Add video widget model and option card * add video widget service and resource * Add video widget crud and UI component * Fix linting issue * Add video widget display in engagement view * improve service methods return * Use some instead of map includes * remove console log --- met-api/src/met_api/constants/widget.py | 2 + met-web/package-lock.json | 60 +++++++++++++ met-web/package.json | 1 + .../Documents/DocumentOptionCard.tsx | 2 +- .../Events/EventsOptionCard.tsx | 2 +- .../EngagementWidgets/Map/MapOptionCard.tsx | 2 +- .../Phases/PhasesOptionCard.tsx | 2 +- .../Subscribe/SubscribeOptionCard.tsx | 2 +- .../Video/VideoOptionCard.tsx | 6 +- .../WhoIsListeningOptionCard.tsx | 2 +- .../view/widgets/Video/VideoWidgetView.tsx | 90 +++++++++++++++++++ .../engagement/view/widgets/WidgetSwitch.tsx | 4 + .../widgetService/VideoService/index.tsx | 10 +-- 13 files changed, 168 insertions(+), 17 deletions(-) create mode 100644 met-web/src/components/engagement/view/widgets/Video/VideoWidgetView.tsx diff --git a/met-api/src/met_api/constants/widget.py b/met-api/src/met_api/constants/widget.py index bfcc9fbc7..a5ae6da25 100644 --- a/met-api/src/met_api/constants/widget.py +++ b/met-api/src/met_api/constants/widget.py @@ -23,3 +23,5 @@ class WidgetType(IntEnum): PHASES = 3 SUBSCRIBE = 4 EVENTS = 5 + Map = 6 + Video = 7 diff --git a/met-web/package-lock.json b/met-web/package-lock.json index 8923e4b57..8c2676c05 100644 --- a/met-web/package-lock.json +++ b/met-web/package-lock.json @@ -60,6 +60,7 @@ "react-hook-form": "^7.37.0", "react-if": "^4.1.4", "react-map-gl": "^7.0.21", + "react-player": "^2.12.0", "react-redux": "^7.2.8", "react-router-dom": "^6.10.0", "react-scripts": "5.0.1", @@ -15996,6 +15997,11 @@ "uc.micro": "^1.0.1" } }, + "node_modules/load-script": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/load-script/-/load-script-1.0.0.tgz", + "integrity": "sha512-kPEjMFtZvwL9TaZo0uZ2ml+Ye9HUMmPwbYRJ324qF9tqMejwykJ5ggTyvzmrbBeapCAbk98BSbTeovHEEP1uCA==" + }, "node_modules/loader-runner": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", @@ -19470,6 +19476,11 @@ "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz", "integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==" }, + "node_modules/react-fast-compare": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz", + "integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==" + }, "node_modules/react-hook-form": { "version": "7.37.0", "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.37.0.tgz", @@ -19518,6 +19529,26 @@ "react": ">=16.3.0" } }, + "node_modules/react-player": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/react-player/-/react-player-2.12.0.tgz", + "integrity": "sha512-rymLRz/2GJJD+Wc01S7S+i9pGMFYnNmQibR2gVE3KmHJCBNN8BhPAlOPTGZtn1uKpJ6p4RPLlzPQ1OLreXd8gw==", + "dependencies": { + "deepmerge": "^4.0.0", + "load-script": "^1.0.0", + "memoize-one": "^5.1.1", + "prop-types": "^15.7.2", + "react-fast-compare": "^3.0.1" + }, + "peerDependencies": { + "react": ">=16.6.0" + } + }, + "node_modules/react-player/node_modules/memoize-one": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz", + "integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==" + }, "node_modules/react-redux": { "version": "7.2.8", "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.8.tgz", @@ -36488,6 +36519,11 @@ "uc.micro": "^1.0.1" } }, + "load-script": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/load-script/-/load-script-1.0.0.tgz", + "integrity": "sha512-kPEjMFtZvwL9TaZo0uZ2ml+Ye9HUMmPwbYRJ324qF9tqMejwykJ5ggTyvzmrbBeapCAbk98BSbTeovHEEP1uCA==" + }, "loader-runner": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", @@ -38930,6 +38966,11 @@ "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz", "integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==" }, + "react-fast-compare": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz", + "integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==" + }, "react-hook-form": { "version": "7.37.0", "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.37.0.tgz", @@ -38960,6 +39001,25 @@ "@types/mapbox-gl": "^2.6.0" } }, + "react-player": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/react-player/-/react-player-2.12.0.tgz", + "integrity": "sha512-rymLRz/2GJJD+Wc01S7S+i9pGMFYnNmQibR2gVE3KmHJCBNN8BhPAlOPTGZtn1uKpJ6p4RPLlzPQ1OLreXd8gw==", + "requires": { + "deepmerge": "^4.0.0", + "load-script": "^1.0.0", + "memoize-one": "^5.1.1", + "prop-types": "^15.7.2", + "react-fast-compare": "^3.0.1" + }, + "dependencies": { + "memoize-one": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz", + "integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==" + } + } + }, "react-redux": { "version": "7.2.8", "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.8.tgz", diff --git a/met-web/package.json b/met-web/package.json index ae53b14d3..815f4e561 100644 --- a/met-web/package.json +++ b/met-web/package.json @@ -55,6 +55,7 @@ "react-hook-form": "^7.37.0", "react-if": "^4.1.4", "react-map-gl": "^7.0.21", + "react-player": "^2.12.0", "react-redux": "^7.2.8", "react-router-dom": "^6.10.0", "react-scripts": "5.0.1", diff --git a/met-web/src/components/engagement/form/EngagementWidgets/Documents/DocumentOptionCard.tsx b/met-web/src/components/engagement/form/EngagementWidgets/Documents/DocumentOptionCard.tsx index 24018c51a..3e37413fa 100644 --- a/met-web/src/components/engagement/form/EngagementWidgets/Documents/DocumentOptionCard.tsx +++ b/met-web/src/components/engagement/form/EngagementWidgets/Documents/DocumentOptionCard.tsx @@ -20,7 +20,7 @@ const DocumentOptionCard = () => { const [isCreatingWidget, setIsCreatingWidget] = useState(false); const handleCreateWidget = async () => { - const alreadyExists = widgets.map((widget) => widget.widget_type_id).includes(WidgetType.Document); + const alreadyExists = widgets.some((widget) => widget.widget_type_id === WidgetType.Document); if (alreadyExists) { handleWidgetDrawerTabValueChange(WidgetTabValues.DOCUMENT_FORM); return; diff --git a/met-web/src/components/engagement/form/EngagementWidgets/Events/EventsOptionCard.tsx b/met-web/src/components/engagement/form/EngagementWidgets/Events/EventsOptionCard.tsx index bd72061a4..923a2b496 100644 --- a/met-web/src/components/engagement/form/EngagementWidgets/Events/EventsOptionCard.tsx +++ b/met-web/src/components/engagement/form/EngagementWidgets/Events/EventsOptionCard.tsx @@ -21,7 +21,7 @@ const EventsOptionCard = () => { const [isCreatingWidget, setIsCreatingWidget] = useState(false); const handleCreateWidget = async () => { - const alreadyExists = widgets.map((widget) => widget.widget_type_id).includes(WidgetType.Events); + const alreadyExists = widgets.some((widget) => widget.widget_type_id === WidgetType.Events); if (alreadyExists) { handleWidgetDrawerTabValueChange(WidgetTabValues.EVENTS_FORM); return; diff --git a/met-web/src/components/engagement/form/EngagementWidgets/Map/MapOptionCard.tsx b/met-web/src/components/engagement/form/EngagementWidgets/Map/MapOptionCard.tsx index 94f997969..ee39e4379 100644 --- a/met-web/src/components/engagement/form/EngagementWidgets/Map/MapOptionCard.tsx +++ b/met-web/src/components/engagement/form/EngagementWidgets/Map/MapOptionCard.tsx @@ -21,7 +21,7 @@ const MapOptionCard = () => { const [isCreatingWidget, setIsCreatingWidget] = useState(false); const handleCreateWidget = async () => { - const alreadyExists = widgets.map((widget) => widget.widget_type_id).includes(WidgetType.Map); + const alreadyExists = widgets.some((widget) => widget.widget_type_id === WidgetType.Map); if (alreadyExists) { handleWidgetDrawerTabValueChange(WidgetTabValues.MAP_FORM); return; diff --git a/met-web/src/components/engagement/form/EngagementWidgets/Phases/PhasesOptionCard.tsx b/met-web/src/components/engagement/form/EngagementWidgets/Phases/PhasesOptionCard.tsx index 6c6b266b6..62887eb20 100644 --- a/met-web/src/components/engagement/form/EngagementWidgets/Phases/PhasesOptionCard.tsx +++ b/met-web/src/components/engagement/form/EngagementWidgets/Phases/PhasesOptionCard.tsx @@ -26,7 +26,7 @@ const PhasesOptionCard = () => { const [isCreatingWidget, setIsCreatingWidget] = useState(false); const handleCreateWidget = async () => { - const alreadyExists = widgets.map((widget) => widget.widget_type_id).includes(WidgetType.Phases); + const alreadyExists = widgets.some((widget) => widget.widget_type_id === WidgetType.Phases); if (alreadyExists) { handleWidgetDrawerTabValueChange(WidgetTabValues.PHASES_FORM); return; diff --git a/met-web/src/components/engagement/form/EngagementWidgets/Subscribe/SubscribeOptionCard.tsx b/met-web/src/components/engagement/form/EngagementWidgets/Subscribe/SubscribeOptionCard.tsx index e3cac018f..31d6baf99 100644 --- a/met-web/src/components/engagement/form/EngagementWidgets/Subscribe/SubscribeOptionCard.tsx +++ b/met-web/src/components/engagement/form/EngagementWidgets/Subscribe/SubscribeOptionCard.tsx @@ -19,7 +19,7 @@ const SubscribeOptionCard = () => { const [isCreatingWidget, setIsCreatingWidget] = useState(false); const handleCreateWidget = async () => { - const alreadyExists = widgets.map((widget) => widget.widget_type_id).includes(WidgetType.Subscribe); + const alreadyExists = widgets.some((widget) => widget.widget_type_id === WidgetType.Subscribe); if (alreadyExists) { return; } diff --git a/met-web/src/components/engagement/form/EngagementWidgets/Video/VideoOptionCard.tsx b/met-web/src/components/engagement/form/EngagementWidgets/Video/VideoOptionCard.tsx index ee0ebb473..b8e11bbcd 100644 --- a/met-web/src/components/engagement/form/EngagementWidgets/Video/VideoOptionCard.tsx +++ b/met-web/src/components/engagement/form/EngagementWidgets/Video/VideoOptionCard.tsx @@ -9,8 +9,8 @@ import { useAppDispatch } from 'hooks'; import { openNotification } from 'services/notificationService/notificationSlice'; import { optionCardStyle } from '../Phases/PhasesOptionCard'; import { WidgetTabValues } from '../type'; -import LocationOnIcon from '@mui/icons-material/LocationOn'; import { useCreateWidgetMutation } from 'apiManager/apiSlices/widgets'; +import MovieIcon from '@mui/icons-material/Movie'; const VideoOptionCard = () => { const { widgets, loadWidgets, handleWidgetDrawerOpen, handleWidgetDrawerTabValueChange } = @@ -21,7 +21,7 @@ const VideoOptionCard = () => { const [isCreatingWidget, setIsCreatingWidget] = useState(false); const handleCreateWidget = async () => { - const alreadyExists = widgets.map((widget) => widget.widget_type_id).includes(WidgetType.Video); + const alreadyExists = widgets.some((widget) => widget.widget_type_id === WidgetType.Video); if (alreadyExists) { handleWidgetDrawerTabValueChange(WidgetTabValues.VIDEO_FORM); return; @@ -65,7 +65,7 @@ const VideoOptionCard = () => { - + { const [isCreatingWidget, setIsCreatingWidget] = useState(false); const handleCreateWidget = async () => { - const alreadyExists = widgets.map((widget) => widget.widget_type_id).includes(WidgetType.WhoIsListening); + const alreadyExists = widgets.some((widget) => widget.widget_type_id === WidgetType.WhoIsListening); if (alreadyExists) { handleWidgetDrawerTabValueChange(WidgetTabValues.WHO_IS_LISTENING_FORM); return; diff --git a/met-web/src/components/engagement/view/widgets/Video/VideoWidgetView.tsx b/met-web/src/components/engagement/view/widgets/Video/VideoWidgetView.tsx new file mode 100644 index 000000000..6b09fcb6a --- /dev/null +++ b/met-web/src/components/engagement/view/widgets/Video/VideoWidgetView.tsx @@ -0,0 +1,90 @@ +import React, { useEffect, useState } from 'react'; +import { MetPaper, MetHeader2, MetParagraph } from 'components/common'; +import { Grid, Skeleton, Divider } from '@mui/material'; +import { Widget } from 'models/widget'; +import { useAppDispatch } from 'hooks'; +import { openNotification } from 'services/notificationService/notificationSlice'; +import { VideoWidget } from 'models/videoWidget'; +import { fetchVideoWidgets } from 'services/widgetService/VideoService'; +import ReactPlayer from 'react-player/lazy'; + +interface VideoWidgetProps { + widget: Widget; +} + +const VideoWidgetView = ({ widget }: VideoWidgetProps) => { + const dispatch = useAppDispatch(); + const [videoWidget, setVideoWidget] = useState(null); + const [isLoading, setIsLoading] = useState(true); + + const fetchVideo = async () => { + try { + const videos = await fetchVideoWidgets(widget.id); + const video = videos[videos.length - 1]; + setVideoWidget(video); + setIsLoading(false); + } catch (error) { + setIsLoading(false); + console.log(error); + dispatch( + openNotification({ + severity: 'error', + text: 'Error occurred while fetching Engagement widgets information', + }), + ); + } + }; + + useEffect(() => { + fetchVideo(); + }, [widget]); + + if (isLoading) { + return ( + + + + + + + + + + + + + ); + } + + if (!videoWidget) { + return null; + } + + return ( + <> + + + + Video + + + + {videoWidget.description} + + + + + + + + ); +}; + +export default VideoWidgetView; diff --git a/met-web/src/components/engagement/view/widgets/WidgetSwitch.tsx b/met-web/src/components/engagement/view/widgets/WidgetSwitch.tsx index 1ea71b8c3..ee2de56ea 100644 --- a/met-web/src/components/engagement/view/widgets/WidgetSwitch.tsx +++ b/met-web/src/components/engagement/view/widgets/WidgetSwitch.tsx @@ -6,6 +6,7 @@ import DocumentWidget from './DocumentWidget'; import SubscribeWidget from './Subscribe/SubscribeWidget'; import EventsWidget from './Events/EventsWidget'; import MapWidget from './Map/MapWidget'; +import VideoWidgetView from './Video/VideoWidgetView'; interface WidgetSwitchProps { widget: Widget; } @@ -29,6 +30,9 @@ export const WidgetSwitch = ({ widget }: WidgetSwitchProps) => { + + + ); diff --git a/met-web/src/services/widgetService/VideoService/index.tsx b/met-web/src/services/widgetService/VideoService/index.tsx index adc12bb01..4398527c8 100644 --- a/met-web/src/services/widgetService/VideoService/index.tsx +++ b/met-web/src/services/widgetService/VideoService/index.tsx @@ -24,10 +24,7 @@ export const postVideo = async (widget_id: number, data: PostVideoRequest): Prom try { const url = replaceUrl(Endpoints.VideoWidgets.CREATE, 'widget_id', String(widget_id)); const response = await http.PostRequest(url, data); - if (response.data) { - return response.data; - } - return Promise.reject('Failed to create video widget'); + return response.data || Promise.reject('Failed to create video widget'); } catch (err) { return Promise.reject(err); } @@ -52,10 +49,7 @@ export const patchVideo = async ( }, }); const response = await http.PatchRequest(url, data); - if (response.data) { - return response.data; - } - return Promise.reject('Failed to create video widget'); + return response.data || Promise.reject('Failed to create video widget'); } catch (err) { return Promise.reject(err); }