Skip to content

Commit

Permalink
Merge pull request #56 from stephane-r/refactor-card-types-and-database
Browse files Browse the repository at this point in the history
refactor: add new Card type and save smaller data in localstorage
  • Loading branch information
stephane-r authored Oct 24, 2023
2 parents 156fa2c + 33e8e0d commit 270e1d7
Show file tree
Hide file tree
Showing 57 changed files with 826 additions and 379 deletions.
61 changes: 38 additions & 23 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
"postcss": "^8.4.31",
"postcss-preset-mantine": "^1.9.0",
"postcss-simple-vars": "^7.0.1",
"pretty-bytes": "^6.1.1",
"qs": "^6.11.2",
"react": "^18.2.0",
"react-audio-player": "^0.17.0",
Expand Down
85 changes: 63 additions & 22 deletions src/components/ButtonFavorite.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,32 +13,61 @@ import { db } from "../database";
import { getFavoritePlaylist } from "../database/utils";
import { useFavorite, useSetFavorite } from "../providers/Favorite";
import { usePlayerVideo } from "../providers/Player";
import { Playlist } from "../types/interfaces/Playlist";
import {
Card,
CardChannel,
CardPlaylist,
CardVideo,
} from "../types/interfaces/Card";
import { Channel } from "../types/interfaces/Channel";
import {
FavoritePlaylist as Favorite,
Playlist,
} from "../types/interfaces/Playlist";
import { Video } from "../types/interfaces/Video";
import { cleanVideoThumbnailsUrl } from "../utils/cleanVideoThumbnailsUrl";
import {
formatedCardChannel,
formatedCardPlaylist,
formatedCardVideo,
} from "../utils/formatData";

type ButtonFavoriteCard = Card | Video | Playlist | Channel;
type FavoriteChannel = CardChannel | Channel;
type FavoritePlaylist = CardPlaylist | Playlist;
type FavoriteVideo = CardVideo | Video;

interface ButtonFavoriteProps extends ActionIconProps {
video?: Video;
card?: ButtonFavoriteCard;
iconSize?: number;
buttonSize?: number;
render?: "menu";
}

