Skip to content
Snippets Groups Projects
Commit 2c46b2e5 authored by 희원 전's avatar 희원 전
Browse files

doing Favorites

parent 5435307c
Branches
No related tags found
No related merge requests found
Pipeline #7878 passed
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
"dependencies": { "dependencies": {
"@emotion/react": "^11.9.3", "@emotion/react": "^11.9.3",
"@emotion/styled": "^11.9.3", "@emotion/styled": "^11.9.3",
"@mui/icons-material": "^5.13.7",
"@mui/material": "^5.8.6" "@mui/material": "^5.8.6"
}, },
"devDependencies": { "devDependencies": {
......
import React from 'react'; import React from 'react';
import Typography from '@mui/material/Typography'; import {Box, Tab, Tabs, Typography, AppBar, CssBaseline} from '@mui/material';
import MusicList from './MusicList';
import music_list from './data';
import SearchPage from './SearchPage';
import Favorites from './Favorites';
export default function App () { export default function App () {
return <Typography variant="h1">Hello World</Typography> const [currentTab, setCurrentTab] = React.useState(0);
const [searchResult, setSearchResult] = React.useState([]);
const handleTabChange = (event, newValue) => {
setCurrentTab(newValue);
}
return (
<React.Fragment>
<AppBar position='fixed'>
<Typography align='center' variant="h3" color='inherit'>Heewon Jeon</Typography>
</AppBar>
<div style={{height: 60, width: '100%'}}></div>
<Box sx={{borderBottom: 1, borderColor: 'divider'}}>
<Tabs value={currentTab} onChange={handleTabChange} aria-label='basic tabs' centered>
<Tab label="Search Music" value={0}/>
<Tab label="Favorites" value={1}/>
<Tab label="More Contents" value={2}/>
</Tabs>
</Box>
{currentTab == 0 && <SearchPage list={searchResult} onSearch={setSearchResult} />}
{currentTab == 1 && <Typography align='center' variant='h2'>Favorites</Typography>}
{currentTab == 2 && <Typography align='center' variant='h2'>Item Three</Typography>}
</React.Fragment>
)
} }
import React, { useState } from 'react';
import MusicList from './MusicList';
const Favorites = () => {
const [favoriteSongs, setFavoriteSongs] = useState([]);
const handleToggleFavorite = (id) => {
if (favoriteSongs.includes(id)) {
setFavoriteSongs(favoriteSongs.filter((songId) => songId !== id));
} else {
setFavoriteSongs([...favoriteSongs, id]);
}
};
const filteredList = musicList.filter((song) =>
favoriteSongs.includes(song.collectionName)
);
return (
<div>
<h2>Favorites</h2>
{filteredList.length === 0 ? (
<p>No favorite songs.</p>
) : (
<MusicList list={filteredList} toggleFavorite={handleToggleFavorite} />
)}
</div>
);
};
export default Favorites;
\ No newline at end of file
import React from "react";
import {Card, CardContent, CardActions, Typography, IconButton} from '@mui/material';
import {Favorite, FavoriteBorder} from '@mui/icons-material';
import SnackMsg from "./SnackMsg";
const styles = {
content: {},
layout: {
display: 'flex',
justifyContent: 'center'
},
card: {
minWidth: 275,
maxWidth: 600,
marginBottom: "20pt",
marginLeft: 'auto',
marginRight: 'auto'
},
};
export default function MusicList ({list}) {
const [likes, setLikes] = React.useState({});
let [snackState, setSnackState] = React.useState({open: false, msg: ''});
const toggleFavorite = (id) => () => {
setLikes({...likes, [id] : !likes[id]});
setSnackState({...snackState, open: true, msg: `${id} is clicked`});
}
const handleSnackbarClose = (event, reason) => {
if (reason == 'clickaway') {
return;
}
setSnackState({open: false, msg: ''});
}
return (
<div>
{list.map(item => {
return (
<Card sx={styles.card} key={item.collectionName}>
<CardContent>
<Typography variant="subtitle1"> {item.artistName} </Typography>
<Typography variant="subtitle2"> {item.collectionCensoredName} </Typography>
</CardContent>
<CardActions>
<IconButton onClick={toggleFavorite(item.collectionName)}>
{(likes[item.collectionName] === true) ? <Favorite/> : <FavoriteBorder/>}
</IconButton>
</CardActions>
</Card>
)
})}
<SnackMsg open = {snackState.open} message={snackState.msg}
onClose={handleSnackbarClose}/>
</div>
)
}
\ No newline at end of file
import React from "react";
import { Button, TextField } from "@mui/material";
import MusicList from "./MusicList";
import music_list from "./data";
export default function SearchPage ({list, onSearch}) {
const [searchWord, setSearchWord] = React.useState('');
const handleSearch = (event) => {
event.preventDefault();
console.log(searchWord);
setSearchWord('');
fetch (`http://itunes.apple.com/search?term=${searchWord}&entity=album`)
.then(r => r.json()).then(r => {
console.log(r);
onSearch(r.results);
setSearchWord('');
}).catch(e => console.log('error when search musician'));
}
const handleSearchTextChange = (event) => {
setSearchWord(event.target.value);
}
return (
<React.Fragment>
<form style={{display: 'flex', marginTop: 20, marginBottom: 15}}>
<div style={{display: 'flex', marginLeft: 'auto', marginRight: 'auto'}}>
<TextField variant="outlined" label="Music Album Search" type="search" style={{width: 450}}
onChange={handleSearchTextChange} value={searchWord}>
</TextField>
<Button variant="contained" color="primary"
type="submit" onClick={handleSearch}
style={{marginLeft: 20}}>
Search
</Button>
</div>
</form>
<MusicList list={list}></MusicList>
</React.Fragment>
)
}
import React from "react";
import { Alert, Snackbar } from "@mui/material";
const SnackMsg = (props) => {
return (
<Snackbar
open={props.open}
anchorOrigin={{vertical: 'bottom', horizontal: 'right'}}
autoHideDuration={3000}
onClose={props.onClose}
message={props.message}>
</Snackbar>
);
}
export default SnackMsg;
\ No newline at end of file
This diff is collapsed.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment