mirror of
https://github.com/Stremio/stremio-web.git
synced 2026-03-11 17:15:48 +00:00
Library refactored to use new model schema
This commit is contained in:
parent
2cf0bfa4b1
commit
3252b8e829
3 changed files with 60 additions and 85 deletions
|
|
@ -9,18 +9,15 @@ const useLibrary = require('./useLibrary');
|
|||
const useSelectableInputs = require('./useSelectableInputs');
|
||||
const styles = require('./styles');
|
||||
|
||||
const Library = ({ model, route, urlParams, queryParams }) => {
|
||||
const Library = ({ model, urlParams, queryParams }) => {
|
||||
const profile = useProfile();
|
||||
const library = useLibrary(model, urlParams, queryParams);
|
||||
const [typeSelect, sortSelect] = useSelectableInputs(route, library);
|
||||
const available = React.useMemo(() => {
|
||||
return route === 'continuewatching' || profile.auth !== null;
|
||||
}, []);
|
||||
const [typeSelect, sortSelect] = useSelectableInputs(library);
|
||||
return (
|
||||
<MainNavBars className={styles['library-container']} route={route}>
|
||||
<MainNavBars className={styles['library-container']} route={model}>
|
||||
<div className={styles['library-content']}>
|
||||
{
|
||||
available && library.type_names.length > 0 ?
|
||||
model === 'continue_watching' || profile.auth !== null ?
|
||||
<div className={styles['selectable-inputs-container']}>
|
||||
<Multiselect {...typeSelect} className={styles['select-input-container']} />
|
||||
<Multiselect {...sortSelect} className={styles['select-input-container']} />
|
||||
|
|
@ -29,7 +26,7 @@ const Library = ({ model, route, urlParams, queryParams }) => {
|
|||
null
|
||||
}
|
||||
{
|
||||
!available ?
|
||||
model === 'library' && profile.auth === null ?
|
||||
<div className={classnames(styles['message-container'], styles['no-user-message-container'])}>
|
||||
<Image
|
||||
className={styles['image']}
|
||||
|
|
@ -42,41 +39,31 @@ const Library = ({ model, route, urlParams, queryParams }) => {
|
|||
<div className={styles['message-label']}>Library is only available for logged in users!</div>
|
||||
</div>
|
||||
:
|
||||
library.type_names.length === 0 ?
|
||||
library.selected === null ?
|
||||
<div className={styles['message-container']}>
|
||||
<Image
|
||||
className={styles['image']}
|
||||
src={'/images/empty.png'}
|
||||
alt={' '}
|
||||
/>
|
||||
<div className={styles['message-label']}>Empty {route === 'continuewatching' ? 'Continue Watching' : 'Library'}</div>
|
||||
<div className={styles['message-label']}>{model === 'library' ? 'Library' : 'Continue Watching'} not loaded!</div>
|
||||
</div>
|
||||
:
|
||||
library.selected === null ?
|
||||
library.catalog.length === 0 ?
|
||||
<div className={styles['message-container']}>
|
||||
<Image
|
||||
className={styles['image']}
|
||||
src={'/images/empty.png'}
|
||||
alt={' '}
|
||||
/>
|
||||
<div className={styles['message-label']}>{route === 'continuewatching' ? 'Continue Watching' : 'Library'} not loaded!</div>
|
||||
<div className={styles['message-label']}>Empty {model === 'library' ? 'Library' : 'Continue Watching'}</div>
|
||||
</div>
|
||||
:
|
||||
library.library_items.length === 0 ?
|
||||
<div className={styles['message-container']}>
|
||||
<Image
|
||||
className={styles['image']}
|
||||
src={'/images/empty.png'}
|
||||
alt={' '}
|
||||
/>
|
||||
<div className={styles['message-label']}>There are no items for the selected type!</div>
|
||||
</div>
|
||||
:
|
||||
<div className={styles['meta-items-container']}>
|
||||
{library.library_items.map((libItem, index) => (
|
||||
<LibItem {...libItem} key={index} />
|
||||
))}
|
||||
</div>
|
||||
<div className={styles['meta-items-container']}>
|
||||
{library.catalog.map((libItem, index) => (
|
||||
<LibItem {...libItem} key={index} />
|
||||
))}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</MainNavBars>
|
||||
|
|
@ -85,7 +72,6 @@ const Library = ({ model, route, urlParams, queryParams }) => {
|
|||
|
||||
Library.propTypes = {
|
||||
model: PropTypes.oneOf(['library', 'continue_watching']),
|
||||
route: PropTypes.oneOf(['library', 'continuewatching']),
|
||||
urlParams: PropTypes.shape({
|
||||
type: PropTypes.string
|
||||
}),
|
||||
|
|
@ -93,24 +79,23 @@ Library.propTypes = {
|
|||
};
|
||||
|
||||
module.exports = ({ urlParams, queryParams }) => {
|
||||
const [model, route] = React.useMemo(() => {
|
||||
const model = React.useMemo(() => {
|
||||
return typeof urlParams.path === 'string' ?
|
||||
urlParams.path.match(routesRegexp.library.regexp) ?
|
||||
['library', 'library']
|
||||
'library'
|
||||
:
|
||||
urlParams.path.match(routesRegexp.continuewatching.regexp) ?
|
||||
['continue_watching', 'continuewatching']
|
||||
'continue_watching'
|
||||
:
|
||||
[null, null]
|
||||
null
|
||||
:
|
||||
[null, null];
|
||||
null;
|
||||
}, [urlParams.path]);
|
||||
if (typeof model === 'string') {
|
||||
return (
|
||||
<Library
|
||||
key={model}
|
||||
model={model}
|
||||
route={route}
|
||||
urlParams={urlParams}
|
||||
queryParams={queryParams}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -1,18 +1,20 @@
|
|||
// Copyright (C) 2017-2020 Smart code 203358507
|
||||
|
||||
const React = require('react');
|
||||
const { CONSTANTS, deepLinking, useModelState, comparatorWithPriorities } = require('stremio/common');
|
||||
const { useModelState } = require('stremio/common');
|
||||
|
||||
const initLibraryState = () => ({
|
||||
const init = () => ({
|
||||
selected: null,
|
||||
type_names: [],
|
||||
library_items: []
|
||||
selectable: {
|
||||
types: [],
|
||||
sorts: []
|
||||
},
|
||||
catalog: []
|
||||
});
|
||||
|
||||
const mapLibraryState = (library) => {
|
||||
const selected = library.selected;
|
||||
const type_names = library.type_names.sort(comparatorWithPriorities(CONSTANTS.TYPE_PRIORITIES));
|
||||
const library_items = library.library_items.map((libItem) => ({
|
||||
const map = (library) => ({
|
||||
...library,
|
||||
catalog: library.catalog.map((libItem) => ({
|
||||
id: libItem._id,
|
||||
type: libItem.type,
|
||||
name: libItem.name,
|
||||
|
|
@ -22,28 +24,24 @@ const mapLibraryState = (library) => {
|
|||
libItem.state.timeOffset / libItem.state.duration
|
||||
:
|
||||
null,
|
||||
deepLinks: deepLinking.withLibItem({ libItem })
|
||||
}));
|
||||
return { selected, type_names, library_items };
|
||||
};
|
||||
deepLinks: libItem.deepLinks
|
||||
}))
|
||||
});
|
||||
|
||||
const useLibrary = (libraryModel, urlParams, queryParams) => {
|
||||
const loadLibraryAction = React.useMemo(() => ({
|
||||
const useLibrary = (model, urlParams, queryParams) => {
|
||||
const action = React.useMemo(() => ({
|
||||
action: 'Load',
|
||||
args: {
|
||||
model: 'LibraryWithFilters',
|
||||
args: {
|
||||
type_name: typeof urlParams.type === 'string' ? urlParams.type : null,
|
||||
sort: queryParams.has('sort') ? queryParams.get('sort') : 'lastwatched'
|
||||
request: {
|
||||
type: typeof urlParams.type === 'string' ? urlParams.type : null,
|
||||
sort: queryParams.has('sort') ? queryParams.get('sort') : undefined
|
||||
}
|
||||
}
|
||||
}
|
||||
}), [urlParams, queryParams]);
|
||||
return useModelState({
|
||||
model: libraryModel,
|
||||
action: loadLibraryAction,
|
||||
map: mapLibraryState,
|
||||
init: initLibraryState
|
||||
});
|
||||
return useModelState({ model, action, map, init });
|
||||
};
|
||||
|
||||
module.exports = useLibrary;
|
||||
|
|
|
|||
|
|
@ -2,49 +2,41 @@
|
|||
|
||||
const React = require('react');
|
||||
|
||||
const SORT_OPTIONS = [
|
||||
{ label: 'Recent', value: 'lastwatched' },
|
||||
{ label: 'A-Z', value: 'name' },
|
||||
{ label: 'Watched', value: 'timeswatched' },
|
||||
];
|
||||
|
||||
const mapSelectableInputs = (route, library) => {
|
||||
const mapSelectableInputs = (library) => {
|
||||
const typeSelect = {
|
||||
title: 'Select type',
|
||||
selected: library.selected !== null ?
|
||||
[JSON.stringify(library.selected.type_name)]
|
||||
:
|
||||
[],
|
||||
options: [{ label: 'All', value: JSON.stringify(null) }]
|
||||
.concat(library.type_names.map((type) => ({ label: type, value: JSON.stringify(type) }))),
|
||||
renderLabelText: () => {
|
||||
return library.selected.type_name === null ? 'All' : library.selected.type_name;
|
||||
},
|
||||
options: library.selectable.types
|
||||
.map(({ type, deep_links }) => ({
|
||||
value: deep_links.library,
|
||||
label: type === null ? 'All' : type
|
||||
})),
|
||||
selected: library.selectable.types
|
||||
.filter(({ selected }) => selected)
|
||||
.map(({ deep_links }) => deep_links.library),
|
||||
onSelect: (event) => {
|
||||
const type = JSON.parse(event.value);
|
||||
const queryParams = new URLSearchParams(library.selected !== null ? [['sort', library.selected.sort]] : []);
|
||||
window.location = `#/${route}${type !== null ? `/${encodeURIComponent(type)}` : ''}?${queryParams.toString()}`;
|
||||
window.location = event.value;
|
||||
}
|
||||
};
|
||||
const sortSelect = {
|
||||
title: 'Select sort',
|
||||
selected: library.selected !== null ?
|
||||
[library.selected.sort]
|
||||
:
|
||||
[],
|
||||
options: SORT_OPTIONS,
|
||||
options: library.selectable.sorts
|
||||
.map(({ sort, deep_links }) => ({
|
||||
value: deep_links.library,
|
||||
label: sort
|
||||
})),
|
||||
selected: library.selectable.sorts
|
||||
.filter(({ selected }) => selected)
|
||||
.map(({ deep_links }) => deep_links.library),
|
||||
onSelect: (event) => {
|
||||
const type = library.selected !== null ? library.selected.type_name : null;
|
||||
const queryParams = new URLSearchParams([['sort', event.value]]);
|
||||
window.location = `#/${route}${type !== null ? `/${encodeURIComponent(type)}` : ''}?${queryParams.toString()}`;
|
||||
window.location = event.value;
|
||||
}
|
||||
};
|
||||
return [typeSelect, sortSelect];
|
||||
};
|
||||
|
||||
const useSelectableInputs = (route, library) => {
|
||||
const useSelectableInputs = (library) => {
|
||||
const selectableInputs = React.useMemo(() => {
|
||||
return mapSelectableInputs(route, library);
|
||||
return mapSelectableInputs(library);
|
||||
}, [library]);
|
||||
return selectableInputs;
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue