Card updates

This commit is contained in:
2024-11-30 14:30:56 +01:00
parent 0c5b2b4bbc
commit d127beed48
3 changed files with 98 additions and 48 deletions

1
package-lock.json generated
View File

@@ -14805,6 +14805,7 @@
"version": "0.453.0", "version": "0.453.0",
"resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.453.0.tgz", "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.453.0.tgz",
"integrity": "sha512-kL+RGZCcJi9BvJtzg2kshO192Ddy9hv3ij+cPrVPWSRzgCWCVazoQJxOjAwgK53NomL07HB7GPHW120FimjNhQ==", "integrity": "sha512-kL+RGZCcJi9BvJtzg2kshO192Ddy9hv3ij+cPrVPWSRzgCWCVazoQJxOjAwgK53NomL07HB7GPHW120FimjNhQ==",
"license": "ISC",
"peerDependencies": { "peerDependencies": {
"react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc" "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc"
} }

View File

@@ -1,7 +1,8 @@
import React, { useState } from 'react'; import React, { useState } from "react";
import { useSelector, useDispatch } from 'react-redux'; import { useSelector, useDispatch } from "react-redux";
import { removePoster } from '../services/action'; import { removePoster } from "../services/action";
import DeleteIcon from '@material-ui/icons/Delete'; import DeleteIcon from "@material-ui/icons/Delete";
import { Camera } from "lucide-react";
const apiUrl = process.env.REACT_APP_API_URL; const apiUrl = process.env.REACT_APP_API_URL;
@@ -10,11 +11,11 @@ const Cart = () => {
const selectedPosters = useSelector((state) => { const selectedPosters = useSelector((state) => {
const selections = state.posterSelections; const selections = state.posterSelections;
return Object.entries(selections).flatMap(([movieId, posters]) => return Object.entries(selections).flatMap(([movieId, posters]) =>
posters.map((posterId) => ({ movieId, posterId })) posters.map((posterId) => ({ movieId, posterId }))
); );
}); });
const [downloadFormat, setDownloadFormat] = useState('zip'); const [downloadFormat, setDownloadFormat] = useState("zip");
const handleRemovePoster = (movieId, posterId) => { const handleRemovePoster = (movieId, posterId) => {
dispatch(removePoster(movieId, posterId)); dispatch(removePoster(movieId, posterId));
@@ -23,9 +24,9 @@ const Cart = () => {
const handleDownload = async () => { const handleDownload = async () => {
try { try {
const response = await fetch(`${apiUrl}/api/download-posters`, { const response = await fetch(`${apiUrl}/api/download-posters`, {
method: 'POST', method: "POST",
headers: { headers: {
'Content-Type': 'application/json', "Content-Type": "application/json",
}, },
body: JSON.stringify({ body: JSON.stringify({
posters: selectedPosters, posters: selectedPosters,
@@ -33,70 +34,94 @@ const Cart = () => {
}), }),
}); });
if (!response.ok) throw new Error('Download failed'); if (!response.ok) throw new Error("Download failed");
const contentType = response.headers.get('content-type'); const contentType = response.headers.get("content-type");
if (contentType && contentType.includes('application/zip')) { if (contentType && contentType.includes("application/zip")) {
const blob = await response.blob(); const blob = await response.blob();
const url = window.URL.createObjectURL(blob); const url = window.URL.createObjectURL(blob);
const link = document.createElement('a'); const link = document.createElement("a");
link.href = url; link.href = url;
link.download = 'posters.zip'; link.download = "posters.zip";
document.body.appendChild(link); document.body.appendChild(link);
link.click(); link.click();
link.remove(); link.remove();
window.URL.revokeObjectURL(url); window.URL.revokeObjectURL(url);
} else { } else {
throw new Error('Invalid response format'); throw new Error("Invalid response format");
} }
} catch (error) { } catch (error) {
console.error('Failed to download posters:', error); console.error("Failed to download posters:", error);
} }
}; };
const totalSlots = 4;
const posterSlots = [...Array(totalSlots)].map((_, index) => {
if (index < selectedPosters.length) {
return selectedPosters[index];
}
return null;
});
return ( return (
<div className="cart-container"> <div className="cart-container">
<div className="poster-grid"> <div className="poster-grid">
{selectedPosters.map((poster) => ( {posterSlots.map((poster, index) => (
<div key={`${poster.movieId}-${poster.posterId}`} className="poster-card"> <div
key={
poster ? `${poster.movieId}-${poster.posterId}` : `empty-${index}`
}
className="poster-card"
>
{poster ? (
<>
<img <img
src={`https://image.tmdb.org/t/p/w500${poster.posterId}`} src={`https://image.tmdb.org/t/p/w500${poster.posterId}`}
alt="Movie poster" alt="Movie poster"
className="poster-image" className="poster-image"
/> />
<div className="delete-overlay"> <div className="delete-overlay">
<button <button
className="delete-button" className="delete-button"
onClick={() => handleRemovePoster(poster.movieId, poster.posterId)} onClick={() =>
handleRemovePoster(poster.movieId, poster.posterId)
}
> >
<DeleteIcon /> <DeleteIcon />
</button> </button>
</div> </div>
</>
) : (
<div className="empty-poster">
<Camera size={48} />
<p>Emplacement disponible</p>
</div> </div>
))} )}
</div> </div>
))}
<div className="action-panel">
<h2>Download Options</h2>
<select
value={downloadFormat}
onChange={(e) => setDownloadFormat(e.target.value)}
className="format-select"
>
<option value="zip">ZIP</option>
<option value="tar">TAR</option>
<option value="7z">7Z</option>
</select>
<button
className="download-button"
onClick={handleDownload}
disabled={selectedPosters.length === 0}
>
Download Selected
</button>
</div>
</div> </div>
<div className="action-panel">
<h2>Download Options</h2>
<select
value={downloadFormat}
onChange={(e) => setDownloadFormat(e.target.value)}
className="format-select"
>
<option value="zip">ZIP</option>
<option value="tar">TAR</option>
<option value="7z">7Z</option>
</select>
<button
className="download-button"
onClick={handleDownload}
disabled={selectedPosters.length === 0}
>
Download Selected
</button>
</div>
</div>
); );
}; };
export default Cart; export default Cart;

View File

@@ -54,6 +54,30 @@
} }
} }
} }
.empty-poster {
width: 100%;
height: 100%;
background-color: #f5f6fa10;
border: 2px #95a5a6;
border-radius: 8px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
color: #7f8c8d;
svg {
margin-bottom: 1rem;
color: #95a5a6;
}
p {
font-size: 0.875rem;
text-align: center;
padding: 0 1rem;
}
}
} }
.action-panel { .action-panel {
@@ -102,4 +126,4 @@
} }
} }
} }
} }