import React, { useState, useEffect } from "react"; import { useNavigate } from "react-router-dom"; import { useDispatch, useSelector } from "react-redux"; import { Container, Grid, Typography, CircularProgress, Box, Link, TextField, InputAdornment, } from "@material-ui/core"; import { Button } from "@mui/material"; import { CloudUploadOutlined } from "@material-ui/icons"; import CloudDoneOutlinedIcon from "@mui/icons-material/CloudDoneOutlined"; import SyncIcon from "@material-ui/icons/Sync"; import { useDropzone } from "react-dropzone"; import api from "../services/api"; import { setUsername, setDataSource } from "../services/action"; const VERSION = require("../../package.json").version; const UploadDiary = () => { const [file, setFile] = useState(null); const [uploading, setUploading] = useState(false); const [usernameInput, setUsernameInput] = useState(""); const [syncing, setSyncing] = useState(false); const [syncError, setSyncError] = useState(null); const navigate = useNavigate(); const dispatch = useDispatch(); const storedUsername = useSelector((state) => state.username); useEffect(() => { if (storedUsername) setUsernameInput(storedUsername); }, [storedUsername]); useEffect(() => { const checkCSVFile = async () => { try { const response = await api.get("/api/check-csv"); if (response.data.fileExists) { navigate("/PosterSelector"); } } catch (error) { console.error("Error checking CSV file:", error); } }; checkCSVFile(); }, [navigate]); const { getRootProps, getInputProps } = useDropzone({ onDrop: (acceptedFiles) => { setFile(acceptedFiles[0]); }, maxFiles: 1, accept: ".csv", }); const handleUpload = async () => { if (!file) return; setUploading(true); try { const formData = new FormData(); formData.append("file", file); await api.post("/api/upload-csv", formData, { headers: { "Content-Type": "multipart/form-data" }, }); dispatch(setDataSource('csv')); navigate("/PosterSelector"); } catch (error) { console.error("Error processing diary:", error); } finally { setUploading(false); } }; const handleRssSync = async () => { const username = usernameInput.trim(); if (!username) return; setSyncing(true); setSyncError(null); try { const res = await api.post("/api/sync-rss", { username }); dispatch(setUsername(username)); if (res.data.fresh) dispatch(setDataSource('rss')); navigate("/PosterSelector"); } catch (err) { const msg = err.response?.data?.error || "Could not fetch RSS feed."; setSyncError(msg); } finally { setSyncing(false); } }; return (
logo
{/* CSV upload */} Upload Letterboxd Diary
{file ? ( <> Your file has been uploaded: {file.name} ) : ( <> Drag and drop a CSV file here or click to select )}
{uploading ? ( ) : ( )} {/* Divider */}
or
{/* RSS sync */} Sync from Letterboxd RSS
{ setUsernameInput(e.target.value); setSyncError(null); }} onKeyDown={(e) => e.key === "Enter" && handleRssSync()} InputProps={{ startAdornment: ( letterboxd.com/ ), }} />
{syncError && ( {syncError} )} Syncs your ~50 most recent diary entries via the public RSS feed. Use CSV export for full history.
This tool allows you to easily import your Letterboxd diary and select your favorite movie poster. Follow these simple steps:
1. Export your diary:{" "} Export your Letterboxd data {" "} and extract the diary.csv file from the ZIP.
2. Upload the CSV: Drop your diary.csv{" "} file above or click to select it.
3. Poster Selection: After processing, you'll be redirected to the calendar where you can browse and choose your favorite poster for each movie.
v{VERSION} • (e.currentTarget.style.opacity = 1)} onMouseLeave={(e) => (e.currentTarget.style.opacity = 0.7)} > Hugyouu
); }; export default UploadDiary;