Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Source filters, move search to SourceMangas #142

Merged
merged 15 commits into from
Mar 4, 2022
4 changes: 0 additions & 4 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ import About from 'screens/settings/About';
import Categories from 'screens/settings/Categories';
import Backup from 'screens/settings/Backup';
import Library from 'screens/Library';
import SearchSingle from 'screens/SearchSingle';
import SourceConfigure from 'screens/SourceConfigure';
import Manga from 'screens/Manga';
import SourceMangas from 'screens/SourceMangas';
Expand Down Expand Up @@ -131,9 +130,6 @@ export default function App() {

{/* Manga Routes */}

<Route path="/sources/:sourceId/search/">
<SearchSingle />
</Route>
<Route path="/sources/:sourceId/popular/">
<SourceMangas popular />
</Route>
Expand Down
29 changes: 4 additions & 25 deletions src/components/SourceCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,7 @@ import React from 'react';
import Card from '@mui/material/Card';
import CardContent from '@mui/material/CardContent';
import { useHistory } from 'react-router-dom';
import SearchIcon from '@mui/icons-material/Search';
import Button from '@mui/material/Button';
import IconButton from '@mui/material/IconButton';
import FiberNewOutlinedIcon from '@mui/icons-material/FiberNewOutlined';
import Avatar from '@mui/material/Avatar';
import Typography from '@mui/material/Typography';
import useLocalStorage from 'util/useLocalStorage';
Expand Down Expand Up @@ -108,34 +105,16 @@ export default function SourceCard(props: IProps) {
</Box>
<>
<MobileWidthButtons>
<IconButton
sx={{ width: 59, height: 59 }}
onClick={(e) => redirectTo(e, `/sources/${id}/search/`)}
size="large"
edge="end"
>
<SearchIcon
fontSize="medium"
/>
</IconButton>
{supportsLatest && (
<IconButton
<Button
variant="outlined"
onClick={(e) => redirectTo(e, `/sources/${id}/latest/`)}
size="large"
>
<FiberNewOutlinedIcon
fontSize="large"
/>
</IconButton>
Latest
</Button>
)}
</MobileWidthButtons>
<WiderWidthButtons>
<Button
variant="outlined"
onClick={(e) => redirectTo(e, `/sources/${id}/search/`)}
>
Search
</Button>
{supportsLatest && (
<Button
variant="outlined"
Expand Down
37 changes: 37 additions & 0 deletions src/components/source/SourceMangaGrid.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Copyright (C) Contributors to the Suwayomi project
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/

import React from 'react';
import MangaGrid, { IMangaGridProps } from 'components/MangaGrid';

const FILTERED_OUT_MESSAGE = 'There are no Manga matching this filter';

function filterManga(mangas: IMangaCard[]): IMangaCard[] {
return mangas;
}

export default function SourceMangaGrid(props: IMangaGridProps) {
const {
mangas, isLoading, hasNextPage, lastPageNum, setLastPageNum, message, messageExtra,
} = props;

const filteredManga = filterManga(mangas);
const showFilteredOutMessage = filteredManga.length === 0 && mangas.length > 0;

return (
<MangaGrid
mangas={filteredManga}
isLoading={isLoading}
hasNextPage={hasNextPage}
lastPageNum={lastPageNum}
setLastPageNum={setLastPageNum}
message={showFilteredOutMessage ? FILTERED_OUT_MESSAGE : message}
messageExtra={messageExtra}
/>
);
}
203 changes: 203 additions & 0 deletions src/components/source/SourceOptions.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
/*
* Copyright (C) Contributors to the Suwayomi project
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/

import React from 'react';
import FilterListIcon from '@mui/icons-material/FilterList';
import {
Drawer, Button, Fab,
} from '@mui/material';
import { Box } from '@mui/system';
import SelectFilter from './filters/SelectFilter';
import CheckBoxFilter from './filters/CheckBoxFilter';
import HeaderFilter from './filters/HeaderFilter';
import SeperatorFilter from './filters/SeparatorFilter';
import SortFilter from './filters/SortFilter';
import TextFilter from './filters/TextFilter';
import TriStateFilter from './filters/TriStateFilter';
// this can only cycle once, so should be fine
// eslint-disable-next-line import/no-cycle
import GroupFilter from './filters/GroupFilter';

interface IFilters {
sourceFilter: ISourceFilters[]
updateFilterValue: Function
group: number | undefined
}

interface IFilters1 {
sourceFilter: ISourceFilters[]
updateFilterValue: Function
resetFilterValue: Function
setTriggerUpdate: Function
setSearch: Function
}

export function Options({
sourceFilter,
group,
updateFilterValue,
}: IFilters) {
return (
<Box key={`filters ${group}`}>
{ sourceFilter.map((e: ISourceFilters, index) => {
switch (e.type) {
case 'CheckBox':
return (
<CheckBoxFilter
key={`filters ${e.filter.name}`}
name={e.filter.name}
state={e.filter.state as boolean}
position={index}
group={group}
updateFilterValue={updateFilterValue}
/>
);
case 'Group':
return (
<GroupFilter
key={`filters ${e.filter.name}`}
name={e.filter.name}
state={e.filter.state as ISourceFilters[]}
position={index}
updateFilterValue={updateFilterValue}
/>
);
case 'Header':
return (
<HeaderFilter
key={`filters ${e.filter.name}`}
name={e.filter.name}
/>
);
case 'Select':
return (
<SelectFilter
key={`filters ${e.filter.name}`}
name={e.filter.name}
values={e.filter.values}
state={e.filter.state as number}
selected={e.filter.selected}
position={index}
group={group}
updateFilterValue={updateFilterValue}
/>
);
case 'Separator':
return (
<SeperatorFilter
key={`filters ${e.filter.name}`}
name={e.filter.name}
/>
);
case 'Sort':
return (
<SortFilter
key={`filters ${e.filter.name}`}
name={e.filter.name}
values={e.filter.values}
state={e.filter.state as IState}
position={index}
group={group}
updateFilterValue={updateFilterValue}
/>
);
case 'Text':
return (
<TextFilter
key={`filters ${e.filter.name}`}
name={e.filter.name}
state={e.filter.state as string}
position={index}
group={group}
updateFilterValue={updateFilterValue}
/>
);
case 'TriState':
return (
<TriStateFilter
key={`filters ${e.filter.name}`}
name={e.filter.name}
state={e.filter.state as number}
position={index}
group={group}
updateFilterValue={updateFilterValue}
/>
);
default:
return (<Box key={`${e.filter.name}null`} />);
}
})}
</Box>
);
}

export default function SourceOptions({
sourceFilter,
updateFilterValue,
resetFilterValue,
setTriggerUpdate,
setSearch,
}: IFilters1) {
const [FilterOptions, setFilterOptions] = React.useState(false);

function handleReset() {
resetFilterValue(0);
setFilterOptions(false);
}

function handleSubmit() {
setTriggerUpdate(0);
setSearch(true);
setFilterOptions(false);
}

return (
<>
<Fab
sx={{ position: 'fixed', bottom: '2em', right: '3em' }}
onClick={() => setFilterOptions(!FilterOptions)}
variant="extended"
color="primary"
>
<FilterListIcon />
Filter
</Fab>

<Drawer
anchor="bottom"
open={FilterOptions}
onClose={() => setFilterOptions(false)}
PaperProps={{
style: {
maxWidth: 600, padding: '1em', marginLeft: 'auto', marginRight: 'auto',
},
}}
>
<Box sx={{ display: 'flex' }}>
<Button
onClick={handleReset}
>
Reset
</Button>
<Button
sx={{ marginLeft: 'auto' }}
variant="contained"
onClick={handleSubmit}
>
Submit
</Button>
</Box>
<Options
sourceFilter={sourceFilter}
updateFilterValue={updateFilterValue}
group={undefined}
/>
</Drawer>
</>
);
}
53 changes: 53 additions & 0 deletions src/components/source/filters/CheckBoxFilter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* Copyright (C) Contributors to the Suwayomi project
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
import React from 'react';
import { Box } from '@mui/system';
import { Checkbox, FormControlLabel } from '@mui/material';

interface Props {
state: boolean
name: string
position: number
group: number | undefined
updateFilterValue: Function
}

export default function CheckBoxFilter(props: Props) {
const {
state,
name,
position,
group,
updateFilterValue,
} = props;
const [val, setval] = React.useState(state);

const handleChange = (event: { target: { name: any; checked: any; }; }) => {
setval(event.target.checked);
updateFilterValue({ position, state: event.target.checked.toString(), group });
};

if (state !== undefined) {
return (
<Box sx={{ display: 'flex', flexDirection: 'column', minWidth: 120 }}>
<FormControlLabel
key={name}
control={(
<Checkbox
name={name}
checked={val}
onChange={handleChange}
/>
)}
label={name}
/>
</Box>
);
}
return (<></>);
}
Loading