From 3dd5d7dde9a13ce7dfb58ef736d916e29840f89e Mon Sep 17 00:00:00 2001 From: sinatragianpaolo Date: Mon, 17 Jun 2024 23:28:04 +0200 Subject: [PATCH 1/4] feat: Remove InsightSection from UxDashboardForm --- .../UxForm/Insights/InsightCard.tsx | 144 ---------- .../UxForm/Insights/InsightModal.tsx | 245 ------------------ .../UxDashboard/UxForm/Insights/index.tsx | 96 ------- src/pages/UxDashboard/UxForm/index.tsx | 9 - 4 files changed, 494 deletions(-) delete mode 100644 src/pages/UxDashboard/UxForm/Insights/InsightCard.tsx delete mode 100644 src/pages/UxDashboard/UxForm/Insights/InsightModal.tsx delete mode 100644 src/pages/UxDashboard/UxForm/Insights/index.tsx diff --git a/src/pages/UxDashboard/UxForm/Insights/InsightCard.tsx b/src/pages/UxDashboard/UxForm/Insights/InsightCard.tsx deleted file mode 100644 index 5ee990fa..00000000 --- a/src/pages/UxDashboard/UxForm/Insights/InsightCard.tsx +++ /dev/null @@ -1,144 +0,0 @@ -import { - Card, - Pill, - Button, - Title, -} from "@appquality/appquality-design-system"; -import SeverityPill from "../components/SeverityPill"; -import { setInsightIndex, setInsightModalOpen } from "../../uxDashboardSlice"; -import { FormInsight, FormValuesInterface } from "../FormProvider"; -import { useFormikContext } from "formik"; -import { useAppDispatch } from "src/store"; -import { setSelectedInsight } from "../../uxDashboardSlice"; -import { Film } from "react-bootstrap-icons"; -import styled from "styled-components"; -import Handler from "../components/Handler"; - -const InsightPillsWrapper = styled.div` - display: flex; - flex-wrap: wrap; - gap: ${({ theme }) => theme.grid.sizes[1]}; -`; - -interface InsightCardProps { - insight: FormInsight; - index: number; - removeInsight: (index: number) => void; - dragHandleProps?: any; -} - -const StyledCard = styled(Card)` - .insight-card-body { - padding-top: ${({ theme }) => theme.grid.sizes[3]}; - padding-bottom: ${({ theme }) => theme.grid.sizes[3]}; - padding-right: ${({ theme }) => theme.grid.sizes[3]}; - display: grid; - grid-template-columns: 30px 1fr; - } -`; - -const CardHeader = styled.div` - display: flex; - justify-content: space-between; - align-items: center; -`; - -const CardFooter = styled.div` - display: grid; - grid-template-columns: 75% auto; - grid-column-gap: ${({ theme }) => theme.grid.sizes[3]}; - - @media (max-width: ${({ theme }) => theme.grid.breakpoints.md}) { - grid-template-columns: 1fr; - grid-row-gap: ${({ theme }) => theme.grid.sizes[3]}; - } -`; - -export const InsightCard = ({ - insight, - removeInsight, - index, - dragHandleProps, -}: InsightCardProps) => { - const { submitForm } = useFormikContext(); - const dispatch = useAppDispatch(); - function editInsight(insight: FormInsight): void { - dispatch(setSelectedInsight(insight)); - dispatch(setInsightModalOpen(true)); - } - - const Actions = () => ( -
- - -
- ); - - return ( - - Scoperta {index + 1} - - - } - data-qa={`insight-card-${index}`} - > - -
- - {insight.title} - -
{insight.description}
- - - {insight?.severity && } - {Array.isArray(insight.cluster) && - insight.cluster.map((cluster) => ( - - {cluster.name} - - ))} - {insight.cluster && !Array.isArray(insight.cluster) && ( - - General - - )} - -
- {" "} - {insight.videoParts.length} video -
-
-
-
- ); -}; diff --git a/src/pages/UxDashboard/UxForm/Insights/InsightModal.tsx b/src/pages/UxDashboard/UxForm/Insights/InsightModal.tsx deleted file mode 100644 index c7280bd6..00000000 --- a/src/pages/UxDashboard/UxForm/Insights/InsightModal.tsx +++ /dev/null @@ -1,245 +0,0 @@ -import { - Button, - Modal, - Field, - FieldProps, - FormikField, - TextareaField, - Title, - Text, - FormLabel, - BSGrid, - BSCol, - Card, -} from "@appquality/appquality-design-system"; -import { useFormikContext } from "formik"; -import { useAppDispatch, useAppSelector } from "src/store"; -import siteWideMessageStore from "src/redux/siteWideMessages"; -import { resetInsight, setInsightModalOpen } from "../../uxDashboardSlice"; -import styled from "styled-components"; -import SeverityField from "../components/fields/SeverityField"; -import ClusterField from "../components/fields/ClusterField"; -import VideoParts from "../VideoParts"; -import { - FormValuesInterface, - insightDescriptionMaxChar, -} from "../FormProvider"; -import { useMemo } from "react"; -import { fieldName } from "."; - -interface InsightModalProps { - remove: (index: number) => void; -} -const StyledModal = styled(Modal)` - .modal { - width: 100vw; - height: 100vh; - max-height: 100vh; - } -`; - -const ModalFooter = ({ remove }: InsightModalProps) => { - const dispatch = useAppDispatch(); - const { add } = siteWideMessageStore(); - const { insightIndex } = useAppSelector((state) => state.uxDashboard); - const { - submitForm, - setFieldTouched, - setFieldValue, - errors, - values, - initialValues, - } = useFormikContext(); - const isNewInsight = useMemo( - () => !values[fieldName][insightIndex].id, - [values, insightIndex] - ); - const handleAdd = () => { - if (errors[fieldName] && errors[fieldName][insightIndex]) { - setFieldTouched(`${fieldName}[${insightIndex}].title`); - setFieldTouched(`${fieldName}[${insightIndex}].description`); - setFieldTouched(`${fieldName}[${insightIndex}].cluster`); // could be a string or an object - setFieldTouched(`${fieldName}[${insightIndex}].severity.id`); - - const insightErrors = errors[fieldName][insightIndex]; - Object.keys(insightErrors).forEach((key) => { - if ( - key === "videoParts" && - typeof insightErrors === "object" && - typeof insightErrors.videoParts !== "string" - ) { - insightErrors.videoParts?.forEach((videoPart, videoPartIndex) => { - Object.keys(videoPart).forEach((videoPartKey) => { - setFieldTouched( - `${fieldName}[${insightIndex}].videoParts[${videoPartIndex}].${videoPartKey}` - ); - }); - }); - } - }); - alert("compila tutti i campi obbligatori"); - return; - } - if (Object.keys(errors).length > 0) { - add({ - type: "warning", - message: ( - - - Attenzione! Hai inserito una scoperta, ma la bozza non è salvata - -
- La bozza non è stata salvata automaticamente perchè manca la - compilazione di alcuni dati obbligatori. Compilati e salva la - bozza. -
-
- ), - expire: 8, - }); - } - submitForm(); - dispatch(resetInsight()); - dispatch(setInsightModalOpen(false)); - }; - const handleClose = async () => { - dispatch(resetInsight()); - dispatch(setInsightModalOpen(false)); - }; - const handleDismiss = async () => { - if (isNewInsight) remove(insightIndex); - if (!isNewInsight) setFieldValue(fieldName, initialValues[fieldName]); - handleClose(); - }; - return ( -
- - -
- ); -}; - -const InsightModal = ({ remove }: InsightModalProps) => { - const { insightIndex, isInsightModalOpen } = useAppSelector( - (state) => state.uxDashboard - ); - return ( - { - /* silence */ - }} - footer={} - > -
- - - - Cosa e dove<span className="aq-text-danger">*</span> - - - - - - {(fieldProps: FieldProps) => ( - - )} - - - - - {(fieldProps: FieldProps) => } - - - - - - - - - Contenuto<span className="aq-text-danger">*</span> - - - -
- - Descrizione{" "} - - (Massimo {insightDescriptionMaxChar} caratteri) - -
- } - /> -
- - - - - - Scegli un titolo composto da: - - Tipo di problema/aspetto positivo: - - ”Malfunzionamenti”, “Difficoltà di navigazione”, “Criticità” - - - + - - Touchpoint/Componente/Sezione: - - ”Sito Desktop”, “Form”, “Pagina Prodotto”... - - Ad esempio: - - ”Criticità sull'esperienza desktop” - - - Descrivi poi brevemente in cosa consiste il - problema/need/feedback positivo individuato - - - - - - - - Evidenze (Spezzoni Video) - - - - - - - -
- ); -}; - -export default InsightModal; diff --git a/src/pages/UxDashboard/UxForm/Insights/index.tsx b/src/pages/UxDashboard/UxForm/Insights/index.tsx deleted file mode 100644 index 3c980109..00000000 --- a/src/pages/UxDashboard/UxForm/Insights/index.tsx +++ /dev/null @@ -1,96 +0,0 @@ -import { - BSCol, - BSGrid, - Card, - FormLabel, - Title, -} from "@appquality/appquality-design-system"; -import { FieldArray } from "formik"; -import { setInsightIndex, setInsightModalOpen } from "../../uxDashboardSlice"; -import { FormInsight, FormValuesInterface } from "../FormProvider"; -import { useFormikContext } from "formik"; -import { InsightCard } from "./InsightCard"; -import { useAppDispatch } from "src/store"; -import InsightModal from "./InsightModal"; -import { AddNew } from "../components/AddNew"; -import { v4 as uuidv4 } from "uuid"; -import DragNDropProvider from "../DragNDropProvider"; -import { OnDragEndResponder } from "react-beautiful-dnd"; - -type NewFormInsight = Pick< - FormInsight, - "internalId" | "title" | "description" | "videoParts" ->; - -export const fieldName = "insights"; - -const InsightSection = () => { - const dispatch = useAppDispatch(); - const { values } = useFormikContext(); - const insights = values[fieldName]; - return ( - - { - const handleDragEnd: OnDragEndResponder = (result) => { - if (!result.destination) { - return; - } - move(result.source.index, result.destination.index); - }; - return ( - <> - - - - {insights && insights.length > 0 && ( - - onDragEnd={handleDragEnd} - items={insights} - renderItem={(insight, index, dragHandleProps) => ( - - )} - /> - )} - { - const newInsight: NewFormInsight = { - internalId: uuidv4(), - title: "", - description: "", - videoParts: [], - }; - push(newInsight); - dispatch(setInsightIndex(form.values.insights.length)); - dispatch(setInsightModalOpen(true)); - }} - > - Aggiungi scoperta - - - - - - - È l'executive summary del test, dove ogni scoperta è - associata ad uno o più video. - - - - - - ); - }} - /> - - ); -}; - -export default InsightSection; diff --git a/src/pages/UxDashboard/UxForm/index.tsx b/src/pages/UxDashboard/UxForm/index.tsx index 90a7761f..43f5ca53 100644 --- a/src/pages/UxDashboard/UxForm/index.tsx +++ b/src/pages/UxDashboard/UxForm/index.tsx @@ -1,5 +1,4 @@ import { Title, Form, Text } from "@appquality/appquality-design-system"; -import InsightSection from "./Insights"; import Test from "./campaign/Goal"; import Methodology from "./campaign/Methodology"; import { useInView } from "react-intersection-observer"; @@ -110,14 +109,6 @@ const UxDashboardForm = () => { > - - - ); From c221004cd325aaf8a9d66638fe3c1115c197881f Mon Sep 17 00:00:00 2001 From: sinatragianpaolo Date: Wed, 19 Jun 2024 08:25:38 +0200 Subject: [PATCH 2/4] Remove Insights and videoParts from UxDashboardForm --- src/pages/UxDashboard/UxForm/FormProvider.tsx | 96 ------- .../UxForm/VideoParts/ListItemCard.tsx | 23 -- .../UxForm/VideoParts/VideoPart.tsx | 142 ----------- .../VideoParts/VideoPlayer/VideoControls.tsx | 241 ------------------ .../UxForm/VideoParts/VideoPlayer/index.tsx | 136 ---------- .../UxDashboard/UxForm/VideoParts/index.tsx | 147 ----------- .../UxForm/components/SeverityPill.tsx | 35 --- .../UxForm/components/fields/ClusterField.tsx | 85 ------ .../components/fields/SeverityField.tsx | 63 ----- src/pages/UxDashboard/uxDashboardSlice.ts | 21 -- src/services/tryberApi/index.ts | 41 --- src/utils/schema.ts | 45 +--- 12 files changed, 4 insertions(+), 1071 deletions(-) delete mode 100644 src/pages/UxDashboard/UxForm/VideoParts/ListItemCard.tsx delete mode 100644 src/pages/UxDashboard/UxForm/VideoParts/VideoPart.tsx delete mode 100644 src/pages/UxDashboard/UxForm/VideoParts/VideoPlayer/VideoControls.tsx delete mode 100644 src/pages/UxDashboard/UxForm/VideoParts/VideoPlayer/index.tsx delete mode 100644 src/pages/UxDashboard/UxForm/VideoParts/index.tsx delete mode 100644 src/pages/UxDashboard/UxForm/components/SeverityPill.tsx delete mode 100644 src/pages/UxDashboard/UxForm/components/fields/ClusterField.tsx delete mode 100644 src/pages/UxDashboard/UxForm/components/fields/SeverityField.tsx diff --git a/src/pages/UxDashboard/UxForm/FormProvider.tsx b/src/pages/UxDashboard/UxForm/FormProvider.tsx index 18f8b050..bf8244eb 100644 --- a/src/pages/UxDashboard/UxForm/FormProvider.tsx +++ b/src/pages/UxDashboard/UxForm/FormProvider.tsx @@ -16,49 +16,6 @@ export interface FormQuestion { name: GetCampaignsByCampaignUxApiResponse["questions"][number]["name"]; id?: GetCampaignsByCampaignUxApiResponse["questions"][number]["id"]; } -export interface FormVideoPart { - id?: NonNullable< - GetCampaignsByCampaignUxApiResponse["insights"] - >[number]["videoParts"][number]["id"]; - internalId: string; - end: NonNullable< - GetCampaignsByCampaignUxApiResponse["insights"] - >[number]["videoParts"][number]["end"]; - description: NonNullable< - GetCampaignsByCampaignUxApiResponse["insights"] - >[number]["videoParts"][number]["description"]; - start: NonNullable< - GetCampaignsByCampaignUxApiResponse["insights"] - >[number]["videoParts"][number]["start"]; - mediaId: NonNullable< - GetCampaignsByCampaignUxApiResponse["insights"] - >[number]["videoParts"][number]["mediaId"]; - streamUrl: NonNullable< - GetCampaignsByCampaignUxApiResponse["insights"] - >[number]["videoParts"][number]["streamUrl"]; - url: NonNullable< - GetCampaignsByCampaignUxApiResponse["insights"] - >[number]["videoParts"][number]["url"]; -} -export interface FormInsight { - id?: NonNullable< - GetCampaignsByCampaignUxApiResponse["insights"] - >[number]["id"]; - internalId: string; - title: NonNullable< - GetCampaignsByCampaignUxApiResponse["insights"] - >[number]["title"]; - description: NonNullable< - GetCampaignsByCampaignUxApiResponse["insights"] - >[number]["description"]; - severity: NonNullable< - GetCampaignsByCampaignUxApiResponse["insights"] - >[number]["severity"]; - cluster: NonNullable< - GetCampaignsByCampaignUxApiResponse["insights"] - >[number]["clusters"]; - videoParts: FormVideoPart[]; -} export interface FormSentiment { clusterId: NonNullable< @@ -75,7 +32,6 @@ export interface FormValuesInterface { methodology: GetCampaignsByCampaignUxApiResponse["methodology"]; questions: FormQuestion[]; usersNumber?: GetCampaignsByCampaignUxApiResponse["usersNumber"]; - insights: FormInsight[]; sentiments?: FormSentiment[]; } @@ -110,32 +66,6 @@ const FormProvider = ({ children }: { children: ReactNode }) => { }; }, []) || [], usersNumber: currentData?.usersNumber, - insights: - currentData?.insights?.map((insight) => { - return { - id: insight.id, - internalId: uuidv4(), - title: insight.title, - description: insight.description, - severity: { - id: insight.severity.id, - name: insight.severity.name, - }, - cluster: insight.clusters, - videoParts: insight.videoParts.map((video) => { - return { - id: video.id, - internalId: uuidv4(), - start: video.start, - end: video.end - video.start, - description: video.description, - mediaId: video.mediaId, - streamUrl: video.streamUrl, - url: video.url, - }; - }), - }; - }) || [], sentiments: currentData?.sentiments && currentData.sentiments.length ? currentData.sentiments.map((sentiment) => { @@ -229,31 +159,6 @@ const FormProvider = ({ children }: { children: ReactNode }) => { ), }); - const mapFormInsightsForPatch = (insights: FormValuesInterface["insights"]) => - insights?.map((insight, index) => { - return { - id: insight.id, - title: insight.title, - description: insight.description, - order: index, - severityId: insight.severity.id, - clusterIds: Array.isArray(insight.cluster) - ? insight.cluster.map((cluster) => cluster.id) - : insight.cluster, - videoParts: !insight.videoParts - ? [] - : insight.videoParts.map((video, videoIndex) => { - return { - id: video.id, - order: videoIndex, - start: video.start, - end: Math.round(video.end) + video.start, - mediaId: video.mediaId, - description: video.description, - }; - }), - }; - }); return ( { })), methodology: values.methodology, usersNumber: values.usersNumber, - insights: mapFormInsightsForPatch(values.insights) || [], sentiments: values.sentiments || [], }, }); diff --git a/src/pages/UxDashboard/UxForm/VideoParts/ListItemCard.tsx b/src/pages/UxDashboard/UxForm/VideoParts/ListItemCard.tsx deleted file mode 100644 index c9231947..00000000 --- a/src/pages/UxDashboard/UxForm/VideoParts/ListItemCard.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import { Card } from "@appquality/appquality-design-system"; -import styled from "styled-components"; - -export const ListItemCard = styled(Card)` - @media (min-width: 768px) { - .aq-card-body { - display: grid; - grid-template-columns: 20px 350px 1fr 50px; - grid-gap: ${({ theme }) => theme.grid.sizes[3]}; - margin: 0; - > div:nth-child(2) { - background-color: ${({ theme }) => theme.colors.gray900}; - display: flex; - align-items: center; - justify-content: center; - } - > div:nth-child(3) { - padding-top: ${({ theme }) => theme.grid.sizes[3]}; - padding-bottom: ${({ theme }) => theme.grid.sizes[3]}; - } - } - } -`; diff --git a/src/pages/UxDashboard/UxForm/VideoParts/VideoPart.tsx b/src/pages/UxDashboard/UxForm/VideoParts/VideoPart.tsx deleted file mode 100644 index 8d84f299..00000000 --- a/src/pages/UxDashboard/UxForm/VideoParts/VideoPart.tsx +++ /dev/null @@ -1,142 +0,0 @@ -import { - Input, - FormikField, - TextareaField, - FieldProps, - FormGroup, - ErrorMessage, - FormLabel, - Button, -} from "@appquality/appquality-design-system"; -import { useVideoContext } from "@appquality/stream-player"; -import VideoPlayer from "./VideoPlayer"; -import moment from "moment"; -import styled from "styled-components"; -import { Trash } from "react-bootstrap-icons"; -import { ListItemCard } from "./ListItemCard"; -import { videoCitMaxChar } from "../FormProvider"; -import Handler from "../components/Handler"; -import { DraggableProvidedDragHandleProps } from "react-beautiful-dnd"; - -const Actions = styled.div` - display: flex; - flex-direction: column; - align-items: center; - padding-top: ${({ theme }) => theme.grid.sizes[2]}; - padding-bottom: ${({ theme }) => theme.grid.sizes[4]}; -`; - -const DeleteButton = styled(Button)` - border-radius: 50%; - border: none; - padding: 8px 4px; - transition: all 0.2s; - width: 36px; - min-width: 36px; - height: 36px; - min-height: 36px; -`; - -const VideoPart = ({ - start, - videoPartIndex, - fieldName, - remove, - handleDragProps, - title, -}: { - start: number; - videoPartIndex: number; - fieldName: string; - remove: (index: number) => void; - handleDragProps?: DraggableProvidedDragHandleProps | null; - title?: string; -}) => { - const { - context: { player }, - } = useVideoContext(); - - return ( - - - -
- { - if (player) { - let error; - if (value > player.totalTime - start) { - error = "Non puoi tagliare oltre la durata del video"; - } - return error; - } - }} - > - {({ field, form }: FieldProps) => ( - - - { - field.onBlur(field.name); - form.setFieldTouched(field.name); - form.validateField(field.name); - }, - }} - value={ - !field.value - ? "00:00:00" - : moment.utc(field.value * 1000).format("HH:mm:ss") - } - onChange={(value) => { - form.setFieldValue( - field.name, - moment.duration(value).asSeconds() - ); - form.setFieldTouched(field.name); - }} - /> - - - )} - - - Citazione utente{" "} - (Massimo {videoCitMaxChar} caratteri) -
- } - height="4em" - /> - - - { - window.confirm("Are you sure you wish to delete this item?") && - remove(videoPartIndex); - }} - > - - - -
- ); -}; -export default VideoPart; diff --git a/src/pages/UxDashboard/UxForm/VideoParts/VideoPlayer/VideoControls.tsx b/src/pages/UxDashboard/UxForm/VideoParts/VideoPlayer/VideoControls.tsx deleted file mode 100644 index af477cb5..00000000 --- a/src/pages/UxDashboard/UxForm/VideoParts/VideoPlayer/VideoControls.tsx +++ /dev/null @@ -1,241 +0,0 @@ -import { Button } from "@appquality/appquality-design-system"; -import Video, { useVideoContext } from "@appquality/stream-player"; -import styled from "styled-components"; -import { useFormikContext } from "formik"; -import { - ArrowCounterclockwise, - Scissors, - PlayCircleFill, - PauseCircleFill, - ArrowsFullscreen, - FullscreenExit, - VolumeMuteFill, - VolumeUpFill, - PlayFill, - PauseFill, -} from "react-bootstrap-icons"; -import { useState } from "react"; -import { FormValuesInterface } from "../../FormProvider"; - -const controlsMargin = "10px"; -const ProgressBar = styled(Video.ProgressBar)` - cursor: pointer; - height: 8px; - width: calc(100% - ${controlsMargin} * 2); - margin: ${controlsMargin} 0; - background: ${({ theme }) => theme.colors.gray500}; - background: ${({ theme }) => - `linear-gradient(180deg, rgba(0,0,0,0) 39%, ${theme.colors.gray500} 40%, ${theme.colors.gray500} 60%, rgba(0,0,0,0) 61%);`}; - border-radius: 4px; - :after { - background-color: ${({ theme }) => theme.colors.white}; - background: ${({ theme }) => - `linear-gradient(180deg, rgba(0,0,0,0) 39%, ${theme.colors.white} 40%, ${theme.colors.white} 60%, rgba(0,0,0,0) 61%);`}; - } -`; -const InfoContainer = styled.div<{ isFullScreen?: boolean }>` - height: 100%; - width: 100%; - display: flex; - flex-direction: column; - justify-content: space-between; - align-items: center; - padding: 10px 10px 0 10px; - color: ${({ theme }) => theme.colors.white}; - .video-title { - align-self: flex-start; - } - .video-timer { - align-self: flex-end; - } - ${({ isFullScreen }) => - isFullScreen && - ` - flex-direction: row; - `} -`; - -const ControlsWrapper = styled.div<{ show: boolean; isFullScreen: boolean }>` - opacity: 0; - transition: opacity 0.2s; - position: absolute; - bottom: 0; - left: 0; - width: 100%; - height: 100%; - background: rgb(0, 0, 0); - background: linear-gradient( - 180deg, - rgba(0, 0, 0, 0.6) 74%, - rgba(0, 0, 0, 0.8) 100% - ); - display: flex; - flex-direction: column; - justify-content: flex-end; - align-items: center; - svg { - fill: white; - } - button { - background-color: transparent; - border: none; - } - ${({ isFullScreen, show }) => - (!isFullScreen || show) && - ` - &:hover { - opacity: 1; - } - `} -`; - -const CenteredPlayPause = styled(Video.PlayPauseButton)` - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - - svg { - width: 40px; - height: 40px; - } -`; - -const OtherControls = styled.div<{ isFullScreen?: boolean }>` - width: calc(100% - ${controlsMargin} * 2); - display: flex; - justify-content: space-between; - align-items: center; - .player-control { - display: inline-flex; - cursor: pointer; - padding: 0; - justify-content: center; - align-items: center; - width: 32px; - height: 32px; - - svg { - width: 14px; - height: 14px; - } - } - .player-control + .player-control { - margin-left: 5px; - } - ${({ isFullScreen }) => - isFullScreen && - ` - .player-control { - width: 40px; - height: 40px; - - svg { - width: 18px; - height: 18px; - } - } - .player-control + .player-control { - margin-left: 8px; - } - `} -`; - -export const VideoControls = ({ - videoFieldName, - title, - isFullScreen, - setFullScreen, -}: { - videoFieldName: string; - title?: string; - isFullScreen: boolean; - setFullScreen: (isFullScreen: boolean) => void; -}) => { - const [isPointerMoving, setIsPointerMoving] = useState(false); - const [timer, setTimer] = useState(); - const { context, togglePlay } = useVideoContext(); - const { setFieldValue, getFieldMeta } = - useFormikContext(); - const fillEndTime = () => { - if (context.player?.currentTime) { - const start = getFieldMeta< - FormValuesInterface["insights"][number]["videoParts"][number] - >(`${videoFieldName}`).value.start; - setFieldValue( - `${videoFieldName}.end`, - context.player.currentTime - start - ); - // setIsPlaying(false); not working in this version - if (context.isPlaying) { - togglePlay(); - } - setFullScreen(false); - } else { - alert("Current time is not available"); - } - }; - - const handleMove = () => { - setIsPointerMoving(true); - clearTimeout(timer); - setTimer( - setTimeout(() => { - setIsPointerMoving(false); - }, 1500) - ); - }; - - return ( - - , pause: }} - /> - - {title} - - - - - , off: }} - /> -
- }} - /> - , pause: }} - /> - -
-
- {isFullScreen ? ( - { - setFullScreen(false); - }} - /> - ) : ( - { - setFullScreen(true); - }} - /> - )} -
-
-
- ); -}; diff --git a/src/pages/UxDashboard/UxForm/VideoParts/VideoPlayer/index.tsx b/src/pages/UxDashboard/UxForm/VideoParts/VideoPlayer/index.tsx deleted file mode 100644 index ecc14fac..00000000 --- a/src/pages/UxDashboard/UxForm/VideoParts/VideoPlayer/index.tsx +++ /dev/null @@ -1,136 +0,0 @@ -import Video from "@appquality/stream-player"; -import styled from "styled-components"; -import { VideoControls } from "./VideoControls"; -import { useCallback, useEffect, useRef, useState } from "react"; - -const PlayerWrapper = styled.div<{ - isFullScreen?: boolean; - isLoading?: boolean; -}>` - position: relative; - background-color: black; - - video { - width: 100%; - max-height: 200px; - } - - ${({ isFullScreen }) => - isFullScreen && - ` - video { - position: absolute; - top: 0; - left: 0; - bottom: 0; - display: block; - margin: 0 auto; - max-height: 100%; - } - `} - - ${({ isLoading }) => - isLoading && - ` - background: #eee; - background: linear-gradient(110deg, #ececec 8%, #f5f5f5 18%, #ececec 33%); - background-size: 200% 100%; - animation: 1.5s shine linear infinite; - @keyframes shine { - to { - background-position-x: -200%; - } - } - `} -`; - -interface ElementWithFullscreen extends HTMLDivElement { - webkitEnterFullscreen?: () => Promise; - webkitRequestFullscreen?: () => Promise; - mozRequestFullScreen?: () => Promise; - msRequestFullscreen?: () => Promise; -} - -const VideoPlayer = ({ - videoFieldName, - title, -}: { - videoFieldName: string; - title?: string; -}) => { - const [isFullScreen, setFullScreen] = useState(false); - const [isLoading, setIsLoading] = useState(true); - const playerRef = useRef(null); - - const handleFullScreen = useCallback(async () => { - if (playerRef) { - const ref = playerRef.current as ElementWithFullscreen; - if (!isFullScreen || !document.fullscreenElement) { - setFullScreen(true); - if (ref.requestFullscreen) { - await ref.requestFullscreen(); - } else if (ref.webkitRequestFullscreen) { - await ref.webkitRequestFullscreen(); - } else if (ref.mozRequestFullScreen) { - await ref.mozRequestFullScreen(); - } else if (ref.webkitEnterFullscreen) { - // iOS - await ref.webkitEnterFullscreen(); - } else if (ref.msRequestFullscreen) { - await ref.msRequestFullscreen(); - } else { - console.error("Fullscreen API is not supported"); - setFullScreen(false); - } - } else { - if (document.fullscreenElement) { - await document.exitFullscreen(); - } - setFullScreen(false); - } - } - }, [playerRef, isFullScreen]); - - useEffect(() => { - if (playerRef && playerRef.current) { - playerRef.current.addEventListener("fullscreenchange", () => { - setFullScreen(!!document.fullscreenElement); - }); - } - - return () => { - if (playerRef && playerRef.current) { - playerRef.current.removeEventListener("fullscreenchange", () => { - setFullScreen(!!document.fullscreenElement); - }); - } - }; - }, [playerRef]); - - useEffect(() => { - playerRef.current - ?.querySelector("video") - ?.addEventListener("loadeddata", () => { - setIsLoading(false); - }); - }, []); - return ( - - - {!isLoading && ( - - )} - - ); -}; - -export default VideoPlayer; diff --git a/src/pages/UxDashboard/UxForm/VideoParts/index.tsx b/src/pages/UxDashboard/UxForm/VideoParts/index.tsx deleted file mode 100644 index aa61dc81..00000000 --- a/src/pages/UxDashboard/UxForm/VideoParts/index.tsx +++ /dev/null @@ -1,147 +0,0 @@ -import { Card, Select, Title } from "@appquality/appquality-design-system"; -import Video from "@appquality/stream-player"; -import { FieldArray, useFormikContext } from "formik"; -import { useMemo } from "react"; -import { OnDragEndResponder } from "react-beautiful-dnd"; -import { Plus } from "react-bootstrap-icons"; -import { useParams } from "react-router-dom"; -import { - GetCampaignsByCampaignObservationsApiResponse, - useGetCampaignsByCampaignObservationsQuery, -} from "src/services/tryberApi"; -import { useAppSelector } from "src/store"; -import styled from "styled-components"; -import { v4 as uuidv4 } from "uuid"; -import DragNDropProvider from "../DragNDropProvider"; -import { FormValuesInterface, FormVideoPart } from "../FormProvider"; -import VideoPart from "./VideoPart"; - -export type VideoPartsOption = SelectOptionType & - GetCampaignsByCampaignObservationsApiResponse["items"][number]; - -type NewInsightVideopart = Pick< - FormVideoPart, - "internalId" | "mediaId" | "start" | "url" | "streamUrl" | "description" ->; - -const StyledAddNewEvidence = styled.div` - display: grid; - grid-template-columns: 165px 1fr; - grid-template-rows: 1fr; - gap: ${({ theme }) => theme.grid.spacing.default}; -`; - -const PlusContainer = styled.div` - @media (min-width: ${({ theme }) => theme.grid.breakpoints.lg}) { - display: flex; - align-items: center; - justify-content: center; - background-color: ${({ theme }) => theme.colors.gray50}; - } -`; - -const VideoParts = () => { - const { id } = useParams<{ id: string }>(); - const { data } = useGetCampaignsByCampaignObservationsQuery({ campaign: id }); - const { insightIndex } = useAppSelector((state) => state.uxDashboard); - const formikContext = useFormikContext(); - const { values } = formikContext; - const fieldName = `insights[${insightIndex}].videoParts`; - const videoParts = values.insights[insightIndex].videoParts; - - const observationsOptions: VideoPartsOption[] = useMemo( - () => - data?.items.map((observation) => ({ - label: - observation.name + - " - " + - observation.tester.name + - " - " + - observation.cluster?.name, - value: observation.id.toString(), - ...observation, - })) || [], - [data] - ); - - return ( -
- - {({ remove, push, move }) => { - const handleDragEnd: OnDragEndResponder = (result) => { - if (!result.destination) { - return; - } - move(result.source.index, result.destination.index); - formikContext.setFieldTouched(fieldName, false); - }; - return ( - <> - - onDragEnd={handleDragEnd} - items={videoParts} - renderItem={(videopart, index, dragHandleProps) => ( - - )} - /> - - - - - -
- - Aggiungi una nuova evidenza - - { - if (value.length === 0) { - form.setFieldValue(field.name, []); - } - if (value.length > 0) { - if ( - value.find( - (v: SelectOptionType) => v.value === clusterOptionGeneral.value - ) - ) { - form.setFieldValue(field.name, clusterOptionGeneral.value); - } else { - form.setFieldValue( - field.name, - value.map((item: SelectOptionType) => { - return item.value - ? { id: parseInt(item.value, 10), name: item.label } - : undefined; - }) - ); - } - return; - } - }} - /> - - - ); -}; - -export default ClusterField; diff --git a/src/pages/UxDashboard/UxForm/components/fields/SeverityField.tsx b/src/pages/UxDashboard/UxForm/components/fields/SeverityField.tsx deleted file mode 100644 index fb5e938b..00000000 --- a/src/pages/UxDashboard/UxForm/components/fields/SeverityField.tsx +++ /dev/null @@ -1,63 +0,0 @@ -import { - ErrorMessage, - FieldProps, - FormGroup, - Select, -} from "@appquality/appquality-design-system"; -import { useMemo } from "react"; -import { FormInsight } from "../../FormProvider"; - -export const severityOptions = [ - { - label: "Minor", - value: "1", - }, - { - label: "Major", - value: "2", - }, - { - label: "Positive", - value: "3", - }, - { - label: "Observation", - value: "4", - }, -]; - -const SeverityField = ({ - form, - field, -}: FieldProps) => { - const mapSeverityToSelectValue = useMemo(() => { - return typeof field.value === "object" && field.value !== null - ? { label: field.value.name, value: field.value.id.toString() } - : { label: "" }; - }, [field.value]); - return ( - -