mirror of
https://github.com/Stremio/stremio-web.git
synced 2026-04-25 20:03:00 +00:00
182 lines
6.8 KiB
JavaScript
182 lines
6.8 KiB
JavaScript
const React = require('react');
|
|
const { CONSTANTS } = require('stremio/common');
|
|
|
|
const SKIP_EXTRA_PROP = {
|
|
name: CONSTANTS.SKIP_EXTRA_NAME,
|
|
optionsLimit: 1,
|
|
isRequired: false
|
|
};
|
|
|
|
const navigateWithRequest = (request) => {
|
|
const transportUrl = encodeURIComponent(request.base);
|
|
const type = encodeURIComponent(request.path.type_name);
|
|
const catalogId = encodeURIComponent(request.path.id);
|
|
const extra = new URLSearchParams(request.path.extra).toString();
|
|
window.location.replace(`#/discover/${transportUrl}/${type}/${catalogId}?${extra}`);
|
|
};
|
|
|
|
const getNextExtra = (prevExtra, extraProp, extraValue) => {
|
|
return prevExtra
|
|
.concat([[extraProp.name, extraValue]])
|
|
.reduceRight((result, [name, value]) => {
|
|
if (extraProp.name === name) {
|
|
if (extraValue !== CONSTANTS.NONE_EXTRA_VALUE) {
|
|
const optionsCount = result.reduce((optionsCount, [name]) => {
|
|
if (extraProp.name === name) {
|
|
optionsCount++;
|
|
}
|
|
|
|
return optionsCount;
|
|
}, 0);
|
|
if (extraProp.optionsLimit === 1) {
|
|
if (optionsCount === 0) {
|
|
result.unshift([name, value]);
|
|
}
|
|
} else if (extraProp.optionsLimit > 1) {
|
|
const valueIndex = result.findIndex(([_name, _value]) => {
|
|
return _name === name && _value === value;
|
|
});
|
|
if (valueIndex !== -1) {
|
|
result.splice(valueIndex, 1);
|
|
} else if (extraProp.optionsLimit > optionsCount) {
|
|
result.unshift([name, value]);
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
result.unshift([name, value]);
|
|
}
|
|
|
|
return result;
|
|
}, []);
|
|
};
|
|
|
|
const mapSelectableInputs = (discover) => {
|
|
const selectedCatalogRequest = discover.catalog_resource !== null ?
|
|
discover.catalog_resource.request
|
|
:
|
|
{
|
|
base: null,
|
|
path: {
|
|
resource: 'catalog',
|
|
id: null,
|
|
type_name: null,
|
|
extra: []
|
|
}
|
|
};
|
|
const requestedPage = selectedCatalogRequest.path.extra.reduce((requestedPage, [name, value]) => {
|
|
if (name === CONSTANTS.SKIP_EXTRA_NAME) {
|
|
const skip = parseInt(value);
|
|
if (isFinite(skip)) {
|
|
return Math.floor(skip / CONSTANTS.CATALOG_PAGE_SIZE) + 1;
|
|
}
|
|
}
|
|
|
|
return requestedPage;
|
|
}, 1);
|
|
const typeSelect = {
|
|
title: 'Select type',
|
|
options: discover.selectable.types
|
|
.map(({ name, request }) => ({
|
|
value: JSON.stringify(request),
|
|
label: name
|
|
})),
|
|
selected: discover.selectable.types
|
|
.filter(({ request }) => {
|
|
return selectedCatalogRequest.path.type_name === request.path.type_name;
|
|
})
|
|
.map(({ request }) => JSON.stringify(request)),
|
|
onSelect: (event) => {
|
|
navigateWithRequest(JSON.parse(event.value));
|
|
}
|
|
};
|
|
const catalogSelect = {
|
|
title: 'Select catalog',
|
|
options: discover.selectable.catalogs
|
|
.map(({ name, request }) => ({
|
|
value: JSON.stringify(request),
|
|
label: name
|
|
})),
|
|
selected: discover.selectable.catalogs
|
|
.filter(({ request }) => {
|
|
return selectedCatalogRequest.base === request.base &&
|
|
selectedCatalogRequest.path.id === request.path.id;
|
|
})
|
|
.map(({ request }) => JSON.stringify(request)),
|
|
onSelect: (event) => {
|
|
navigateWithRequest(JSON.parse(event.value));
|
|
}
|
|
};
|
|
const extraSelects = discover.selectable.extra.map((extra) => {
|
|
const title = `Select ${extra.name}`;
|
|
const isRequired = extra.isRequired;
|
|
const options = (extra.isRequired ? [] : [CONSTANTS.NONE_EXTRA_VALUE])
|
|
.concat(extra.options)
|
|
.map((option) => ({
|
|
value: option,
|
|
label: option
|
|
}));
|
|
const selected = selectedCatalogRequest.path.extra
|
|
.reduce((selected, [name, value]) => {
|
|
if (name === extra.name) {
|
|
selected = selected
|
|
.filter((value) => value !== CONSTANTS.NONE_EXTRA_VALUE)
|
|
.concat([value]);
|
|
}
|
|
|
|
return selected;
|
|
}, extra.isRequired ? [] : [CONSTANTS.NONE_EXTRA_VALUE]);
|
|
const renderLabelText = selected.includes(CONSTANTS.NONE_EXTRA_VALUE) ?
|
|
() => title
|
|
:
|
|
null;
|
|
const onSelect = (event) => {
|
|
navigateWithRequest({
|
|
base: selectedCatalogRequest.base,
|
|
path: {
|
|
resource: 'catalog',
|
|
type_name: selectedCatalogRequest.path.type_name,
|
|
id: selectedCatalogRequest.path.id,
|
|
extra: getNextExtra(selectedCatalogRequest.path.extra, extra, event.value)
|
|
}
|
|
});
|
|
};
|
|
return { title, isRequired, options, selected, renderLabelText, onSelect };
|
|
});
|
|
const paginationInput = discover.selectable.has_prev_page || discover.selectable.has_next_page ?
|
|
{
|
|
label: String(requestedPage),
|
|
onSelect: (event) => {
|
|
if (event.value === 'prev' && !discover.selectable.has_prev_page ||
|
|
event.value === 'next' && !discover.selectable.has_next_page) {
|
|
return;
|
|
}
|
|
|
|
const nextValue = event.value === 'next' ?
|
|
String(requestedPage * CONSTANTS.CATALOG_PAGE_SIZE)
|
|
:
|
|
String((requestedPage - 2) * CONSTANTS.CATALOG_PAGE_SIZE);
|
|
navigateWithRequest({
|
|
base: selectedCatalogRequest.base,
|
|
path: {
|
|
resource: 'catalog',
|
|
type_name: selectedCatalogRequest.path.type_name,
|
|
id: selectedCatalogRequest.path.id,
|
|
extra: getNextExtra(selectedCatalogRequest.path.extra, SKIP_EXTRA_PROP, nextValue)
|
|
}
|
|
});
|
|
}
|
|
}
|
|
:
|
|
null;
|
|
return [[typeSelect, catalogSelect, ...extraSelects], paginationInput];
|
|
};
|
|
|
|
const useSelectableInputs = (discover) => {
|
|
const selectableInputs = React.useMemo(() => {
|
|
return mapSelectableInputs(discover);
|
|
}, [discover]);
|
|
return selectableInputs;
|
|
};
|
|
|
|
module.exports = useSelectableInputs;
|