global persistent reactive storage 🎉

This commit is contained in:
Jelle van Snik 2022-02-18 21:11:23 +01:00
parent d217c4d9f4
commit 63742a1b60
6 changed files with 104 additions and 18 deletions

View File

@ -1,16 +1,19 @@
import { Route, Switch } from 'react-router-dom';
import './index.css';
import { MovieView } from './views/MovieView';
import { SearchView } from './views/SearchView';
import { SeriesView } from './views/SeriesView';
import { Route, Switch } from "react-router-dom";
import { WatchedContextProvider } from "state/watched/context";
import "./index.css";
import { MovieView } from "./views/MovieView";
import { SearchView } from "./views/SearchView";
import { SeriesView } from "./views/SeriesView";
function App() {
return (
<WatchedContextProvider>
<Switch>
<Route exact path="/" component={SearchView} />
<Route exact path="/media/movie" component={MovieView} />
<Route exact path="/media/series" component={SeriesView} />
</Switch>
</WatchedContextProvider>
);
}

View File

@ -1,4 +1,5 @@
import { MWMedia } from "providers";
import { useWatchedContext, getWatchedFromPortable } from "state/watched";
import { MediaCard } from "./MediaCard";
export interface WatchedMediaCardProps {
@ -6,5 +7,15 @@ export interface WatchedMediaCardProps {
}
export function WatchedMediaCard(props: WatchedMediaCardProps) {
return <MediaCard watchedPercentage={0} media={props.media} linkable />;
const { watched } = useWatchedContext();
const foundWatched = getWatchedFromPortable(watched, props.media);
const watchedPercentage = (foundWatched && foundWatched.percentage) || 0;
return (
<MediaCard
watchedPercentage={watchedPercentage}
media={props.media}
linkable
/>
);
}

View File

@ -0,0 +1,69 @@
import { MWPortableMedia } from "providers";
import React, { createContext, ReactNode, useContext, useState } from "react";
import { VideoProgressStore } from "./store";
interface WatchedStoreItem extends MWPortableMedia {
progress: number;
percentage: number;
}
interface WatchedStoreData {
items: WatchedStoreItem[];
}
interface WatchedStoreDataWrapper {
setWatched: React.Dispatch<React.SetStateAction<WatchedStoreData>>;
watched: WatchedStoreData;
}
const WatchedContext = createContext<WatchedStoreDataWrapper>({
setWatched: () => {},
watched: {
items: [],
},
});
WatchedContext.displayName = "WatchedContext";
export function WatchedContextProvider(props: { children: ReactNode }) {
const watchedLocalstorage = VideoProgressStore.get();
const [watched, setWatched] = useState<WatchedStoreData>(
watchedLocalstorage as WatchedStoreData
);
const contextValue = {
setWatched(data: any) {
setWatched((old) => {
let newData = data;
if (data.constructor === Function) {
newData = data(old);
}
watchedLocalstorage.save(newData);
return newData;
});
},
watched,
};
return (
<WatchedContext.Provider value={contextValue}>
{props.children}
</WatchedContext.Provider>
);
}
export function useWatchedContext() {
return useContext(WatchedContext);
}
export function getWatchedFromPortable(
store: WatchedStoreData,
media: MWPortableMedia
): WatchedStoreItem | undefined {
return store.items.find((v) => {
return (
v.mediaId === media.mediaId &&
v.providerId === media.providerId &&
v.episode === media.episode &&
v.season === media.season
);
});
}

View File

@ -0,0 +1 @@
export * from "./context";

View File

@ -36,15 +36,16 @@ export const VideoProgressStore = versionedStoreBuilder()
.setKey('video-progress')
.addVersion({
version: 0,
migrate(data: any) {
// TODO migration
throw new Error("Migration not been written yet!!")
},
})
.addVersion({
version: 1,
migrate(data: any) {
// TODO migration
},
create() {
return {}
return {
items: [],
}
}
})
.build()

View File

@ -85,8 +85,9 @@ function buildStoreObject(d: any) {
data = this.update(data);
// add a save object to return value
data.save = function save() {
localStorage.setItem(store.id, JSON.stringify(data));
data.save = function save(newData: any) {
let dataToStore = newData || data;
localStorage.setItem(store.id, JSON.stringify(dataToStore));
};
// add instance helpers