// Copyright (C) 2020 Intel Corporation // // SPDX-License-Identifier: MIT import React, { useState, useEffect } from 'react'; import { AnyAction } from 'redux'; import { useSelector, useDispatch } from 'react-redux'; import Text from 'antd/lib/typography/Text'; import Title from 'antd/lib/typography/Title'; import Modal from 'antd/lib/modal'; import Radio, { RadioChangeEvent } from 'antd/lib/radio'; import RadioButton from 'antd/lib/radio/radioButton'; import Description from 'antd/lib/descriptions'; import Rate from 'antd/lib/rate'; import { Row, Col } from 'antd/lib/grid'; import UserSelector, { User } from 'components/task-page/user-selector'; import { CombinedState, ReviewStatus } from 'reducers/interfaces'; import { switchSubmitReviewDialog } from 'actions/annotation-actions'; import { submitReviewAsync } from 'actions/review-actions'; import { clamp } from 'utils/math'; import { useHistory } from 'react-router'; function computeEstimatedQuality(reviewedStates: number, openedIssues: number): number { if (reviewedStates === 0 && openedIssues === 0) { return 5; // corner case } const K = 2; // means how many reviewed states are equivalent to one issue const quality = reviewedStates / (reviewedStates + K * openedIssues); return clamp(+(5 * quality).toPrecision(2), 0, 5); } export default function SubmitReviewModal(): JSX.Element | null { const dispatch = useDispatch(); const history = useHistory(); const isVisible = useSelector((state: CombinedState): boolean => state.annotation.submitReviewDialogVisible); const job = useSelector((state: CombinedState): any => state.annotation.job.instance); const activeReview = useSelector((state: CombinedState): any => state.review.activeReview); const reviewIsBeingSubmitted = useSelector((state: CombinedState): any => state.review.fetching.reviewId); const numberOfIssues = useSelector((state: CombinedState): any => state.review.issues.length); const [isSubmitting, setIsSubmitting] = useState(false); const numberOfNewIssues = activeReview ? activeReview.issues.length : 0; const reviewedFrames = activeReview ? activeReview.reviewedFrames.length : 0; const reviewedStates = activeReview ? activeReview.reviewedStates.length : 0; const [reviewer, setReviewer] = useState(job.reviewer ? job.reviewer : null); const [reviewStatus, setReviewStatus] = useState(ReviewStatus.ACCEPTED); const [estimatedQuality, setEstimatedQuality] = useState(0); const close = (): AnyAction => dispatch(switchSubmitReviewDialog(false)); const submitReview = (): void => { activeReview.estimatedQuality = estimatedQuality; activeReview.status = reviewStatus; if (reviewStatus === ReviewStatus.REVIEW_FURTHER) { activeReview.reviewer = reviewer; } dispatch(submitReviewAsync(activeReview)); }; useEffect(() => { setEstimatedQuality(computeEstimatedQuality(reviewedStates, numberOfNewIssues)); }, [reviewedStates, numberOfNewIssues]); useEffect(() => { if (!isSubmitting && activeReview && activeReview.id === reviewIsBeingSubmitted) { setIsSubmitting(true); } else if (isSubmitting && reviewIsBeingSubmitted === null) { setIsSubmitting(false); close(); history.push(`/tasks/${job.task.id}`); } }, [reviewIsBeingSubmitted, activeReview]); if (!isVisible) { return null; } return ( Submitting your review {estimatedQuality} {numberOfIssues} {!!numberOfNewIssues && {` (+${numberOfNewIssues})`}} {reviewedFrames} {reviewedStates} { if (typeof event.target.value !== 'undefined') { setReviewStatus(event.target.value); } }} > Accept Review next Reject {reviewStatus === ReviewStatus.REVIEW_FURTHER && ( Reviewer: )} { if (typeof value !== 'undefined') { setEstimatedQuality(value); } }} /> ); }