import Button from '@app/components/Common/Button'; import SlideCheckbox from '@app/components/Common/SlideCheckbox'; import Tag from '@app/components/Common/Tag'; import Tooltip from '@app/components/Common/Tooltip'; import CompanyTag from '@app/components/CompanyTag'; import { sliderTitles } from '@app/components/Discover/constants'; import CreateSlider from '@app/components/Discover/CreateSlider'; import GenreTag from '@app/components/GenreTag'; import KeywordTag from '@app/components/KeywordTag'; import globalMessages from '@app/i18n/globalMessages'; import { MagnifyingGlassIcon } from '@heroicons/react/24/outline'; import { ArrowUturnLeftIcon, Bars3Icon, ChevronDownIcon, ChevronUpIcon, PencilIcon, XMarkIcon, } from '@heroicons/react/24/solid'; import { DiscoverSliderType } from '@server/constants/discover'; import type DiscoverSlider from '@server/entity/DiscoverSlider'; import axios from 'axios'; import { useRef, useState } from 'react'; import { useDrag, useDrop } from 'react-aria'; import { defineMessages, useIntl } from 'react-intl'; import { useToasts } from 'react-toast-notifications'; const messages = defineMessages({ deletesuccess: 'Sucessfully deleted slider.', deletefail: 'Failed to delete slider.', remove: 'Remove', enable: 'Toggle Visibility', }); const Position = { None: 'None', Above: 'Above', Below: 'Below', } as const; type DiscoverSliderEditProps = { slider: Partial; onEnable: () => void; onDelete: () => void; onPositionUpdate: ( updatedItemId: number, position: keyof typeof Position, isClickable: boolean ) => void; children: React.ReactNode; disableUpButton: boolean; disableDownButton: boolean; }; const DiscoverSliderEdit = ({ slider, children, onEnable, onDelete, onPositionUpdate, disableUpButton, disableDownButton, }: DiscoverSliderEditProps) => { const intl = useIntl(); const { addToast } = useToasts(); const [isEditing, setIsEditing] = useState(false); const ref = useRef(null); const [hoverPosition, setHoverPosition] = useState( Position.None ); const { dragProps, isDragging } = useDrag({ getItems() { return [{ id: (slider.id ?? -1).toString(), title: slider.title ?? '' }]; }, }); const deleteSlider = async () => { try { await axios.delete(`/api/v1/settings/discover/${slider.id}`); addToast(intl.formatMessage(messages.deletesuccess), { appearance: 'success', autoDismiss: true, }); onDelete(); } catch (e) { addToast(intl.formatMessage(messages.deletefail), { appearance: 'error', autoDismiss: true, }); } }; const { dropProps } = useDrop({ ref, onDropMove: (e) => { if (ref.current) { const middlePoint = ref.current.offsetHeight / 2; if (e.y < middlePoint) { setHoverPosition(Position.Above); } else { setHoverPosition(Position.Below); } } }, onDropExit: () => { setHoverPosition(Position.None); }, onDrop: async (e) => { const items = await Promise.all( e.items .filter((item) => item.kind === 'text' && item.types.has('id')) .map(async (item) => { if (item.kind === 'text') { return item.getText('id'); } }) ); if (items?.[0]) { const dropped = Number(items[0]); onPositionUpdate(dropped, hoverPosition, false); } }, }); const getSliderTitle = (slider: Partial): string => { switch (slider.type) { case DiscoverSliderType.RECENTLY_ADDED: return intl.formatMessage(sliderTitles.recentlyAdded); case DiscoverSliderType.RECENT_REQUESTS: return intl.formatMessage(sliderTitles.recentrequests); case DiscoverSliderType.PLEX_WATCHLIST: return intl.formatMessage(sliderTitles.plexwatchlist); case DiscoverSliderType.TRENDING: return intl.formatMessage(sliderTitles.trending); case DiscoverSliderType.POPULAR_MOVIES: return intl.formatMessage(sliderTitles.popularmovies); case DiscoverSliderType.MOVIE_GENRES: return intl.formatMessage(sliderTitles.moviegenres); case DiscoverSliderType.UPCOMING_MOVIES: return intl.formatMessage(sliderTitles.upcoming); case DiscoverSliderType.STUDIOS: return intl.formatMessage(sliderTitles.studios); case DiscoverSliderType.POPULAR_TV: return intl.formatMessage(sliderTitles.populartv); case DiscoverSliderType.TV_GENRES: return intl.formatMessage(sliderTitles.tvgenres); case DiscoverSliderType.UPCOMING_TV: return intl.formatMessage(sliderTitles.upcomingtv); case DiscoverSliderType.NETWORKS: return intl.formatMessage(sliderTitles.networks); case DiscoverSliderType.TMDB_MOVIE_KEYWORD: return intl.formatMessage(sliderTitles.tmdbmoviekeyword); case DiscoverSliderType.TMDB_TV_KEYWORD: return intl.formatMessage(sliderTitles.tmdbtvkeyword); case DiscoverSliderType.TMDB_MOVIE_GENRE: return intl.formatMessage(sliderTitles.tmdbmoviegenre); case DiscoverSliderType.TMDB_TV_GENRE: return intl.formatMessage(sliderTitles.tmdbtvgenre); case DiscoverSliderType.TMDB_STUDIO: return intl.formatMessage(sliderTitles.tmdbstudio); case DiscoverSliderType.TMDB_NETWORK: return intl.formatMessage(sliderTitles.tmdbnetwork); case DiscoverSliderType.TMDB_SEARCH: return intl.formatMessage(sliderTitles.tmdbsearch); case DiscoverSliderType.TMDB_MOVIE_STREAMING_SERVICES: return intl.formatMessage(sliderTitles.tmdbmoviestreamingservices); case DiscoverSliderType.TMDB_TV_STREAMING_SERVICES: return intl.formatMessage(sliderTitles.tmdbtvstreamingservices); default: return 'Unknown Slider'; } }; return (
{hoverPosition === Position.Above && (
)} {hoverPosition === Position.Below && (
)}
{getSliderTitle(slider)}
{(slider.type === DiscoverSliderType.TMDB_MOVIE_KEYWORD || slider.type === DiscoverSliderType.TMDB_TV_KEYWORD) && (
{slider.data?.split(',').map((keywordId) => ( ))}
)} {(slider.type === DiscoverSliderType.TMDB_NETWORK || slider.type === DiscoverSliderType.TMDB_STUDIO) && ( )} {(slider.type === DiscoverSliderType.TMDB_TV_GENRE || slider.type === DiscoverSliderType.TMDB_MOVIE_GENRE) && ( )} {slider.type === DiscoverSliderType.TMDB_SEARCH && ( }>{slider.data} )}
{!slider.isBuiltIn && ( <> {!isEditing ? ( ) : ( )} )}
{ onEnable(); }} checked={slider.enabled} />
{isEditing ? (
{ onDelete(); setIsEditing(false); }} slider={slider} />
) : (
{children}
)}
); }; export default DiscoverSliderEdit;