const getItemId = (item: Video) => {
export const getCardId = (item: ButtonFavoriteCard) => {
if ((item as FavoritePlaylist)?.playlistId) {
return (item as FavoritePlaylist).playlistId;
}
if (
(item as FavoriteChannel)?.authorId &&
(item as FavoriteChannel).type === "channel"
) {
return (item as FavoriteChannel).authorId;
}
return (item as FavoriteVideo)?.videoId;
};

export const getCardTitle = (item: ButtonFavoriteCard) => {
switch (item.type) {
case "channel":
return item.authorId;
case "playlist":
// @ts-ignore
return item.playlistId;
return item.author;
default:
return item.videoId;
return item.title;
}
};

export const ButtonFavorite: React.FC<ButtonFavoriteProps> = memo(
({
video: parentVideo,
card: parentCard,
iconSize = 18,
variant = "default",
buttonSize = 36,
Expand All @@ -50,13 +79,17 @@ export const ButtonFavorite: React.FC<ButtonFavoriteProps> = memo(
const { t } = useTranslation();
const theme = useMantineTheme();

const video = parentVideo ?? (currentVideo as Video);
const card = parentCard ?? (currentVideo as Video);

const isFavorite = favorite.videos.find(
(favVideo) => getItemId(favVideo) === getItemId(video),
if (!card) {
return null;
}

const isFavorite = favorite.cards.find(
(favCard) => getCardId(favCard) === getCardId(card),
);

const updateAndCommit = (updatedFavoritePlaylist: Playlist) => {
const updateAndCommit = (updatedFavoritePlaylist: Favorite) => {
db.update(
"playlists",
{ title: "Favorites" },
Expand All @@ -67,30 +100,38 @@ export const ButtonFavorite: React.FC<ButtonFavoriteProps> = memo(
};

const handleAdd = () => {
const formatedCard = (() => {
switch (card.type) {
case "channel":
return formatedCardChannel(card as FavoriteChannel);
case "playlist":
return formatedCardPlaylist(card as FavoritePlaylist);
default:
return formatedCardVideo(card);
}
})();

updateAndCommit({
...favorite,
videos: [
cleanVideoThumbnailsUrl({ ...video, videoId: getItemId(video) }),
...favorite.videos,
],
cards: [formatedCard, ...favorite.cards],
});

notifications.show({
title: video.title ?? video.author,
title: getCardTitle(card),
message: t("favorite.add.success.message"),
});
};

const handleDelete = () => {
updateAndCommit({
...favorite,
videos: favorite.videos.filter(
(favVideo) => getItemId(favVideo) !== getItemId(video),
cards: favorite.cards.filter(
(favCard) => getCardId(favCard) !== getCardId(card),
),
});

notifications.show({
title: video.title ?? video.author,
title: getCardTitle(card),
message: t("favorite.remove.success.message"),
});
};
Expand Down
10 changes: 5 additions & 5 deletions src/components/CardImage.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
import { Flex } from "@mantine/core";

import { VideoThumbnail } from "../types/interfaces/Video";
import classes from "./CardImage.module.css";
import { Image } from "./Image";

interface CardImageProps {
image: VideoThumbnail;
src: string;
title: string;
domain?: string;
children?: React.ReactNode;
}

export const CardImage: React.FC<CardImageProps> = ({
image,
src,
title,
domain = "",
children,
}) => {
const domainUrl = image.url.startsWith("https") ? "" : domain;
const domainUrl =
src.startsWith("https") || src.startsWith("//") ? "" : domain;

return (
<Flex
Expand All @@ -26,7 +26,7 @@ export const CardImage: React.FC<CardImageProps> = ({
justify="flex-end"
>
<Image
src={`${domainUrl}${image.url}`}
src={`${domainUrl}${src}`}
alt={title}
className={classes.image}
loading="lazy"
Expand Down
43 changes: 30 additions & 13 deletions src/components/CardList.tsx
Original file line number Diff line number Diff line change
@@ -1,40 +1,57 @@
import { Box } from "@mantine/core";
import { memo } from "react";
import { FC, memo } from "react";

import { Video } from "../types/interfaces/Video";
import { Card } from "./Card";
import { useSettings } from "../providers/Settings";
import { Card as CardType } from "../types/interfaces/Card";
import { getCardTitle } from "./ButtonFavorite";
import classes from "./CardList.module.css";
import { ChannelCard } from "./ChannelCard";
import { PlaylistCard } from "./PlaylistCard";
import { VideoCard } from "./VideoCard";

interface CardListProps {
data: Video[];
data: CardType[];
scrollable?: boolean;
}

export const CardList: React.FC<CardListProps> = memo(
export const CardList: FC<CardListProps> = memo(
({ data, scrollable = false }) => {
const { currentInstance } = useSettings();

if (!data.length) {
return null;
}

console.log(classes);

return (
<Box className={scrollable ? classes.flexGrid : classes.grid}>
{data.map((item, index) => (
{data.map((card, index) => (
<Box
key={`${document.location.pathname}${item.title}-${index}`}
key={`${document.location.pathname}${getCardTitle(card)}-${index}`}
className={scrollable ? classes.flexColumn : classes.column}
>
{(() => {
switch (item.type) {
switch (card.type) {
case "playlist":
return <PlaylistCard playlist={item as any} />;
return (
<PlaylistCard
playlist={card}
currentInstanceUri={currentInstance?.uri ?? ""}
/>
);
case "channel":
return <ChannelCard channel={item as any} />;
return (
<ChannelCard
channel={card}
currentInstanceUri={currentInstance?.uri ?? ""}
/>
);
default:
return <Card video={item} />;
return (
<VideoCard
video={card}
currentInstanceUri={currentInstance?.uri ?? ""}
/>
);
}
})()}
</Box>
Expand Down
Loading

0 comments on commit 270e1d7

Please sign in to comment.