Issue #16: Grid en search y recomended

This commit is contained in:
Daniel Cortes
2020-06-19 14:04:04 -04:00
parent 3bf86c74da
commit 8ed4ad16e1
7 changed files with 258 additions and 229 deletions

15
src/components/Grid.jsx Normal file
View File

@@ -0,0 +1,15 @@
import React from 'react';
import './Grid.scss';
export const Col = (props) => {
return <div className="col">{props.children}</div>
}
export const Row = (props) => {
return <div className="row">{props.children}</div>
}
export const Grid = (props) => {
return <div className="grid">{props.children}</div>
}

View File

@@ -1,5 +1,5 @@
.grid { .grid {
--gutter: 1em; --gutter: 1rem;
width: 100%; width: 100%;
.row { .row {

View File

@@ -1,7 +1,4 @@
.searchbar { .searchbar {
margin-bottom: 2em;
margin-top: 1em;
input { input {
border: var(--line-width) solid var(--accent); border: var(--line-width) solid var(--accent);
border-right: none; border-right: none;

View File

@@ -4,7 +4,6 @@ import ReactDOM from 'react-dom';
import './styles/reset.css'; import './styles/reset.css';
import './styles/main.scss'; import './styles/main.scss';
import './styles/grid.scss';
import './styles/tabs.scss'; import './styles/tabs.scss';
import {Nav} from "./components/Nav"; import {Nav} from "./components/Nav";

View File

@@ -2,10 +2,10 @@ ul.tabs {
display: flex; display: flex;
align-items: stretch; align-items: stretch;
border-bottom: var(--line-width) var(--gray-1) solid; border-bottom: var(--line-width) var(--gray-1) solid;
margin: 1rem 0; margin-top: 1em;
li.tab { li.tab {
padding: .5rem 1em; padding: .5em 1em;
margin-bottom: -2px; margin-bottom: -2px;
cursor: pointer; cursor: pointer;

View File

@@ -5,6 +5,7 @@ import {getArtist, getDisc, getSong} from '../services/entity_service';
import {EntityList} from '../components/EntityList'; import {EntityList} from '../components/EntityList';
import {CoverArt} from '../components/CoverArt'; import {CoverArt} from '../components/CoverArt';
import {Grid, Row, Col} from '../components/Grid';
const PopularArtists = () => { const PopularArtists = () => {
const artistIDs = ['fa3b825f-7c85-4377-b393-d28a2016e293', 'b2d122f9-eadb-4930-a196-8f221eeb0c66', const artistIDs = ['fa3b825f-7c85-4377-b393-d28a2016e293', 'b2d122f9-eadb-4930-a196-8f221eeb0c66',
@@ -91,23 +92,23 @@ export const Recomended = () => {
// TODO crear una forma de obtener cosas populares // TODO crear una forma de obtener cosas populares
// Esto es un por mientras hago todo el resto y la pagina de inicio no se vea tan vacia // Esto es un por mientras hago todo el resto y la pagina de inicio no se vea tan vacia
return ( return (
<div class='grid'> <Grid>
<div class='row'> <Row>
<div class='col'> <Col>
<h3>Artistas Populares</h3> <h3>Artistas Populares</h3>
<PopularArtists/> <PopularArtists/>
</div> </Col>
<div class='col'> <Col>
<h3>Canciones Populares</h3> <h3>Canciones Populares</h3>
<PopularSongs/> <PopularSongs/>
</div> </Col>
</div> </Row>
<div className="row"> <Row>
<div className="col"> <Col>
<h3>Discos Populares</h3> <h3>Discos Populares</h3>
<PopularDiscs/> <PopularDiscs/>
</div> </Col>
</div> </Row>
</div> </Grid>
) )
} }

View File

@@ -8,269 +8,286 @@ import {SearchBar} from "../components/SearchBar";
import {Paginate} from "../components/Paginate"; import {Paginate} from "../components/Paginate";
import {CoverArt} from "../components/CoverArt"; import {CoverArt} from "../components/CoverArt";
import {EntityList} from "../components/EntityList"; import {EntityList} from "../components/EntityList";
import {Grid, Col, Row} from '../components/Grid';
const SearchSongs = (props) => { const SearchSongs = (props) => {
const [songs, setSongs] = useState(null); const [songs, setSongs] = useState(null);
const [paginate, setPaginate] = useState(null); const [paginate, setPaginate] = useState(null);
const [page, setPage] = useState(props.page ? props.page : 1); const [page, setPage] = useState(props.page ? props.page : 1);
useEffect(() => { useEffect(() => {
setSongs(null); setSongs(null);
setPaginate(null); setPaginate(null);
loadSongs(props.query, page) loadSongs(props.query, page)
}, [props.query, page]); }, [props.query, page]);
const makeLink = page => `/search/song?query=${props.query}&page=${page}`; const makeLink = page => `/search/song?query=${props.query}&page=${page}`;
const handlePageChange = page => { const handlePageChange = page => {
setSongs(null); setSongs(null);
setPage(page); setPage(page);
props.onPageChange(page); props.onPageChange(page);
} }
const loadSongs = (query, page) => { const loadSongs = (query, page) => {
page = page ? page : 1; page = page ? page : 1;
searchSong(query, page).then((response) => { searchSong(query, page).then((response) => {
setSongs(response.recordings); setSongs(response.recordings);
setPaginate(response.paginate); setPaginate(response.paginate);
}) })
}; };
let songsComponent = <EntityList placeholder={true} size={10}/>; let songsComponent = <EntityList placeholder={true} size={10}/>;
if (songs) { if (songs) {
const items = songs.map((song) => { const items = songs.map((song) => {
return { return {
'cover': null, 'cover': null,
'link': `/song/${song.id}`, 'link': `/song/${song.id}`,
'title': song.title, 'title': song.title,
'subtitle': song.artist.name 'subtitle': song.artist.name
}; };
}); });
const list = [{ const list = [{
'items': items 'items': items
}] }]
songsComponent = <EntityList list={list}/> songsComponent = <EntityList list={list}/>
} }
let paginateComponent; let paginateComponent;
if (paginate) { if (paginate) {
const total = paginate.total; const total = paginate.total;
const currentPage = paginate.current_page; const currentPage = paginate.current_page;
const pageLimit = paginate.per_page; const pageLimit = paginate.per_page;
paginateComponent = <Paginate totalRecords={total} pageLimit={pageLimit} currentPage={currentPage} pageNeighbours={2} onPageChanged={handlePageChange} makeLink={makeLink}/> paginateComponent = <Paginate totalRecords={total} pageLimit={pageLimit} currentPage={currentPage} pageNeighbours={2} onPageChanged={handlePageChange} makeLink={makeLink}/>
} }
return ( return (
<Fragment> <Fragment>
<ul className='entity_list'> <ul className='entity_list'>
{songsComponent} {songsComponent}
</ul> </ul>
{paginateComponent} {paginateComponent}
</Fragment> </Fragment>
) )
} }
const SearchDiscs = (props) => { const SearchDiscs = (props) => {
const [discs, setDiscs] = useState(null); const [discs, setDiscs] = useState(null);
const [paginate, setPaginate] = useState(null); const [paginate, setPaginate] = useState(null);
const [page, setPage] = useState(null); const [page, setPage] = useState(null);
useEffect(_ => { useEffect(_ => {
setDiscs(null) setDiscs(null)
setPaginate(null) setPaginate(null)
loadDiscs(props.query, page) loadDiscs(props.query, page)
}, [props.query, page]) }, [props.query, page])
const makeLink = page => `/search/disc?query=${props.query}&page=${page}`; const makeLink = page => `/search/disc?query=${props.query}&page=${page}`;
const handlePageChange = page => { const handlePageChange = page => {
setDiscs(null); setDiscs(null);
setPage(page); setPage(page);
props.onPageChange(page); props.onPageChange(page);
} }
const loadDiscs = (query, page) => { const loadDiscs = (query, page) => {
page = page ? page : 1; page = page ? page : 1;
searchDisc(query, page, 16).then((response) => { searchDisc(query, page, 16).then((response) => {
setDiscs(response.discs); setDiscs(response.discs);
setPaginate(response.paginate); setPaginate(response.paginate);
}) })
}; };
let discsComponent = <EntityList placeholder={true} grid={true} size={16} cover={true}/>; let discsComponent = <EntityList placeholder={true} grid={true} size={16} cover={true}/>;
if (discs) { if (discs) {
const items = discs.map((disc) => ({ const items = discs.map((disc) => ({
'cover': <CoverArt disc={disc} size={3}/>, 'cover': <CoverArt disc={disc} size={3}/>,
'link': `/disc/${disc.id}`, 'link': `/disc/${disc.id}`,
'title': disc.title, 'title': disc.title,
'subtitle': disc.artist.name 'subtitle': disc.artist.name
})); }));
const list = [{ const list = [{
'items': items 'items': items
}] }]
discsComponent = <EntityList list={list} grid={true}/> discsComponent = <EntityList list={list} grid={true}/>
} }
let paginateComponent; let paginateComponent;
if (paginate) { if (paginate) {
const total = paginate.total; const total = paginate.total;
const currentPage = paginate.current_page; const currentPage = paginate.current_page;
const pageLimit = paginate.per_page; const pageLimit = paginate.per_page;
paginateComponent = <Paginate totalRecords={total} pageLimit={pageLimit} currentPage={currentPage} pageNeighbours={2} onPageChanged={handlePageChange} makeLink={makeLink}/> paginateComponent = <Paginate totalRecords={total} pageLimit={pageLimit} currentPage={currentPage} pageNeighbours={2} onPageChanged={handlePageChange} makeLink={makeLink}/>
} }
return ( return (
<Fragment> <Fragment>
<ul className='entity_list'> <ul className='entity_list'>
{discsComponent} {discsComponent}
</ul> </ul>
{paginateComponent} {paginateComponent}
</Fragment> </Fragment>
) )
} }
const SearchArtists = (props) => { const SearchArtists = (props) => {
const [artists, setArtist] = useState(null); const [artists, setArtist] = useState(null);
const [paginate, setPaginate] = useState(null); const [paginate, setPaginate] = useState(null);
const [page, setPage] = useState(props.page ? props.page : 1); const [page, setPage] = useState(props.page ? props.page : 1);
useEffect(_ => { useEffect(_ => {
setArtist(null) setArtist(null)
setPaginate(null) setPaginate(null)
loadArtists(props.query, page) loadArtists(props.query, page)
}, [props.query, page]) }, [props.query, page])
const makeLink = page => `/search/artist?query=${props.query}&page=${page}`; const makeLink = page => `/search/artist?query=${props.query}&page=${page}`;
const handlePageChange = page => { const handlePageChange = page => {
setArtist(null); setArtist(null);
setPage(page); setPage(page);
props.onPageChange(page); props.onPageChange(page);
} }
const loadArtists = (query, page) => { const loadArtists = (query, page) => {
page = page ? page : 1; page = page ? page : 1;
searchArtist(query, page).then((response) => { searchArtist(query, page).then((response) => {
setArtist(response.artists); setArtist(response.artists);
setPaginate(response.paginate); setPaginate(response.paginate);
}) })
}; };
let artistsContent = <EntityList placeholder={true} size={10}/>; let artistsContent = <EntityList placeholder={true} size={10}/>;
if (artists) { if (artists) {
const items = artists.map((artist) => ({ const items = artists.map((artist) => ({
'cover': null, 'cover': null,
'link': `/artist/${artist.id}`, 'link': `/artist/${artist.id}`,
'title': artist.name, 'title': artist.name,
'subtitle': [artist.type, artist.country].filter(Boolean).join(' - ') 'subtitle': [artist.type, artist.country].filter(Boolean).join(' - ')
})); }));
const list = [{ const list = [{
'items': items 'items': items
}]; }];
artistsContent = <EntityList list={list}/> artistsContent = <EntityList list={list}/>
} }
let paginateContent; let paginateContent;
if (paginate) { if (paginate) {
const total = paginate.total; const total = paginate.total;
const currentPage = paginate.current_page; const currentPage = paginate.current_page;
const pageLimit = paginate.per_page; const pageLimit = paginate.per_page;
paginateContent = <Paginate totalRecords={total} pageLimit={pageLimit} currentPage={currentPage} pageNeighbours={2} onPageChanged={handlePageChange} makeLink={makeLink}/> paginateContent = <Paginate totalRecords={total} pageLimit={pageLimit} currentPage={currentPage} pageNeighbours={2} onPageChanged={handlePageChange} makeLink={makeLink}/>
} }
return ( return (
<Fragment> <Grid>
<ul className='entity_list'> <Row>
{artistsContent} <Col>
</ul> <ul className='entity_list'>
{paginateContent} {artistsContent}
</Fragment> </ul>
) </Col>
</Row>
<Row>
<Col>
{paginateContent}
</Col>
</Row>
</Grid>
)
} }
const SearchTabs = (props) => { const SearchTabs = (props) => {
const nameToIndex = (name) => { const nameToIndex = (name) => {
if (name === 'artist') return 0 if (name === 'artist') return 0
if (name === 'disc') return 1 if (name === 'disc') return 1
if (name === 'song') return 2 if (name === 'song') return 2
else return 0; else return 0;
} }
const indexToName = (index) => { const indexToName = (index) => {
if (index === 0) return 'artist' if (index === 0) return 'artist'
if (index === 1) return 'disc' if (index === 1) return 'disc'
if (index === 2) return 'song' if (index === 2) return 'song'
else return 'artist'; else return 'artist';
} }
const handleSelect = (index) => { const handleSelect = (index) => {
props.onTabChanged(indexToName(index)) props.onTabChanged(indexToName(index))
} }
const handlePageChange = (who) => (index) => props.onPageChange(who, index); const handlePageChange = (who) => (index) => props.onPageChange(who, index);
return ( return (
<Tabs selectedIndex={nameToIndex(props.selected)} onSelect={handleSelect}> <Tabs selectedIndex={nameToIndex(props.selected)} onSelect={handleSelect}>
<TabList className='tabs'> <TabList className='tabs'>
<Tab className='tab' selectedClassName='selected'>Artistas</Tab> <Tab className='tab' selectedClassName='selected'>Artistas</Tab>
<Tab className='tab' selectedClassName='selected'>Discos</Tab> <Tab className='tab' selectedClassName='selected'>Discos</Tab>
<Tab className='tab' selectedClassName='selected'>Canciones</Tab> <Tab className='tab' selectedClassName='selected'>Canciones</Tab>
</TabList> </TabList>
<TabPanel><SearchArtists query={props.query} page={props.page} onPageChange={handlePageChange('artist')}/></TabPanel> <TabPanel><SearchArtists query={props.query} page={props.page} onPageChange={handlePageChange('artist')}/></TabPanel>
<TabPanel><SearchDiscs query={props.query} page={props.page} onPageChange={handlePageChange('disc')}/></TabPanel> <TabPanel><SearchDiscs query={props.query} page={props.page} onPageChange={handlePageChange('disc')}/></TabPanel>
<TabPanel><SearchSongs query={props.query} page={props.page} onPageChange={handlePageChange('song')}/></TabPanel> <TabPanel><SearchSongs query={props.query} page={props.page} onPageChange={handlePageChange('song')}/></TabPanel>
</Tabs> </Tabs>
) )
} }
export const Search = (props) => { export const Search = (props) => {
const parsedParams = queryString.parse(props.location.search); const parsedParams = queryString.parse(props.location.search);
const [who, setWho] = useState(props.match.params['who'] ? props.match.params['who'] : 'artist') const [who, setWho] = useState(props.match.params['who'] ? props.match.params['who'] : 'artist')
const [query, setQuery] = useState(parsedParams.query) const [query, setQuery] = useState(parsedParams.query)
const [page, setPage] = useState(!isNaN(+parsedParams.page) ? +parsedParams.page : 1) const [page, setPage] = useState(!isNaN(+parsedParams.page) ? +parsedParams.page : 1)
const navigateTo = (who, query, page) => props.history.push(`/search/${who}?query=${query}&page=${page}`); const navigateTo = (who, query, page) => props.history.push(`/search/${who}?query=${query}&page=${page}`);
const handleQueryChange = query => { const handleQueryChange = query => {
setQuery(query); setQuery(query);
setPage(1); setPage(1);
navigateTo(who, query, 1) navigateTo(who, query, 1)
}; };
const handleTabChange = who => { const handleTabChange = who => {
setWho(who); setWho(who);
setPage(1) setPage(1)
navigateTo(who, query, 1) navigateTo(who, query, 1)
}; };
const handlePageChange = (who, page) => { const handlePageChange = (who, page) => {
setWho(who); setWho(who);
setPage(page); setPage(page);
navigateTo(who, query, page); navigateTo(who, query, page);
}; };
const content = _ => { const content = (() => {
if (query) { if (query) {
return <SearchTabs query={query} onTabChanged={handleTabChange} onPageChange={handlePageChange} selected={who} page={page}/> return <SearchTabs query={query} onTabChanged={handleTabChange} onPageChange={handlePageChange} selected={who} page={page}/>
} else { } else {
return null; return null;
}
} }
})();
return ( return (
<Fragment> <Grid>
<h1>Búsqueda</h1> <Row><Col><h1>Búsqueda</h1></Col></Row>
<SearchBar query={query} onQueryChanged={handleQueryChange} history={props.history}/> <Row>
{content()} <Col>
</Fragment> <SearchBar query={query} onQueryChanged={handleQueryChange} history={props.history}/>
); </Col>
</Row>
<Row>
<Col>
{content}
</Col>
</Row>
</Grid>
);
} }