mirror of
https://github.com/sussy-code/smov.git
synced 2024-12-20 14:37:43 +01:00
global persistent reactive storage 🎉
This commit is contained in:
parent
d217c4d9f4
commit
63742a1b60
6 changed files with 104 additions and 18 deletions
23
src/App.tsx
23
src/App.tsx
|
@ -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 (
|
||||
<Switch>
|
||||
<Route exact path="/" component={SearchView} />
|
||||
<Route exact path="/media/movie" component={MovieView} />
|
||||
<Route exact path="/media/series" component={SeriesView} />
|
||||
</Switch>
|
||||
<WatchedContextProvider>
|
||||
<Switch>
|
||||
<Route exact path="/" component={SearchView} />
|
||||
<Route exact path="/media/movie" component={MovieView} />
|
||||
<Route exact path="/media/series" component={SeriesView} />
|
||||
</Switch>
|
||||
</WatchedContextProvider>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
69
src/state/watched/context.tsx
Normal file
69
src/state/watched/context.tsx
Normal 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
|
||||
);
|
||||
});
|
||||
}
|
1
src/state/watched/index.ts
Normal file
1
src/state/watched/index.ts
Normal file
|
@ -0,0 +1 @@
|
|||
export * from "./context";
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue