Make directors and photographers clickable in detail view (#4621)

* Make directors and photographers clickable
* Make director clickable on movie details page
---------
Co-authored-by: WithoutPants <53250216+WithoutPants@users.noreply.github.com>
This commit is contained in:
bdbenim
2024-03-13 16:34:24 -07:00
committed by GitHub
parent 3d0a8f653a
commit 49cd214c9d
6 changed files with 120 additions and 4 deletions

View File

@@ -9,6 +9,7 @@ import { PerformerCard } from "src/components/Performers/PerformerCard";
import { RatingSystem } from "src/components/Shared/Rating/RatingSystem";
import { sortPerformers } from "src/core/performers";
import { galleryTitle } from "src/core/galleries";
import { PhotographerLink } from "src/components/Shared/Link";
interface IGalleryDetailProps {
gallery: GQL.GalleryDataFragment;
@@ -118,7 +119,11 @@ export const GalleryDetailPanel: React.FC<IGalleryDetailProps> = ({
)}
{gallery.photographer && (
<h6>
<FormattedMessage id="photographer" />: {gallery.photographer}{" "}
<FormattedMessage id="photographer" />:{" "}
<PhotographerLink
photographer={gallery.photographer}
linkType="gallery"
/>
</h6>
)}
</div>

View File

@@ -9,6 +9,7 @@ import { RatingSystem } from "src/components/Shared/Rating/RatingSystem";
import { sortPerformers } from "src/core/performers";
import { FormattedDate, FormattedMessage, useIntl } from "react-intl";
import { objectTitle } from "src/core/files";
import { PhotographerLink } from "src/components/Shared/Link";
interface IImageDetailProps {
image: GQL.ImageDataFragment;
}
@@ -154,7 +155,11 @@ export const ImageDetailPanel: React.FC<IImageDetailProps> = (props) => {
)}
{props.image.photographer && (
<h6>
<FormattedMessage id="photographer" />: {props.image.photographer}{" "}
<FormattedMessage id="photographer" />:{" "}
<PhotographerLink
photographer={props.image.photographer}
linkType="image"
/>
</h6>
)}
</div>

View File

@@ -4,6 +4,7 @@ import * as GQL from "src/core/generated-graphql";
import TextUtils from "src/utils/text";
import { DetailItem } from "src/components/Shared/DetailItem";
import { Link } from "react-router-dom";
import { DirectorLink } from "src/components/Shared/Link";
interface IMovieDetailsPanel {
movie: GQL.MovieDataFragment;
@@ -45,7 +46,17 @@ export const MovieDetailsPanel: React.FC<IMovieDetailsPanel> = ({
fullWidth={fullWidth}
/>
<DetailItem id="director" value={movie.director} fullWidth={fullWidth} />
<DetailItem
id="director"
value={
movie.director ? (
<DirectorLink director={movie.director} linkType="movie" />
) : (
""
)
}
fullWidth={fullWidth}
/>
<DetailItem id="synopsis" value={movie.synopsis} fullWidth={fullWidth} />
</div>
);

View File

@@ -9,6 +9,7 @@ import { PerformerCard } from "src/components/Performers/PerformerCard";
import { sortPerformers } from "src/core/performers";
import { RatingSystem } from "src/components/Shared/Rating/RatingSystem";
import { objectTitle } from "src/core/files";
import { DirectorLink } from "src/components/Shared/Link";
interface ISceneDetailProps {
scene: GQL.SceneDataFragment;
@@ -128,7 +129,8 @@ export const SceneDetailPanel: React.FC<ISceneDetailProps> = (props) => {
)}
{props.scene.director && (
<h6>
<FormattedMessage id="director" />: {props.scene.director}{" "}
<FormattedMessage id="director" />:{" "}
<DirectorLink director={props.scene.director} linkType="scene" />
</h6>
)}
</div>

View File

@@ -0,0 +1,37 @@
import { useMemo } from "react";
import { Link } from "react-router-dom";
import NavUtils from "src/utils/navigation";
// common link components
export const DirectorLink: React.FC<{
director: string;
linkType: "scene" | "movie";
}> = ({ director: director, linkType = "scene" }) => {
const link = useMemo(() => {
switch (linkType) {
case "scene":
return NavUtils.makeDirectorScenesUrl(director);
case "movie":
return NavUtils.makeDirectorMoviesUrl(director);
}
}, [director, linkType]);
return <Link to={link}>{director}</Link>;
};
export const PhotographerLink: React.FC<{
photographer: string;
linkType: "gallery" | "image";
}> = ({ photographer, linkType = "image" }) => {
const link = useMemo(() => {
switch (linkType) {
case "gallery":
return NavUtils.makePhotographerGalleriesUrl(photographer);
case "image":
return NavUtils.makePhotographerImagesUrl(photographer);
}
}, [photographer, linkType]);
return <Link to={link}>{photographer}</Link>;
};

View File

@@ -15,7 +15,10 @@ import { ListFilterModel } from "src/models/list-filter/filter";
import { MoviesCriterion } from "src/models/list-filter/criteria/movies";
import {
Criterion,
CriterionOption,
CriterionValue,
StringCriterion,
createStringCriterionOption,
} from "src/models/list-filter/criteria/criterion";
import { GalleriesCriterion } from "src/models/list-filter/criteria/galleries";
import { PhashCriterion } from "src/models/list-filter/criteria/phash";
@@ -355,6 +358,55 @@ const makeGalleryImagesUrl = (
return `/images?${filter.makeQueryParameters()}`;
};
function stringEqualsCriterion(option: CriterionOption, value: string) {
const criterion = new StringCriterion(option);
criterion.modifier = GQL.CriterionModifier.Equals;
criterion.value = value;
return criterion;
}
const makeDirectorScenesUrl = (director: string) => {
if (director.length == 0) return "#";
const filter = new ListFilterModel(GQL.FilterMode.Scenes, undefined);
filter.criteria.push(
stringEqualsCriterion(createStringCriterionOption("director"), director)
);
return `/scenes?${filter.makeQueryParameters()}`;
};
const makeDirectorMoviesUrl = (director: string) => {
if (director.length == 0) return "#";
const filter = new ListFilterModel(GQL.FilterMode.Movies, undefined);
filter.criteria.push(
stringEqualsCriterion(createStringCriterionOption("director"), director)
);
return `/movies?${filter.makeQueryParameters()}`;
};
const makePhotographerGalleriesUrl = (photographer: string) => {
if (photographer.length == 0) return "#";
const filter = new ListFilterModel(GQL.FilterMode.Galleries, undefined);
filter.criteria.push(
stringEqualsCriterion(
createStringCriterionOption("photographer"),
photographer
)
);
return `/galleries?${filter.makeQueryParameters()}`;
};
const makePhotographerImagesUrl = (photographer: string) => {
if (photographer.length == 0) return "#";
const filter = new ListFilterModel(GQL.FilterMode.Images, undefined);
filter.criteria.push(
stringEqualsCriterion(
createStringCriterionOption("photographer"),
photographer
)
);
return `/images?${filter.makeQueryParameters()}`;
};
export function handleUnsavedChanges(
intl: IntlShape,
basepath: string,
@@ -394,6 +446,10 @@ const NavUtils = {
makeMovieScenesUrl,
makeChildStudiosUrl,
makeGalleryImagesUrl,
makeDirectorScenesUrl,
makePhotographerGalleriesUrl,
makePhotographerImagesUrl,
makeDirectorMoviesUrl,
};
export default NavUtils;