Adding Cart page
This commit is contained in:
@@ -7,7 +7,7 @@ import { store, persistor } from "./services/store";
|
||||
import PosterSelector from "./components/PosterSelector";
|
||||
import PosterGallery from "./components/PosterGallery";
|
||||
import UploadDiary from "./components/UploadDiary";
|
||||
import GlobalDownloadButton from "./components/DownloadButton";
|
||||
import Cart from "./components/Cart";
|
||||
|
||||
function App() {
|
||||
return (
|
||||
@@ -23,11 +23,11 @@ function App() {
|
||||
path="/posters/:movieName/:movieYear"
|
||||
element={<PosterGallery />}
|
||||
/>
|
||||
<Route path="/Cart" element={<Cart />} />
|
||||
</Routes>
|
||||
</div>
|
||||
</Router>
|
||||
}
|
||||
<GlobalDownloadButton />
|
||||
</PersistGate>
|
||||
</Provider>
|
||||
);
|
||||
|
||||
239
src/components/Cart.js
Normal file
239
src/components/Cart.js
Normal file
@@ -0,0 +1,239 @@
|
||||
import React, { useState } from 'react';
|
||||
import { useSelector, useDispatch } from 'react-redux';
|
||||
import {
|
||||
Container, Typography, Card, CardMedia, CardContent,
|
||||
Button, Checkbox, FormControlLabel, TextField, Dialog, DialogTitle, DialogContent, DialogActions,
|
||||
Paper
|
||||
} from '@material-ui/core';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import DeleteIcon from '@material-ui/icons/Delete';
|
||||
import GetAppIcon from '@material-ui/icons/GetApp';
|
||||
import ShareIcon from '@material-ui/icons/Share';
|
||||
import EditIcon from '@material-ui/icons/Edit';
|
||||
import { removePoster } from '../services/action';
|
||||
import axios from "axios";
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
root: {
|
||||
marginTop: theme.spacing(4),
|
||||
marginBottom: theme.spacing(8),
|
||||
display: 'flex',
|
||||
},
|
||||
posterList: {
|
||||
flex: 2,
|
||||
marginRight: theme.spacing(2),
|
||||
maxHeight: 'calc(100vh - 200px)',
|
||||
overflowY: 'auto',
|
||||
},
|
||||
actionPanel: {
|
||||
flex: 1,
|
||||
position: 'sticky',
|
||||
top: theme.spacing(4),
|
||||
height: 'fit-content',
|
||||
},
|
||||
card: {
|
||||
display: 'flex',
|
||||
marginBottom: theme.spacing(2),
|
||||
backgroundColor: '#2c3e50',
|
||||
},
|
||||
cardMedia: {
|
||||
width: 100,
|
||||
},
|
||||
cardContent: {
|
||||
flex: '1 0 auto',
|
||||
},
|
||||
actions: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: theme.spacing(2),
|
||||
},
|
||||
slider: {
|
||||
width: '100%',
|
||||
marginTop: theme.spacing(2),
|
||||
},
|
||||
button: {
|
||||
width: '100%',
|
||||
},
|
||||
typography: {
|
||||
color: '#ecf0f1',
|
||||
},
|
||||
formControl: {
|
||||
marginBottom: theme.spacing(2),
|
||||
},
|
||||
checkbox: {
|
||||
color: '#3498db',
|
||||
},
|
||||
paper: {
|
||||
padding: theme.spacing(3),
|
||||
backgroundColor: '#34495e',
|
||||
},
|
||||
}));
|
||||
|
||||
const Cart = () => {
|
||||
const classes = useStyles();
|
||||
const dispatch = useDispatch();
|
||||
const selectedPosters = useSelector((state) => {
|
||||
const selections = state.posterSelections;
|
||||
return Object.entries(selections).flatMap(([movieId, posters]) =>
|
||||
posters.map(posterId => ({ movieId, posterId }))
|
||||
);
|
||||
});
|
||||
|
||||
const [selectedForDownload, setSelectedForDownload] = useState(selectedPosters.map(() => true));
|
||||
const [downloadFormat, setDownloadFormat] = useState('zip');
|
||||
const [renameDialogOpen, setRenameDialogOpen] = useState(false);
|
||||
const [currentPosterIndex, setCurrentPosterIndex] = useState(null);
|
||||
const [newPosterName, setNewPosterName] = useState('');
|
||||
|
||||
const handleRemovePoster = (index) => {
|
||||
dispatch(removePoster(selectedPosters[index].movieId, selectedPosters[index].posterId));
|
||||
};
|
||||
|
||||
const handleDownload = async () => {
|
||||
const postersToDownload = selectedPosters
|
||||
.filter((_, index) => selectedForDownload[index])
|
||||
.map((poster) => ({
|
||||
movieId: poster.movieId,
|
||||
posterId: poster.posterId,
|
||||
movieName: poster.movieName,
|
||||
movieYear: poster.movieYear
|
||||
}));
|
||||
|
||||
console.log('Downloading posters:', postersToDownload);
|
||||
|
||||
try {
|
||||
const response = await axios.post('http://localhost:5000/api/download-posters', {
|
||||
posters: postersToDownload,
|
||||
format: downloadFormat,
|
||||
}, {
|
||||
responseType: 'blob',
|
||||
});
|
||||
|
||||
const blob = new Blob([response.data], { type: response.headers['content-type'] });
|
||||
const link = document.createElement('a');
|
||||
link.href = window.URL.createObjectURL(blob);
|
||||
link.download = `posters.${downloadFormat}`;
|
||||
link.click();
|
||||
} catch (error) {
|
||||
console.error('Failed to download posters:', error);
|
||||
}
|
||||
};
|
||||
|
||||
const handleShare = () => {
|
||||
console.log('Sharing selected posters');
|
||||
};
|
||||
|
||||
const handleRename = (index) => {
|
||||
setCurrentPosterIndex(index);
|
||||
setNewPosterName(selectedPosters[index].posterId);
|
||||
setRenameDialogOpen(true);
|
||||
};
|
||||
|
||||
const handleRenameConfirm = () => {
|
||||
console.log(`Renaming poster ${currentPosterIndex} to ${newPosterName}`);
|
||||
setRenameDialogOpen(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<Container className={classes.root}>
|
||||
<div className={classes.posterList}>
|
||||
<Typography variant="h4" gutterBottom className={classes.typography}>Your Cart</Typography>
|
||||
{selectedPosters.map((poster, index) => (
|
||||
<Card key={index} className={classes.card}>
|
||||
<CardMedia
|
||||
className={classes.cardMedia}
|
||||
image={`https://image.tmdb.org/t/p/w500${poster.posterId}`}
|
||||
title={`Poster ${index + 1}`}
|
||||
/>
|
||||
<CardContent className={classes.cardContent}>
|
||||
<Typography variant="h6"
|
||||
className={classes.typography}>{`Movie ID: ${poster.movieId}`}</Typography>
|
||||
<Typography variant="body2"
|
||||
className={classes.typography}>{poster.posterId}</Typography>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
checked={selectedForDownload[index]}
|
||||
onChange={(e) => {
|
||||
const newSelected = [...selectedForDownload];
|
||||
newSelected[index] = e.target.checked;
|
||||
setSelectedForDownload(newSelected);
|
||||
}}
|
||||
className={classes.checkbox}
|
||||
/>
|
||||
}
|
||||
label="Select for download"
|
||||
className={classes.typography}
|
||||
/>
|
||||
<Button startIcon={<DeleteIcon/>} onClick={() => handleRemovePoster(index)}
|
||||
className={classes.typography}>Remove</Button>
|
||||
<Button startIcon={<EditIcon/>} onClick={() => handleRename(index)}
|
||||
className={classes.typography}>Rename</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
<Paper className={classes.actionPanel} elevation={3}>
|
||||
<div className={classes.actions}>
|
||||
<Typography gutterBottom>Download Format</Typography>
|
||||
<TextField
|
||||
select
|
||||
value={downloadFormat}
|
||||
onChange={(e) => setDownloadFormat(e.target.value)}
|
||||
SelectProps={{
|
||||
native: true,
|
||||
}}
|
||||
className={classes.formControl}
|
||||
>
|
||||
<option value="zip">ZIP</option>
|
||||
<option value="tar">TAR</option>
|
||||
<option value="7z">7Z</option>
|
||||
</TextField>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
startIcon={<GetAppIcon/>}
|
||||
onClick={handleDownload}
|
||||
disabled={selectedForDownload.every((selected) => !selected)}
|
||||
className={classes.button}
|
||||
>
|
||||
Download Selected
|
||||
</Button>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="secondary"
|
||||
startIcon={<ShareIcon/>}
|
||||
onClick={handleShare}
|
||||
className={classes.button}
|
||||
>
|
||||
Share Selection
|
||||
</Button>
|
||||
</div>
|
||||
</Paper>
|
||||
<Dialog open={renameDialogOpen} onClose={() => setRenameDialogOpen(false)}>
|
||||
<DialogTitle>Rename Poster</DialogTitle>
|
||||
<DialogContent>
|
||||
<TextField
|
||||
autoFocus
|
||||
margin="dense"
|
||||
label="New Name"
|
||||
type="text"
|
||||
fullWidth
|
||||
value={newPosterName}
|
||||
onChange={(e) => setNewPosterName(e.target.value)}
|
||||
/>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={() => setRenameDialogOpen(false)} color="primary">
|
||||
Cancel
|
||||
</Button>
|
||||
<Button onClick={handleRenameConfirm} color="primary">
|
||||
Rename
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
|
||||
export default Cart;
|
||||
78
src/components/NavBar.js
Normal file
78
src/components/NavBar.js
Normal file
@@ -0,0 +1,78 @@
|
||||
import React from "react";
|
||||
import { useSelector } from "react-redux";
|
||||
import { AppBar, Toolbar, IconButton, Badge, Button } from '@material-ui/core';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import ShoppingCartIcon from '@material-ui/icons/ShoppingCart';
|
||||
import ArrowBackIcon from '@material-ui/icons/ArrowBack';
|
||||
import { useNavigate, useLocation } from 'react-router-dom';
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
appBar: {
|
||||
top: 'auto',
|
||||
bottom: 0,
|
||||
backgroundColor: '#1c1f23',
|
||||
},
|
||||
toolbar: {
|
||||
justifyContent: 'space-between',
|
||||
},
|
||||
backButton: {
|
||||
color: 'white',
|
||||
},
|
||||
cartButton: {
|
||||
color: 'white',
|
||||
},
|
||||
refreshButton: {
|
||||
color: 'white',
|
||||
marginRight: theme.spacing(2),
|
||||
},
|
||||
}));
|
||||
|
||||
const NavBar = ({onRefreshFiles}) => {
|
||||
const classes = useStyles();
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
const selectedPosters = useSelector((state) => {
|
||||
const selections = state.posterSelections;
|
||||
return Object.values(selections).flat();
|
||||
});
|
||||
|
||||
const totalSelected = selectedPosters.length;
|
||||
|
||||
const handleBack = () => {
|
||||
navigate(-1);
|
||||
};
|
||||
|
||||
const handleCart = () => {
|
||||
navigate('/Cart');
|
||||
};
|
||||
|
||||
const isPosterSelectorPage = location.pathname !== '/PosterSelector';
|
||||
|
||||
return (
|
||||
<AppBar position="fixed" className={classes.appBar}>
|
||||
<Toolbar className={classes.toolbar}>
|
||||
{isPosterSelectorPage ? (
|
||||
<IconButton edge="start" className={classes.backButton} onClick={handleBack}>
|
||||
<ArrowBackIcon />
|
||||
</IconButton>
|
||||
) : (
|
||||
<IconButton edge="start" className={classes.backButton} disabled>
|
||||
{/* Un IconButton vide et désactivé */}
|
||||
</IconButton>
|
||||
)}
|
||||
<div>
|
||||
<Button className={classes.refreshButton} onClick={onRefreshFiles}>
|
||||
Refresh Files
|
||||
</Button>
|
||||
<IconButton edge="end" className={classes.cartButton} onClick={handleCart}>
|
||||
<Badge badgeContent={totalSelected} color="secondary">
|
||||
<ShoppingCartIcon />
|
||||
</Badge>
|
||||
</IconButton>
|
||||
</div>
|
||||
</Toolbar>
|
||||
</AppBar>
|
||||
);
|
||||
};
|
||||
|
||||
export default NavBar;
|
||||
@@ -15,10 +15,12 @@ import {
|
||||
Paper,
|
||||
} from "@material-ui/core";
|
||||
import CheckIcon from "@material-ui/icons/Check";
|
||||
import NavBar from "./NavBar";
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
root: {
|
||||
marginTop: theme.spacing(4),
|
||||
marginBottom: theme.spacing(4),
|
||||
},
|
||||
paper: {
|
||||
padding: theme.spacing(3),
|
||||
@@ -83,6 +85,8 @@ const PosterGallery = ({ movieId }) => {
|
||||
(state) => state.posterSelections[movieId] || []
|
||||
);
|
||||
|
||||
console.log(movieId);
|
||||
|
||||
useEffect(() => {
|
||||
const fetchPosters = async () => {
|
||||
try {
|
||||
@@ -110,42 +114,45 @@ const PosterGallery = ({ movieId }) => {
|
||||
};
|
||||
|
||||
return (
|
||||
<Container className={classes.root}>
|
||||
<Paper elevation={3} className={classes.paper}>
|
||||
<Typography variant="h4" gutterBottom className={classes.title}>
|
||||
Posters for {movieName} ({movieYear})
|
||||
</Typography>
|
||||
{loading ? (
|
||||
<Box className={classes.loadingContainer}>
|
||||
<CircularProgress />
|
||||
</Box>
|
||||
) : (
|
||||
<Grid container spacing={3}>
|
||||
{posters.map((poster, index) => (
|
||||
<Grid item xs={12} sm={6} md={4} lg={3} key={index}>
|
||||
<Card
|
||||
className={`${classes.posterCard} ${
|
||||
selectedPosters.includes(poster.file_path)
|
||||
? classes.selectedPoster
|
||||
: ""
|
||||
}`}
|
||||
onClick={() => handlePosterSelect(poster.file_path)}
|
||||
>
|
||||
<CardMedia
|
||||
className={classes.posterImage}
|
||||
image={`https://image.tmdb.org/t/p/w500${poster.file_path}`}
|
||||
title={`${movieName} poster ${index + 1}`}
|
||||
/>
|
||||
{selectedPosters.includes(poster.file_path) && (
|
||||
<CheckIcon className={classes.checkIcon} />
|
||||
)}
|
||||
</Card>
|
||||
<>
|
||||
<Container className={classes.root}>
|
||||
<Paper elevation={3} className={classes.paper}>
|
||||
<Typography variant="h4" gutterBottom className={classes.title}>
|
||||
Posters for {movieName} ({movieYear})
|
||||
</Typography>
|
||||
{loading ? (
|
||||
<Box className={classes.loadingContainer}>
|
||||
<CircularProgress />
|
||||
</Box>
|
||||
) : (
|
||||
<Grid container spacing={3}>
|
||||
{posters.map((poster, index) => (
|
||||
<Grid item xs={12} sm={6} md={4} lg={3} key={index}>
|
||||
<Card
|
||||
className={`${classes.posterCard} ${
|
||||
selectedPosters.includes(poster.file_path)
|
||||
? classes.selectedPoster
|
||||
: ""
|
||||
}`}
|
||||
onClick={() => handlePosterSelect(poster.file_path)}
|
||||
>
|
||||
<CardMedia
|
||||
className={classes.posterImage}
|
||||
image={`https://image.tmdb.org/t/p/w500${poster.file_path}`}
|
||||
title={`${movieName} poster ${index + 1}`}
|
||||
/>
|
||||
{selectedPosters.includes(poster.file_path) && (
|
||||
<CheckIcon className={classes.checkIcon} />
|
||||
)}
|
||||
</Card>
|
||||
</Grid>
|
||||
))}
|
||||
</Grid>
|
||||
))}
|
||||
</Grid>
|
||||
)}
|
||||
</Paper>
|
||||
</Container>
|
||||
)}
|
||||
</Paper>
|
||||
</Container>
|
||||
<NavBar />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -17,10 +17,12 @@ import Pagination from "@mui/material/Pagination";
|
||||
import { createTheme, ThemeProvider } from "@mui/material/styles";
|
||||
import queryString from "query-string";
|
||||
import pulpGif from "../static/images/pulp.gif";
|
||||
import NavBar from "./NavBar";
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
root: {
|
||||
marginTop: theme.spacing(4),
|
||||
marginBottom: theme.spacing(8),
|
||||
},
|
||||
paper: {
|
||||
padding: theme.spacing(3),
|
||||
@@ -37,7 +39,7 @@ const useStyles = makeStyles((theme) => ({
|
||||
},
|
||||
list: {
|
||||
maxHeight: "800px",
|
||||
minHeight: "1000px",
|
||||
minHeight: "900px",
|
||||
},
|
||||
listItem: {
|
||||
marginBottom: theme.spacing(2),
|
||||
@@ -93,7 +95,7 @@ const useStyles = makeStyles((theme) => ({
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
flexDirection: "column",
|
||||
height: "200px", // Adjust height as needed to keep component size consistent
|
||||
height: "200px",
|
||||
},
|
||||
progressLabel: {
|
||||
marginTop: theme.spacing(2),
|
||||
@@ -186,8 +188,9 @@ const PosterSelector = () => {
|
||||
const parsed = queryString.parse(location.search);
|
||||
const pageNumber = parsed.page ? parseInt(parsed.page, 10) : 1;
|
||||
setPage(pageNumber);
|
||||
fetchMovies(pageNumber);
|
||||
fetchUsername();
|
||||
|
||||
fetchMovies(pageNumber).then(r => console.log(r));
|
||||
// fetchUsername();
|
||||
}, [location.search]);
|
||||
|
||||
const fetchUsername = async () => {
|
||||
@@ -231,7 +234,7 @@ const PosterSelector = () => {
|
||||
navigate(
|
||||
`/posters/${encodeURIComponent(movieName)}/${encodeURIComponent(
|
||||
movieYear
|
||||
)}?page=${page}`
|
||||
)}`
|
||||
);
|
||||
};
|
||||
|
||||
@@ -263,131 +266,127 @@ const PosterSelector = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<Container className={classes.root}>
|
||||
<Paper elevation={3} className={classes.paper}>
|
||||
<Typography variant="h4" gutterBottom className={classes.title}>
|
||||
Your diary
|
||||
</Typography>
|
||||
{username && (
|
||||
<Typography variant="h6" className={classes.username}>
|
||||
Letterboxd User: {username}
|
||||
<>
|
||||
<Container className={classes.root}>
|
||||
<Paper elevation={3} className={classes.paper}>
|
||||
<Typography variant="h4" gutterBottom className={classes.title}>
|
||||
Your diary
|
||||
</Typography>
|
||||
)}
|
||||
{loading ? (
|
||||
<Box className={classes.progressContainer}>
|
||||
<LinearProgress variant="determinate" value={progress} />
|
||||
<Typography className={classes.progressLabel}>
|
||||
Downloading movies...
|
||||
</Typography>
|
||||
</Box>
|
||||
) : movies.length > 0 ? (
|
||||
<>
|
||||
<List className={classes.list}>
|
||||
{movies.map((movie, index) => (
|
||||
<ListItem
|
||||
button
|
||||
key={index}
|
||||
onClick={() => handleMovieClick(movie.Name, movie.Year)}
|
||||
className={classes.listItem}
|
||||
{username && (
|
||||
<Typography variant="h6" className={classes.username}>
|
||||
Letterboxd User: {username}
|
||||
</Typography>
|
||||
)}
|
||||
{loading ? (
|
||||
<Box className={classes.progressContainer}>
|
||||
<LinearProgress variant="determinate" value={progress} />
|
||||
<Typography className={classes.progressLabel}>
|
||||
Downloading movies...
|
||||
</Typography>
|
||||
</Box>
|
||||
) : movies.length > 0 ? (
|
||||
<>
|
||||
<List className={classes.list}>
|
||||
{movies.map((movie, index) => (
|
||||
<ListItem
|
||||
button
|
||||
key={index}
|
||||
onClick={() => handleMovieClick(movie.Name, movie.Year)}
|
||||
className={classes.listItem}
|
||||
>
|
||||
<Grid container alignItems="center">
|
||||
<Grid item>
|
||||
<img
|
||||
src={
|
||||
`https://image.tmdb.org/t/p/w500${movie.Poster.file_path}` ||
|
||||
`/api/placeholder/50/75`
|
||||
}
|
||||
alt={movie.Name}
|
||||
className={classes.poster}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item className={classes.movieInfo}>
|
||||
<Typography
|
||||
variant="subtitle1"
|
||||
className={classes.movieTitle}
|
||||
>
|
||||
{movie.Name}
|
||||
</Typography>
|
||||
<Typography
|
||||
variant="body2"
|
||||
color="textSecondary"
|
||||
className={classes.movieYear}
|
||||
>
|
||||
{movie.Year}
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<Box className={classes.watchedDate}>
|
||||
{(() => {
|
||||
const { day, month } = formatWatchedDate(
|
||||
movie["Watched Date"]
|
||||
);
|
||||
return (
|
||||
<>
|
||||
<Typography
|
||||
variant="body2"
|
||||
className={classes.watchedDay}
|
||||
>
|
||||
{day}
|
||||
</Typography>
|
||||
<Typography
|
||||
variant="body2"
|
||||
className={classes.watchedMonth}
|
||||
>
|
||||
{month}
|
||||
</Typography>
|
||||
</>
|
||||
);
|
||||
})()}
|
||||
</Box>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</ListItem>
|
||||
))}
|
||||
</List>
|
||||
<Box className={classes.paginationContainer}>
|
||||
<ThemeProvider theme={paginationTheme}>
|
||||
<Pagination
|
||||
count={totalPages}
|
||||
page={page}
|
||||
onChange={handlePageChange}
|
||||
color="primary"
|
||||
/>
|
||||
</ThemeProvider>
|
||||
</Box>
|
||||
</>
|
||||
) : (
|
||||
<Box className={classes.noMoviesContainer}>
|
||||
<div className={classes.gifContainer}>
|
||||
<div className={classes.circleBackground}></div>
|
||||
<img
|
||||
src={pulpGif}
|
||||
alt="Confused reaction"
|
||||
className={classes.gif}
|
||||
/>
|
||||
</div>
|
||||
<Typography variant="body1" gutterBottom>
|
||||
No movies found in your diary. Please check your Letterboxd
|
||||
username or CSV file.
|
||||
</Typography>
|
||||
<Button
|
||||
variant="contained"
|
||||
className={classes.backButton}
|
||||
onClick={handleGoBack}
|
||||
>
|
||||
<Grid container alignItems="center">
|
||||
<Grid item>
|
||||
<img
|
||||
src={
|
||||
`https://image.tmdb.org/t/p/w500${movie.Poster.file_path}` ||
|
||||
`/api/placeholder/50/75`
|
||||
}
|
||||
alt={movie.Name}
|
||||
className={classes.poster}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item className={classes.movieInfo}>
|
||||
<Typography
|
||||
variant="subtitle1"
|
||||
className={classes.movieTitle}
|
||||
>
|
||||
{movie.Name}
|
||||
</Typography>
|
||||
<Typography
|
||||
variant="body2"
|
||||
color="textSecondary"
|
||||
className={classes.movieYear}
|
||||
>
|
||||
{movie.Year}
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<Box className={classes.watchedDate}>
|
||||
{(() => {
|
||||
const { day, month } = formatWatchedDate(
|
||||
movie["Watched Date"]
|
||||
);
|
||||
return (
|
||||
<>
|
||||
<Typography
|
||||
variant="body2"
|
||||
className={classes.watchedDay}
|
||||
>
|
||||
{day}
|
||||
</Typography>
|
||||
<Typography
|
||||
variant="body2"
|
||||
className={classes.watchedMonth}
|
||||
>
|
||||
{month}
|
||||
</Typography>
|
||||
</>
|
||||
);
|
||||
})()}
|
||||
</Box>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</ListItem>
|
||||
))}
|
||||
</List>
|
||||
<Box className={classes.paginationContainer}>
|
||||
<ThemeProvider theme={paginationTheme}>
|
||||
<Pagination
|
||||
count={totalPages}
|
||||
page={page}
|
||||
onChange={handlePageChange}
|
||||
color="primary"
|
||||
/>
|
||||
</ThemeProvider>
|
||||
</Box>
|
||||
<Button
|
||||
variant="contained"
|
||||
className={classes.refreshButton}
|
||||
onClick={handleRefreshFiles}
|
||||
>
|
||||
Refresh File
|
||||
</Button>
|
||||
</>
|
||||
) : (
|
||||
<Box className={classes.noMoviesContainer}>
|
||||
<div className={classes.gifContainer}>
|
||||
<div className={classes.circleBackground}></div>
|
||||
<img
|
||||
src={pulpGif}
|
||||
alt="Confused reaction"
|
||||
className={classes.gif}
|
||||
/>
|
||||
</div>
|
||||
<Typography variant="body1" gutterBottom>
|
||||
No movies found in your diary. Please check your Letterboxd
|
||||
username or CSV file.
|
||||
</Typography>
|
||||
<Button
|
||||
variant="contained"
|
||||
className={classes.backButton}
|
||||
onClick={handleGoBack}
|
||||
>
|
||||
Go Back
|
||||
</Button>
|
||||
</Box>
|
||||
)}
|
||||
</Paper>
|
||||
</Container>
|
||||
Go Back
|
||||
</Button>
|
||||
</Box>
|
||||
)}
|
||||
</Paper>
|
||||
</Container>
|
||||
<NavBar onRefreshFiles={handleRefreshFiles} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -9,3 +9,9 @@ export const deselectPoster = (movieId, posterId) => ({
|
||||
movieId,
|
||||
posterId,
|
||||
});
|
||||
|
||||
export const removePoster = (movieId, posterId) => ({
|
||||
type: "REMOVE_POSTER",
|
||||
movieId,
|
||||
posterId,
|
||||
});
|
||||
@@ -13,7 +13,14 @@ const posterSelectionReducer = (state = {}, action) => {
|
||||
return {
|
||||
...state,
|
||||
[action.movieId]: state[action.movieId].filter(
|
||||
(id) => id !== action.posterId
|
||||
(id) => id !== action.posterId
|
||||
),
|
||||
};
|
||||
case "REMOVE_POSTER":
|
||||
return {
|
||||
...state,
|
||||
[action.movieId]: state[action.movieId].filter(
|
||||
(id) => id !== action.posterId
|
||||
),
|
||||
};
|
||||
default:
|
||||
|
||||
Reference in New Issue
Block a user