stremio-web/src/routes/Discover/useSelectableInputs.js
svetlagasheva 498cd7fae7 typo fixed
2020-01-30 14:25:35 +02:00

188 lines
6.9 KiB
JavaScript

const React = require('react');
const NONE_EXTRA_VALUE = 'None';
const CATALOG_PAGE_SIZE = 100;
const SKIP_EXTRA = {
name: 'skip',
optionsLimit: 1,
isRequired: false
};
const navigateWithLoadRequest = (load_request) => {
const transportUrl = encodeURIComponent(load_request.base);
const type = encodeURIComponent(load_request.path.type_name);
const catalogId = encodeURIComponent(load_request.path.id);
const extra = new URLSearchParams(load_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 !== 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 equalWithoutExtra = (request1, request2) => {
return request1.base === request2.base &&
request1.path.resource === request2.path.resource &&
request1.path.type_name === request2.path.type_name &&
request1.path.id === request2.path.id;
};
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 === SKIP_EXTRA.name) {
const skip = parseInt(value);
if (isFinite(skip)) {
return Math.floor(skip / CATALOG_PAGE_SIZE) + 1;
}
}
return requestedPage;
}, 1);
const typeSelect = {
title: 'Select type',
options: discover.selectable.types
.map(({ name, load_request }) => ({
value: JSON.stringify(load_request),
label: name
})),
selected: discover.selectable.types
.filter(({ load_request: { path: { type_name } } }) => {
return type_name === selectedCatalogRequest.path.type_name;
})
.map(({ load_request }) => JSON.stringify(load_request)),
onSelect: (event) => {
navigateWithLoadRequest(JSON.parse(event.value));
}
};
const catalogSelect = {
title: 'Select catalog',
options: discover.selectable.catalogs
.map(({ name, load_request }) => ({
value: JSON.stringify(load_request),
label: name
})),
selected: discover.selectable.catalogs
.filter(({ load_request }) => {
return equalWithoutExtra(load_request, selectedCatalogRequest);
})
.map(({ load_request }) => JSON.stringify(load_request)),
onSelect: (event) => {
navigateWithLoadRequest(JSON.parse(event.value));
}
};
const extraSelects = discover.selectable.extra.map((extra) => {
const title = `Select ${extra.name}`;
const options = (extra.isRequired ? [] : [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 !== NONE_EXTRA_VALUE)
.concat([value]);
}
return selected;
}, extra.isRequired ? [] : [NONE_EXTRA_VALUE]);
const renderLabelText = selected.includes(NONE_EXTRA_VALUE) ?
() => title
:
null;
const onSelect = (event) => {
navigateWithLoadRequest({
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, 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 * CATALOG_PAGE_SIZE)
:
String((requestedPage - 2) * CATALOG_PAGE_SIZE);
navigateWithLoadRequest({
base: selectedCatalogRequest.base,
path: {
resource: 'catalog',
type_name: selectedCatalogRequest.path.type_name,
id: selectedCatalogRequest.path.id,
extra: getNextExtra(selectedCatalogRequest.path.extra, SKIP_EXTRA, nextValue)
}
});
}
}
:
null;
return [[typeSelect, catalogSelect, ...extraSelects], paginationInput];
};
const useSelectableInputs = (discover) => {
const selectableInputs = React.useMemo(() => {
return mapSelectableInputs(discover);
}, [discover]);
return selectableInputs;
};
module.exports = useSelectableInputs;