Enhancement : Decouple the UI by using conditional rendering for each module

This commit is contained in:
Aj - Thomas
2022-05-08 20:54:40 +02:00
parent 5f58f84843
commit 4452b088c8
8 changed files with 24 additions and 5 deletions

View File

@@ -0,0 +1,7 @@
import CalendarComponent from './CalendarModule';
export default {
title: 'Calendar component',
};
export const Default = (args: any) => <CalendarComponent {...args} />;

View File

@@ -0,0 +1,115 @@
/* eslint-disable react/no-children-prop */
import { Popover, Box, ScrollArea, Divider, Indicator } from '@mantine/core';
import { useEffect, useState } from 'react';
import { Calendar } from '@mantine/dates';
import { RadarrMediaDisplay, SonarrMediaDisplay } from './MediaDisplay';
import { useConfig } from '../../../tools/state';
import { CalendarIcon } from '@modulz/radix-icons';
import { MHPModule } from '../modules';
export const CalendarModule: MHPModule = {
title: 'Calendar',
description: 'A calendar module for displaying upcoming releases. It interacts with the Sonarr and Radarr API.',
icon: CalendarIcon,
component: CalendarComponent,
};
export default function CalendarComponent(props: any) {
const { config } = useConfig();
const [sonarrMedias, setSonarrMedias] = useState([] as any);
const [radarrMedias, setRadarrMedias] = useState([] as any);
useEffect(() => {
// Filter only sonarr and radarr services
const filtered = config.services.filter(
(service) => service.type === 'Sonarr' || service.type === 'Radarr'
);
// Get the url and apiKey for all Sonarr and Radarr services
const sonarrService = filtered.filter((service) => service.type === 'Sonarr').at(0);
const radarrService = filtered.filter((service) => service.type === 'Radarr').at(0);
const nextMonth = new Date(new Date().setMonth(new Date().getMonth() + 2)).toISOString();
if (sonarrService && sonarrService.apiKey) {
fetch(
`${sonarrService?.url}api/calendar?apikey=${sonarrService?.apiKey}&end=${nextMonth}`
).then((response) => {
response.ok && response.json().then((data) => setSonarrMedias(data));
});
}
if (radarrService && radarrService.apiKey) {
fetch(
`${radarrService?.url}api/v3/calendar?apikey=${radarrService?.apiKey}&end=${nextMonth}`
).then((response) => {
response.ok && response.json().then((data) => setRadarrMedias(data));
});
}
}, [config.services]);
if (sonarrMedias === undefined && radarrMedias === undefined) {
return <Calendar />;
}
return (
<Calendar
onChange={(day: any) => {}}
renderDay={(renderdate) => (
<DayComponent
renderdate={renderdate}
sonarrmedias={sonarrMedias}
radarrmedias={radarrMedias}
/>
)}
/>
);
}
function DayComponent(props: any) {
const {
renderdate,
sonarrmedias,
radarrmedias,
}: { renderdate: Date; sonarrmedias: []; radarrmedias: [] } = props;
const [opened, setOpened] = useState(false);
const day = renderdate.getDate();
// Itterate over the medias and filter the ones that are on the same day
const sonarrFiltered = sonarrmedias.filter((media: any) => {
const date = new Date(media.airDate);
// Return true if the date is renerdate without counting hours and minutes
return date.getDate() === day && date.getMonth() === renderdate.getMonth();
});
const radarrFiltered = radarrmedias.filter((media: any) => {
const date = new Date(media.inCinemas);
// Return true if the date is renerdate without counting hours and minutes
return date.getDate() === day && date.getMonth() === renderdate.getMonth();
});
if (sonarrFiltered.length === 0 && radarrFiltered.length === 0) {
return <div>{day}</div>;
}
return (
<Box
onClick={() => {
setOpened(true);
}}
>
{radarrFiltered.length > 0 && <Indicator size={7} color="yellow" children={null} />}
{sonarrFiltered.length > 0 && <Indicator size={7} offset={8} color="blue" children={null} />}
<Popover
position="left"
width={700}
onClose={() => setOpened(false)}
opened={opened}
// TODO: Fix this !! WTF ?
target={` ${day}`}
>
<ScrollArea style={{ height: 400 }}>
{sonarrFiltered.length > 0 && <SonarrMediaDisplay media={sonarrFiltered[0]} />}
{radarrFiltered.length > 0 && sonarrFiltered.length > 0 && (
<Divider variant="dashed" my="xl" />
)}
{radarrFiltered.length > 0 && <RadarrMediaDisplay media={radarrFiltered[0]} />}
</ScrollArea>
</Popover>
</Box>
);
}

