Updated PosterSelector and UploadDiary components

This commit is contained in:
2024-09-14 22:49:14 +02:00
parent 480d47de01
commit 704f1d38c7
3 changed files with 244 additions and 124 deletions

View File

@@ -16,6 +16,7 @@ import {
import Pagination from "@mui/material/Pagination"; import Pagination from "@mui/material/Pagination";
import { createTheme, ThemeProvider } from "@mui/material/styles"; import { createTheme, ThemeProvider } from "@mui/material/styles";
import queryString from "query-string"; import queryString from "query-string";
import pulpGif from "../static/images/pulp.gif";
const useStyles = makeStyles((theme) => ({ const useStyles = makeStyles((theme) => ({
root: { root: {
@@ -25,11 +26,15 @@ const useStyles = makeStyles((theme) => ({
padding: theme.spacing(3), padding: theme.spacing(3),
borderRadius: theme.shape.borderRadius, borderRadius: theme.shape.borderRadius,
backgroundColor: "#1c1f23", backgroundColor: "#1c1f23",
color: "white",
}, },
title: { title: {
color: "white",
marginBottom: theme.spacing(3), marginBottom: theme.spacing(3),
}, },
username: {
color: "#00A346",
marginBottom: theme.spacing(2),
},
list: { list: {
maxHeight: "800px", maxHeight: "800px",
minHeight: "1000px", minHeight: "1000px",
@@ -94,6 +99,44 @@ const useStyles = makeStyles((theme) => ({
marginTop: theme.spacing(2), marginTop: theme.spacing(2),
color: "white", color: "white",
}, },
noMoviesContainer: {
display: "flex",
flexDirection: "column",
alignItems: "center",
justifyContent: "center",
height: "400px",
},
gifContainer: {
display: "flex",
justifyContent: "center",
position: "relative",
width: "200px",
height: "200px",
marginBottom: theme.spacing(2),
},
circleBackground: {
position: "absolute",
width: "120%",
height: "120%",
borderRadius: "50%",
backgroundColor: "#ffffff",
clipPath: "inset(0 0 25% 0)",
bottom: "-28%",
},
gif: {
position: "absolute",
width: "100%",
height: "100%",
objectFit: "contain",
},
backButton: {
marginTop: theme.spacing(2),
backgroundColor: "#00A346",
color: "white",
"&:hover": {
backgroundColor: "#008036",
},
},
})); }));
const paginationTheme = createTheme({ const paginationTheme = createTheme({
@@ -134,6 +177,7 @@ const PosterSelector = () => {
const [page, setPage] = useState(1); const [page, setPage] = useState(1);
const [totalPages, setTotalPages] = useState(1); const [totalPages, setTotalPages] = useState(1);
const [progress, setProgress] = useState(0); const [progress, setProgress] = useState(0);
const [username, setUsername] = useState("");
const navigate = useNavigate(); const navigate = useNavigate();
const location = useLocation(); const location = useLocation();
const moviesPerPage = 10; const moviesPerPage = 10;
@@ -143,8 +187,18 @@ const PosterSelector = () => {
const pageNumber = parsed.page ? parseInt(parsed.page, 10) : 1; const pageNumber = parsed.page ? parseInt(parsed.page, 10) : 1;
setPage(pageNumber); setPage(pageNumber);
fetchMovies(pageNumber); fetchMovies(pageNumber);
fetchUsername();
}, [location.search]); }, [location.search]);
const fetchUsername = async () => {
try {
const response = await axios.get("http://localhost:5000/api/username");
setUsername(response.data.username);
} catch (error) {
console.error("Error fetching username:", error);
}
};
const fetchMovies = async (pageNumber) => { const fetchMovies = async (pageNumber) => {
try { try {
setLoading(true); setLoading(true);
@@ -195,6 +249,10 @@ const PosterSelector = () => {
navigate(`?page=${value}`); navigate(`?page=${value}`);
}; };
const handleGoBack = () => {
navigate("/");
};
const formatWatchedDate = (dateString) => { const formatWatchedDate = (dateString) => {
const date = new Date(dateString); const date = new Date(dateString);
const day = date.getDate().toString().padStart(2, "0"); const day = date.getDate().toString().padStart(2, "0");
@@ -210,6 +268,11 @@ const PosterSelector = () => {
<Typography variant="h4" gutterBottom className={classes.title}> <Typography variant="h4" gutterBottom className={classes.title}>
Your diary Your diary
</Typography> </Typography>
{username && (
<Typography variant="h6" className={classes.username}>
Letterboxd User: {username}
</Typography>
)}
{loading ? ( {loading ? (
<Box className={classes.progressContainer}> <Box className={classes.progressContainer}>
<LinearProgress variant="determinate" value={progress} /> <LinearProgress variant="determinate" value={progress} />
@@ -218,6 +281,7 @@ const PosterSelector = () => {
</Typography> </Typography>
</Box> </Box>
) : movies.length > 0 ? ( ) : movies.length > 0 ? (
<>
<List className={classes.list}> <List className={classes.list}>
{movies.map((movie, index) => ( {movies.map((movie, index) => (
<ListItem <ListItem
@@ -281,13 +345,6 @@ const PosterSelector = () => {
</ListItem> </ListItem>
))} ))}
</List> </List>
) : (
<Box>
<Typography variant="body1" color="textSecondary" gutterBottom>
No movies to display. Upload a CSV file to get started.
</Typography>
</Box>
)}
<Box className={classes.paginationContainer}> <Box className={classes.paginationContainer}>
<ThemeProvider theme={paginationTheme}> <ThemeProvider theme={paginationTheme}>
<Pagination <Pagination
@@ -305,6 +362,30 @@ const PosterSelector = () => {
> >
Refresh File Refresh File
</Button> </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> </Paper>
</Container> </Container>
); );

View File

@@ -6,6 +6,7 @@ import {
Typography, Typography,
Button, Button,
CircularProgress, CircularProgress,
TextField,
makeStyles, makeStyles,
} from "@material-ui/core"; } from "@material-ui/core";
import { CloudUploadOutlined } from "@material-ui/icons"; import { CloudUploadOutlined } from "@material-ui/icons";
@@ -81,12 +82,31 @@ const useStyles = makeStyles((theme) => ({
marginTop: theme.spacing(4), marginTop: theme.spacing(4),
padding: theme.spacing(3), padding: theme.spacing(3),
}, },
usernameField: {
marginBottom: theme.spacing(3),
"& .MuiOutlinedInput-root": {
color: "#ffffff",
"& fieldset": {
borderColor: "#00A346",
},
"&:hover fieldset": {
borderColor: "#00A346",
},
"&.Mui-focused fieldset": {
borderColor: "#1caff2",
},
},
"& .MuiInputLabel-root": {
color: "#ffffff",
},
},
})); }));
const UploadDiary = () => { const UploadDiary = () => {
const classes = useStyles(); const classes = useStyles();
const [file, setFile] = useState(null); const [file, setFile] = useState(null);
const [uploading, setUploading] = useState(false); const [uploading, setUploading] = useState(false);
const [username, setUsername] = useState("");
const navigate = useNavigate(); const navigate = useNavigate();
useEffect(() => { useEffect(() => {
@@ -112,9 +132,16 @@ const UploadDiary = () => {
}); });
const handleUpload = async () => { const handleUpload = async () => {
if (file) { if (username || file) {
setUploading(true); setUploading(true);
try { try {
if (username) {
// Here you would implement the logic to fetch the diary from Letterboxd
// For now, we'll just simulate a successful fetch
console.log(`Fetching diary for user: ${username}`);
await new Promise((resolve) => setTimeout(resolve, 1000)); // Simulate API call
navigate("/PosterSelector");
} else if (file) {
const formData = new FormData(); const formData = new FormData();
formData.append("file", file); formData.append("file", file);
@@ -125,8 +152,9 @@ const UploadDiary = () => {
}); });
navigate("/PosterSelector"); navigate("/PosterSelector");
}
} catch (error) { } catch (error) {
console.error("Error uploading file:", error); console.error("Error processing diary:", error);
} finally { } finally {
setUploading(false); setUploading(false);
} }
@@ -137,7 +165,22 @@ const UploadDiary = () => {
<Container className={classes.root}> <Container className={classes.root}>
<div className={classes.card}> <div className={classes.card}>
<Typography variant="h4" className={classes.title}> <Typography variant="h4" className={classes.title}>
Upload CSV File Upload Letterboxd Diary
</Typography>
<TextField
className={classes.usernameField}
label="Letterboxd Username"
variant="outlined"
fullWidth
value={username}
onChange={(e) => setUsername(e.target.value)}
placeholder="Enter your Letterboxd username"
/>
<Typography
variant="body2"
style={{ color: "#ffffff", marginBottom: "1rem" }}
>
Or upload a CSV file:
</Typography> </Typography>
<div {...getRootProps()} className={classes.dropzone}> <div {...getRootProps()} className={classes.dropzone}>
<input {...getInputProps()} /> <input {...getInputProps()} />
@@ -163,12 +206,7 @@ const UploadDiary = () => {
</> </>
)} )}
</div> </div>
{file && ( <Grid container justify="center" className={classes.progressContainer}>
<Grid
container
justify="center"
className={classes.progressContainer}
>
{uploading ? ( {uploading ? (
<CircularProgress /> <CircularProgress />
) : ( ) : (
@@ -176,28 +214,29 @@ const UploadDiary = () => {
className={classes.submitButton} className={classes.submitButton}
variant="contained" variant="contained"
onClick={handleUpload} onClick={handleUpload}
disabled={!username && !file}
> >
SUBMIT SUBMIT
</Button> </Button>
)} )}
</Grid> </Grid>
)}
</div> </div>
<Typography variant="body1" className={classes.overviewText}> <Typography variant="body1" className={classes.overviewText}>
This tool allows you to easily upload your diary.csv file from This tool allows you to easily import your Letterboxd diary and select
Letterboxd and select your favorite movie poster. Follow these simple your favorite movie poster. Follow these simple steps:
steps:
<br /> <br />
<strong>1. Upload Your CSV File:</strong> Drag and drop your diary.csv <strong>1. Enter Your Letterboxd Username:</strong> Type your Letterboxd
file or click to select it from your device. username to automatically fetch your diary.
<br /> <br />
<strong>2. Automatic Processing:</strong> Once uploaded, the application <strong>2. Or Upload Your CSV File:</strong> If you prefer, you can
will automatically process the file. still upload your diary.csv file directly.
<br /> <br />
<strong>3. Poster Selection:</strong> After the file is successfully <strong>3. Automatic Processing:</strong> Once submitted, the
uploaded, you'll be redirected to the Poster Selector page, where you application will process your diary.
can browse and choose your favorite movie poster based on your <br />
Letterboxd diary. <strong>4. Poster Selection:</strong> After processing, you'll be
redirected to the Poster Selector page, where you can browse and choose
your favorite movie poster based on your Letterboxd diary.
</Typography> </Typography>
</Container> </Container>
); );

BIN
src/static/images/pulp.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 MiB