diff --git a/ui/v2.5/src/components/List/AddFilterDialog.tsx b/ui/v2.5/src/components/List/AddFilterDialog.tsx index 871214853..bad1a9dd9 100644 --- a/ui/v2.5/src/components/List/AddFilterDialog.tsx +++ b/ui/v2.5/src/components/List/AddFilterDialog.tsx @@ -216,11 +216,7 @@ export const AddFilterDialog: React.FC = ({ } if (criterion instanceof RatingCriterion) { return ( - + ); } if ( @@ -307,12 +303,32 @@ export const AddFilterDialog: React.FC = ({ ); } + function isValid() { + if (criterion.criterionOption.type === "none") { + return false; + } + + if (criterion instanceof RatingCriterion) { + switch (criterion.modifier) { + case CriterionModifier.Equals: + case CriterionModifier.NotEquals: + case CriterionModifier.LessThan: + return !!criterion.value.value; + case CriterionModifier.Between: + case CriterionModifier.NotBetween: + return criterion.value.value < (criterion.value.value2 ?? 0); + } + } + + return true; + } + const title = !editingCriterion ? intl.formatMessage({ id: "search_filter.add_filter" }) : intl.formatMessage({ id: "search_filter.update_filter" }); return ( <> - onCancel()}> + onCancel()} className="add-filter-dialog"> {title}
@@ -322,10 +338,7 @@ export const AddFilterDialog: React.FC = ({
- diff --git a/ui/v2.5/src/components/List/Filters/RatingFilter.tsx b/ui/v2.5/src/components/List/Filters/RatingFilter.tsx index ba9a217c9..73bc7b402 100644 --- a/ui/v2.5/src/components/List/Filters/RatingFilter.tsx +++ b/ui/v2.5/src/components/List/Filters/RatingFilter.tsx @@ -1,135 +1,61 @@ -import React, { useRef } from "react"; -import { Form } from "react-bootstrap"; -import { useIntl } from "react-intl"; +import React from "react"; +import { FormattedMessage } from "react-intl"; import { CriterionModifier } from "../../../core/generated-graphql"; import { INumberValue } from "../../../models/list-filter/types"; import { Criterion } from "../../../models/list-filter/criteria/criterion"; -import { - convertFromRatingFormat, - convertToRatingFormat, - defaultRatingSystemOptions, -} from "src/utils/rating"; -import * as GQL from "src/core/generated-graphql"; -import { IUIConfig } from "src/core/config"; +import { RatingSystem } from "src/components/Shared/Rating/RatingSystem"; -interface IDurationFilterProps { +interface IRatingFilterProps { criterion: Criterion; onValueChanged: (value: INumberValue) => void; - configuration: GQL.ConfigDataFragment | undefined; } -export const RatingFilter: React.FC = ({ +export const RatingFilter: React.FC = ({ criterion, onValueChanged, - configuration, }) => { - const intl = useIntl(); - const ratingSystem = - (configuration?.ui as IUIConfig)?.ratingSystemOptions ?? - defaultRatingSystemOptions; + function getRatingSystem(field: "value" | "value2") { + const defaultValue = field === "value" ? 0 : undefined; - const valueStage = useRef(criterion.value); - - function onChanged( - event: React.ChangeEvent, - property: "value" | "value2" - ) { - const value = parseInt(event.target.value, 10); - valueStage.current[property] = !Number.isNaN(value) - ? convertFromRatingFormat(value, ratingSystem.type) - : 0; + return ( +
+ { + onValueChanged({ + ...criterion.value, + [field]: value ?? defaultValue, + }); + }} + valueRequired + /> +
+ ); } - function onBlurInput() { - onValueChanged(valueStage.current); - } - - let equalsControl: JSX.Element | null = null; if ( criterion.modifier === CriterionModifier.Equals || - criterion.modifier === CriterionModifier.NotEquals - ) { - equalsControl = ( - - ) => - onChanged(e, "value") - } - onBlur={onBlurInput} - defaultValue={ - convertToRatingFormat(criterion.value?.value, ratingSystem) ?? "" - } - placeholder={intl.formatMessage({ id: "criterion.value" })} - /> - - ); - } - - let lowerControl: JSX.Element | null = null; - if ( + criterion.modifier === CriterionModifier.NotEquals || criterion.modifier === CriterionModifier.GreaterThan || - criterion.modifier === CriterionModifier.Between || - criterion.modifier === CriterionModifier.NotBetween + criterion.modifier === CriterionModifier.LessThan ) { - lowerControl = ( - - ) => - onChanged(e, "value") - } - onBlur={onBlurInput} - defaultValue={ - convertToRatingFormat(criterion.value?.value, ratingSystem) ?? "" - } - placeholder={intl.formatMessage({ id: "criterion.greater_than" })} - /> - - ); + return getRatingSystem("value"); } - let upperControl: JSX.Element | null = null; if ( - criterion.modifier === CriterionModifier.LessThan || criterion.modifier === CriterionModifier.Between || criterion.modifier === CriterionModifier.NotBetween ) { - upperControl = ( - - ) => - onChanged( - e, - criterion.modifier === CriterionModifier.LessThan - ? "value" - : "value2" - ) - } - onBlur={onBlurInput} - defaultValue={ - convertToRatingFormat( - criterion.modifier === CriterionModifier.LessThan - ? criterion.value?.value - : criterion.value?.value2, - ratingSystem - ) ?? "" - } - placeholder={intl.formatMessage({ id: "criterion.less_than" })} - /> - + return ( +
+ {getRatingSystem("value")} + + + + {getRatingSystem("value2")} +
); } - return ( - <> - {equalsControl} - {lowerControl} - {upperControl} - - ); + return <>; }; diff --git a/ui/v2.5/src/components/List/styles.scss b/ui/v2.5/src/components/List/styles.scss index 4c494c017..99933638b 100644 --- a/ui/v2.5/src/components/List/styles.scss +++ b/ui/v2.5/src/components/List/styles.scss @@ -107,3 +107,12 @@ input[type="range"].zoom-slider { } } } + +.add-filter-dialog .rating-stars { + font-size: 1.3em; + margin-left: 0.25em; +} + +.rating-filter .and-divider { + margin-left: 0.5em; +} diff --git a/ui/v2.5/src/components/Performers/styles.scss b/ui/v2.5/src/components/Performers/styles.scss index 57ebdc046..a0e913aea 100644 --- a/ui/v2.5/src/components/Performers/styles.scss +++ b/ui/v2.5/src/components/Performers/styles.scss @@ -41,6 +41,10 @@ } } } + + .rating-number .form-control { + width: inherit; + } } .alias { diff --git a/ui/v2.5/src/components/Shared/Rating/RatingStars.tsx b/ui/v2.5/src/components/Shared/Rating/RatingStars.tsx index 594d84c69..e2801ee80 100644 --- a/ui/v2.5/src/components/Shared/Rating/RatingStars.tsx +++ b/ui/v2.5/src/components/Shared/Rating/RatingStars.tsx @@ -17,6 +17,7 @@ export interface IRatingStarsProps { onSetRating?: (value?: number) => void; disabled?: boolean; precision: RatingStarPrecision; + valueRequired?: boolean; } export const RatingStars: React.FC = ( @@ -62,7 +63,15 @@ export const RatingStars: React.FC = ( ) { const f = newToggleFraction(); if (!f) { - newRating = undefined; + if (props.valueRequired) { + if (fraction) { + newRating = stars + 1; + } else { + newRating = stars; + } + } else { + newRating = undefined; + } } else if (fraction) { // we're toggling from an existing fraction so use the stars value newRating = stars + f; @@ -143,10 +152,17 @@ export const RatingStars: React.FC = ( if (hoverRating) { if (hoverRating === stars && precision === 1) { + if (props.valueRequired) { + return { rating: r, fraction: 0 }; + } + // unsetting return undefined; } if (hoverRating === stars + 1 && fraction && fraction === precision) { + if (props.valueRequired) { + return { rating: r, fraction: 0 }; + } // unsetting return undefined; } diff --git a/ui/v2.5/src/components/Shared/Rating/RatingSystem.tsx b/ui/v2.5/src/components/Shared/Rating/RatingSystem.tsx index 4bfc6004c..61e7c21dc 100644 --- a/ui/v2.5/src/components/Shared/Rating/RatingSystem.tsx +++ b/ui/v2.5/src/components/Shared/Rating/RatingSystem.tsx @@ -13,6 +13,7 @@ export interface IRatingSystemProps { value?: number; onSetRating?: (value?: number) => void; disabled?: boolean; + valueRequired?: boolean; } export const RatingSystem: React.FC = ( @@ -32,6 +33,7 @@ export const RatingSystem: React.FC = ( precision={ ratingSystemOptions.starPrecision ?? defaultRatingStarPrecision } + valueRequired={props.valueRequired} /> ); } diff --git a/ui/v2.5/src/locales/en-GB.json b/ui/v2.5/src/locales/en-GB.json index 1e9a23f1a..5e222fb70 100644 --- a/ui/v2.5/src/locales/en-GB.json +++ b/ui/v2.5/src/locales/en-GB.json @@ -127,6 +127,7 @@ "birth_year": "Birth Year", "birthdate": "Birthdate", "bitrate": "Bit Rate", + "between_and": "and", "captions": "Captions", "career_length": "Career Length", "component_tagger": { diff --git a/ui/v2.5/src/models/list-filter/criteria/criterion.ts b/ui/v2.5/src/models/list-filter/criteria/criterion.ts index a11027851..60d245f62 100644 --- a/ui/v2.5/src/models/list-filter/criteria/criterion.ts +++ b/ui/v2.5/src/models/list-filter/criteria/criterion.ts @@ -342,7 +342,7 @@ export class NullNumberCriterionOption extends CriterionOption { CriterionModifier.IsNull, CriterionModifier.NotNull, ], - defaultModifier: CriterionModifier.GreaterThan, + defaultModifier: CriterionModifier.Equals, inputType: "number", }); } diff --git a/ui/v2.5/src/models/list-filter/criteria/rating.ts b/ui/v2.5/src/models/list-filter/criteria/rating.ts index 049a173dd..ffacdaf3f 100644 --- a/ui/v2.5/src/models/list-filter/criteria/rating.ts +++ b/ui/v2.5/src/models/list-filter/criteria/rating.ts @@ -42,11 +42,11 @@ export class RatingCriterion extends Criterion { this.modifier === CriterionModifier.Between || this.modifier === CriterionModifier.NotBetween ) { - return `${convertToRatingFormat(value, this.ratingSystem)}, ${ + return `${convertToRatingFormat(value, this.ratingSystem) ?? 0}, ${ convertToRatingFormat(value2, this.ratingSystem) ?? 0 }`; } else { - return `${convertToRatingFormat(value, this.ratingSystem)}`; + return `${convertToRatingFormat(value, this.ratingSystem) ?? 0}`; } }