View File

@@ -0,0 +1,67 @@
import { RadarrMediaDisplay } from './MediaDisplay';
export default {
title: 'Media display component',
args: {
media: {
title: 'Doctor Strange in the Multiverse of Madness',
originalTitle: 'Doctor Strange in the Multiverse of Madness',
originalLanguage: {
id: 1,
name: 'English',
},
secondaryYearSourceId: 0,
sortTitle: 'doctor strange in multiverse madness',
sizeOnDisk: 0,
status: 'announced',
overview:
'Doctor Strange, with the help of mystical allies both old and new, traverses the mind-bending and dangerous alternate realities of the Multiverse to confront a mysterious new adversary.',
inCinemas: '2022-05-04T00:00:00Z',
images: [
{
coverType: 'poster',
url: 'https://image.tmdb.org/t/p/original/wRnbWt44nKjsFPrqSmwYki5vZtF.jpg',
},
{
coverType: 'fanart',
url: 'https://image.tmdb.org/t/p/original/ndCSoasjIZAMMDIuMxuGnNWu4DU.jpg',
},
],
website: 'https://www.marvel.com/movies/doctor-strange-in-the-multiverse-of-madness',
year: 2022,
hasFile: false,
youTubeTrailerId: 'aWzlQ2N6qqg',
studio: 'Marvel Studios',
path: '/config/Doctor Strange in the Multiverse of Madness (2022)',
qualityProfileId: 1,
monitored: true,
minimumAvailability: 'announced',
isAvailable: true,
folderName: '/config/Doctor Strange in the Multiverse of Madness (2022)',
runtime: 126,
cleanTitle: 'doctorstrangeinmultiversemadness',
imdbId: 'tt9419884',
tmdbId: 453395,
titleSlug: '453395',
certification: 'PG-13',
genres: ['Fantasy', 'Action', 'Adventure'],
tags: [],
added: '2022-04-29T20:52:33Z',
ratings: {
tmdb: {
votes: 0,
value: 0,
type: 'user',
},
},
collection: {
name: 'Doctor Strange Collection',
tmdbId: 618529,
images: [],
},
id: 1,
},
},
};
export const Default = (args: any) => <RadarrMediaDisplay {...args} />;

View File

