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 { createTheme, ThemeProvider } from "@mui/material/styles";
import queryString from "query-string";
import pulpGif from "../static/images/pulp.gif";
const useStyles = makeStyles((theme) => ({
root: {
@@ -25,11 +26,15 @@ const useStyles = makeStyles((theme) => ({
padding: theme.spacing(3),
borderRadius: theme.shape.borderRadius,
backgroundColor: "#1c1f23",
color: "white",
},
title: {
color: "white",
marginBottom: theme.spacing(3),
},
username: {
color: "#00A346",
marginBottom: theme.spacing(2),
},
list: {
maxHeight: "800px",
minHeight: "1000px",
@@ -94,6 +99,44 @@ const useStyles = makeStyles((theme) => ({
marginTop: theme.spacing(2),
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({
@@ -134,6 +177,7 @@ const PosterSelector = () => {
const [page, setPage] = useState(1);
const [totalPages, setTotalPages] = useState(1);
const [progress, setProgress] = useState(0);
const [username, setUsername] = useState("");
const navigate = useNavigate();
const location = useLocation();
const moviesPerPage = 10;
@@ -143,8 +187,18 @@ const PosterSelector = () => {
const pageNumber = parsed.page ? parseInt(parsed.page, 10) : 1;
setPage(pageNumber);
fetchMovies(pageNumber);
fetchUsername();
}, [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) => {
try {
setLoading(true);
@@ -195,6 +249,10 @@ const PosterSelector = () => {
navigate(`?page=${value}`);
};
const handleGoBack = () => {
navigate("/");
};
const formatWatchedDate = (dateString) => {
const date = new Date(dateString);
const day = date.getDate().toString().padStart(2, "0");
@@ -210,6 +268,11 @@ const PosterSelector = () => {
<Typography variant="h4" gutterBottom className={classes.title}>
Your diary
</Typography>
{username && (
<Typography variant="h6" className={classes.username}>
Letterboxd User: {username}
</Typography>
)}
{loading ? (
<Box className={classes.progressContainer}>
<LinearProgress variant="determinate" value={progress} />
@@ -218,93 +281,111 @@ const PosterSelector = () => {
</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}
/>
<>
<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>
<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>
</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>
<Typography variant="body1" color="textSecondary" gutterBottom>
No movies to display. Upload a CSV file to get started.
<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>
)}
<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>
</Paper>
</Container>
);

View File

@@ -6,6 +6,7 @@ import {
Typography,
Button,
CircularProgress,
TextField,
makeStyles,
} from "@material-ui/core";
import { CloudUploadOutlined } from "@material-ui/icons";
@@ -81,12 +82,31 @@ const useStyles = makeStyles((theme) => ({
marginTop: theme.spacing(4),
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 classes = useStyles();
const [file, setFile] = useState(null);
const [uploading, setUploading] = useState(false);
const [username, setUsername] = useState("");
const navigate = useNavigate();
useEffect(() => {
@@ -112,21 +132,29 @@ const UploadDiary = () => {
});
const handleUpload = async () => {
if (file) {
if (username || file) {
setUploading(true);
try {
const formData = new FormData();
formData.append("file", file);
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();
formData.append("file", file);
await axios.post("http://localhost:5000/api/upload-csv", formData, {
headers: {
"Content-Type": "multipart/form-data",
},
});
await axios.post("http://localhost:5000/api/upload-csv", formData, {
headers: {
"Content-Type": "multipart/form-data",
},
});
navigate("/PosterSelector");
navigate("/PosterSelector");
}
} catch (error) {
console.error("Error uploading file:", error);
console.error("Error processing diary:", error);
} finally {
setUploading(false);
}
@@ -137,7 +165,22 @@ const UploadDiary = () => {
<Container className={classes.root}>
<div className={classes.card}>
<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>
<div {...getRootProps()} className={classes.dropzone}>
<input {...getInputProps()} />
@@ -163,41 +206,37 @@ const UploadDiary = () => {
</>
)}
</div>
{file && (
<Grid
container
justify="center"
className={classes.progressContainer}
>
{uploading ? (
<CircularProgress />
) : (
<Button
className={classes.submitButton}
variant="contained"
onClick={handleUpload}
>
SUBMIT
</Button>
)}
</Grid>
)}
<Grid container justify="center" className={classes.progressContainer}>
{uploading ? (
<CircularProgress />
) : (
<Button
className={classes.submitButton}
variant="contained"
onClick={handleUpload}
disabled={!username && !file}
>
SUBMIT
</Button>
)}
</Grid>
</div>
<Typography variant="body1" className={classes.overviewText}>
This tool allows you to easily upload your diary.csv file from
Letterboxd and select your favorite movie poster. Follow these simple
steps:
This tool allows you to easily import your Letterboxd diary and select
your favorite movie poster. Follow these simple steps:
<br />
<strong>1. Upload Your CSV File:</strong> Drag and drop your diary.csv
file or click to select it from your device.
<strong>1. Enter Your Letterboxd Username:</strong> Type your Letterboxd
username to automatically fetch your diary.
<br />
<strong>2. Automatic Processing:</strong> Once uploaded, the application
will automatically process the file.
<strong>2. Or Upload Your CSV File:</strong> If you prefer, you can
still upload your diary.csv file directly.
<br />
<strong>3. Poster Selection:</strong> After the file is successfully
uploaded, you'll be redirected to the Poster Selector page, where you
can browse and choose your favorite movie poster based on your
Letterboxd diary.
<strong>3. Automatic Processing:</strong> Once submitted, the
application will process your diary.
<br />
<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>
</Container>
);

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 MiB