@@ -0,0 +1,91 @@
import { Stack, Image, Group, Title, Badge, Text, ActionIcon, Anchor } from '@mantine/core';
import { Link } from 'tabler-icons-react';
export interface IMedia {
id: string;
title: string;
description: string;
poster: string;
type: string;
genres: string[];
}
export function RadarrMediaDisplay(props: any) {
const { media }: { media: any } = props;
// Find a poster CoverType
const poster = media.images.find((image: any) => image.coverType === 'poster');
// Return a movie poster containting the title and the description
return (
<Group noWrap align="self-start">
<Image fit="cover" src={poster.url} alt={media.title} width={300} height={400} />
<Stack
justify="space-between"
sx={(theme) => ({
height: 400,
})}
>
<Group direction="column">
<Group>
<Title order={3}>{media.title}</Title>
<Anchor href={`https://www.imdb.com/title/${media.imdbId}`} target="_blank">
<ActionIcon>
<Link />
</ActionIcon>
</Anchor>
</Group>
<Text>{media.overview}</Text>
</Group>
{/*Add the genres at the bottom of the poster*/}
<Group>
{media.genres.map((genre: string, i: number) => (
<Badge key={i}>{genre}</Badge>
))}
</Group>
</Stack>
</Group>
);
}
export function SonarrMediaDisplay(props: any) {
const { media }: { media: any } = props;
// Find a poster CoverType
const poster = media.series.images.find((image: any) => image.coverType === 'poster');
// Return a movie poster containting the title and the description
return (
<Group noWrap align="self-start">
<Image src={poster.url} fit="cover" width={300} height={400} alt={media.series.title} />
<Stack
justify="space-between"
sx={(theme) => ({
height: 400,
})}
>
<Group direction="column">
<Group>
<Title order={3}>{media.series.title}</Title>
<Anchor href={`https://www.imdb.com/title/${media.series.imdbId}`} target="_blank">
<ActionIcon>
<Link />
</ActionIcon>
</Anchor>
</Group>
<Text
style={{
textAlign: 'center',
color: '#a0aec0',
}}
>
Season {media.seasonNumber} episode {media.episodeNumber}
</Text>
<Text>{media.series.overview}</Text>
</Group>
{/*Add the genres at the bottom of the poster*/}
<Group>
{media.series.genres.map((genre: string, i: number) => (
<Badge key={i}>{genre}</Badge>
))}
</Group>
</Stack>
</Group>
);
}

View File

@@ -0,0 +1,408 @@
export const medias = [
{
title: 'Doctor Strange in the Multiverse of Madness',
originalTitle: 'Doctor Strange in the Multiverse of Madness',
originalLanguage: {
id: 1,
name: 'English',
},
alternateTitles: [
{
sourceType: 'tmdb',
movieId: 1,
title: 'Doctor Strange 2',
sourceId: 0,
votes: 0,
voteCount: 0,
language: {
id: 1,
name: 'English',
},
id: 1,
},
{
sourceType: 'tmdb',
movieId: 1,
title: 'Доктор Стрэндж 2',
sourceId: 0,
votes: 0,
voteCount: 0,
language: {
id: 11,
name: 'Russian',
},
id: 2,
},
{
sourceType: 'tmdb',
movieId: 1,
title: 'Doutor Estranho 2',
sourceId: 0,
votes: 0,
voteCount: 0,
language: {
id: 1,
name: 'English',
},
id: 3,
},
{
sourceType: 'tmdb',
movieId: 1,
title: 'Doctor Strange v multivesmíre šialenstva',
sourceId: 0,
votes: 0,
voteCount: 0,
language: {
id: 1,
name: 'English',
},
id: 4,
},
{
sourceType: 'tmdb',
movieId: 1,
title: 'Doctor Strange 2: El multiverso de la locura',
sourceId: 0,
votes: 0,
voteCount: 0,
language: {
id: 3,
name: 'Spanish',
},
id: 5,
},
{
sourceType: 'tmdb',
movieId: 1,
title: 'Doktor Strange Deliliğin Çoklu Evreninde',
sourceId: 0,
votes: 0,
voteCount: 0,
language: {
id: 17,
name: 'Turkish',
},
id: 6,
},
{
sourceType: 'tmdb',
movieId: 1,
title: 'মহাবিশ্বের পাগলামিতে অদ্ভুত চিকিৎসক',
sourceId: 0,
votes: 0,
voteCount: 0,
language: {
id: 1,
name: 'English',
},
id: 7,
},
{
sourceType: 'tmdb',
movieId: 1,
title: 'จอมเวทย์มหากาฬ ในมัลติเวิร์สมหาภัย',
sourceId: 0,
votes: 0,
voteCount: 0,
language: {
id: 28,
name: 'Thai',
},
id: 8,
},
{
sourceType: 'tmdb',
movieId: 1,
title: "Marvel Studios' Doctor Strange in the Multiverse of Madness",
sourceId: 0,
votes: 0,
voteCount: 0,
language: {
id: 1,
name: 'English',
},
id: 9,
},
{
sourceType: 'tmdb',
movieId: 1,
title: 'Doctor Strange en el Multiverso de la Locura de Marvel Studios',
sourceId: 0,
votes: 0,
voteCount: 0,
language: {
id: 3,
name: 'Spanish',
},
id: 10,
},
{
sourceType: 'tmdb',
movieId: 1,
title: 'Doktors Streindžs neprāta multivisumā',
sourceId: 0,
votes: 0,
voteCount: 0,
language: {
id: 1,
name: 'English',
},
id: 11,
},
],
secondaryYearSourceId: 0,
sortTitle: 'doctor strange in multiverse madness',
sizeOnDisk: 0,
status: 'announced',
overview:
'Doctor Strange, with the help of mystical allies both old and new, traverses the mind-bending and dangerous alternate realities of the Multiverse to confront a mysterious new adversary.',
inCinemas: '2022-05-04T00:00:00Z',
images: [
{
coverType: 'poster',
url: 'https://image.tmdb.org/t/p/original/wRnbWt44nKjsFPrqSmwYki5vZtF.jpg',
},
{
coverType: 'fanart',
url: 'https://image.tmdb.org/t/p/original/ndCSoasjIZAMMDIuMxuGnNWu4DU.jpg',
},
],
website: 'https://www.marvel.com/movies/doctor-strange-in-the-multiverse-of-madness',
year: 2022,
hasFile: false,
youTubeTrailerId: 'aWzlQ2N6qqg',
studio: 'Marvel Studios',
path: '/config/Doctor Strange in the Multiverse of Madness (2022)',
qualityProfileId: 1,
monitored: true,
minimumAvailability: 'announced',
isAvailable: true,
folderName: '/config/Doctor Strange in the Multiverse of Madness (2022)',
runtime: 126,
cleanTitle: 'doctorstrangeinmultiversemadness',
imdbId: 'tt9419884',
tmdbId: 453395,
titleSlug: '453395',
certification: 'PG-13',
genres: ['Fantasy', 'Action', 'Adventure'],
tags: [],
added: '2022-04-29T20:52:33Z',
ratings: {
tmdb: {
votes: 0,
value: 0,
type: 'user',
},
},
collection: {
name: 'Doctor Strange Collection',
tmdbId: 618529,
images: [],
},
id: 1,
},
{
title: 'Doctor Strange in the Multiverse of Madness',
originalTitle: 'Doctor Strange in the Multiverse of Madness',
originalLanguage: {
id: 1,
name: 'English',
},
alternateTitles: [
{
sourceType: 'tmdb',
movieId: 1,
title: 'Doctor Strange 2',
sourceId: 0,
votes: 0,
voteCount: 0,
language: {
id: 1,
name: 'English',
},
id: 1,
},
{
sourceType: 'tmdb',
movieId: 1,
title: 'Доктор Стрэндж 2',
sourceId: 0,
votes: 0,
voteCount: 0,
language: {
id: 11,
name: 'Russian',
},
id: 2,
},
{
sourceType: 'tmdb',
movieId: 1,
title: 'Doutor Estranho 2',
sourceId: 0,
votes: 0,
voteCount: 0,
language: {
id: 1,
name: 'English',
},
id: 3,
},
{
sourceType: 'tmdb',
movieId: 1,
title: 'Doctor Strange v multivesmíre šialenstva',
sourceId: 0,
votes: 0,
voteCount: 0,
language: {
id: 1,
name: 'English',
},
id: 4,
},
{
sourceType: 'tmdb',
movieId: 1,
title: 'Doctor Strange 2: El multiverso de la locura',
sourceId: 0,
votes: 0,
voteCount: 0,
language: {
id: 3,
name: 'Spanish',
},
id: 5,
},
{
sourceType: 'tmdb',
movieId: 1,
title: 'Doktor Strange Deliliğin Çoklu Evreninde',
sourceId: 0,
votes: 0,
voteCount: 0,
language: {
id: 17,
name: 'Turkish',
},
id: 6,
},
{
sourceType: 'tmdb',
movieId: 1,
title: 'মহাবিশ্বের পাগলামিতে অদ্ভুত চিকিৎসক',
sourceId: 0,
votes: 0,
voteCount: 0,
language: {
id: 1,
name: 'English',
},
id: 7,
},
{
sourceType: 'tmdb',
movieId: 1,
title: 'จอมเวทย์มหากาฬ ในมัลติเวิร์สมหาภัย',
sourceId: 0,
votes: 0,
voteCount: 0,
language: {
id: 28,
name: 'Thai',
},
id: 8,
},
{
sourceType: 'tmdb',
movieId: 1,
title: "Marvel Studios' Doctor Strange in the Multiverse of Madness",
sourceId: 0,
votes: 0,
voteCount: 0,
language: {
id: 1,
name: 'English',
},
id: 9,
},
{
sourceType: 'tmdb',
movieId: 1,
title: 'Doctor Strange en el Multiverso de la Locura de Marvel Studios',
sourceId: 0,
votes: 0,
voteCount: 0,
language: {
id: 3,
name: 'Spanish',
},
id: 10,
},
{
sourceType: 'tmdb',
movieId: 1,
title: 'Doktors Streindžs neprāta multivisumā',
sourceId: 0,
votes: 0,
voteCount: 0,
language: {
id: 1,
name: 'English',
},
id: 11,
},
],
secondaryYearSourceId: 0,
sortTitle: 'doctor strange in multiverse madness',
sizeOnDisk: 0,
status: 'announced',
overview:
'Doctor Strange, with the help of mystical allies both old and new, traverses the mind-bending and dangerous alternate realities of the Multiverse to confront a mysterious new adversary.',
inCinemas: '2022-05-05T00:00:00Z',
images: [
{
coverType: 'poster',
url: 'https://image.tmdb.org/t/p/original/wRnbWt44nKjsFPrqSmwYki5vZtF.jpg',
},
{
coverType: 'fanart',
url: 'https://image.tmdb.org/t/p/original/ndCSoasjIZAMMDIuMxuGnNWu4DU.jpg',
},
],
website: 'https://www.marvel.com/movies/doctor-strange-in-the-multiverse-of-madness',
year: 2022,
hasFile: false,
youTubeTrailerId: 'aWzlQ2N6qqg',
studio: 'Marvel Studios',
path: '/config/Doctor Strange in the Multiverse of Madness (2022)',
qualityProfileId: 1,
monitored: true,
minimumAvailability: 'announced',
isAvailable: true,
folderName: '/config/Doctor Strange in the Multiverse of Madness (2022)',
runtime: 126,
cleanTitle: 'doctorstrangeinmultiversemadness',
imdbId: 'tt9419884',
tmdbId: 453395,
titleSlug: '453395',
certification: 'PG-13',
genres: ['Fantasy', 'Action', 'Adventure'],
tags: [],
added: '2022-04-29T20:52:33Z',
ratings: {
tmdb: {
votes: 0,
value: 0,
type: 'user',
},
},
collection: {
name: 'Doctor Strange Collection',
tmdbId: 618529,
images: [],
},
id: 2,
},
];

View File

@@ -0,0 +1,11 @@
// This interface is to be used in all the modules of the project
// Each module should have its own interface and call the following function:
// TODO: Add a function to register a module
// Note: Maybe use context to keep track of the modules
export interface MHPModule {
title: string;
description: string;
icon: React.ReactNode;
component: React.ComponentType;
props?: any;
}