|
- import * as React from "react";
- import {useCallback, useEffect, useRef, useState} from "react";
- import useAlbumsApi from "../services/albums-api";
- import {
- AddAPhoto,
- KeyboardArrowRight,
- MoveDown,
- MoveUp
- } from "@mui/icons-material";
- import {Link, useNavigate} from "react-router-dom";
- import Loader from "../components/Loader";
-
- import {Button, TextField} from "@mui/material";
- import {Album} from "../models/album";
-
- import "./portfolio-manager.scss"
- import {useInstances} from "../services/instances/use-instances";
-
- function PortfolioManager() {
- const navigate = useNavigate();
- const {selectedInstance} = useInstances();
-
- const [apiError, setApiError] = useState(null);
- const {fetchAlbums, patchAlbum, deleteAlbum, moveAlbumDown, moveAlbumUp} = useAlbumsApi();
-
- const [albums, setAlbums] = useState(null);
- const [isLoading, setIsLoading] = useState(false);
- const [albumsToUpdate, setAlbumsToUpdate] = useState(null);
- const fetchedRef = useRef(false)
-
- const fetchData = useCallback(async () => {
- try {
- setIsLoading(true);
- setApiError(null);
- const albums = await fetchAlbums(selectedInstance);
- setAlbums(albums);
- setAlbumsToUpdate(albums.map(a => new Album(a)));
- } catch (err) {
- console.error("Could not fetch albums", err);
- setApiError("An error occurred trying to fetch your albums, please contact the system administrator");
- setAlbums([]);
- } finally {
- setIsLoading(false);
- }
- }, [fetchAlbums, selectedInstance])
-
- useEffect(() => {
- if (selectedInstance && !fetchedRef.current) {
- fetchData();
- fetchedRef.current = true;
- }
- }, [selectedInstance, fetchData]);
-
- const handleAlbumNameChange = (albumIndex, e) => {
- albumsToUpdate[albumIndex].name = e.target.value;
- setAlbumsToUpdate([...albumsToUpdate]);
- }
-
- const handleAlbumDescriptionChange = (albumIndex, e) => {
- albumsToUpdate[albumIndex].description = e.target.value;
- setAlbumsToUpdate([...albumsToUpdate]);
- }
-
- const albumHasChanges = (idx) => {
- return albumsToUpdate[idx].name !== albums[idx].name
- || albumsToUpdate[idx].description !== albums[idx].description;
- }
-
- const handleSaveAlbum = async (idx) => {
- try {
- setIsLoading(true);
- if (albumHasChanges(idx)) {
- albumsToUpdate[idx] = await patchAlbum(selectedInstance, albumsToUpdate[idx]);
- setAlbums([
- ...albumsToUpdate.map(a => new Album(a))
- ]);
- }
- } catch (err) {
- if (typeof err === "string" && err.toLowerCase().indexOf("duplicate") >= 0) {
- setApiError("Name already in use");
- } else {
- console.error(err);
- navigate(`/${selectedInstance.instanceId}/albums`, {state: {error: err}});
- }
- } finally {
- setIsLoading(false);
- }
- }
-
- const handleDeleteAlbum = async (e, albumId) => {
- try {
- setIsLoading(true);
- const updatedAlbums = await deleteAlbum(selectedInstance, albumId);
- setAlbums(updatedAlbums);
- setAlbumsToUpdate(albumsToUpdate.filter(a => a.albumId !== albumId));
- } catch (err) {
- console.error(err);
- } finally {
- setIsLoading(false);
- }
- }
-
- const handleMoveAlbumDown = async (idx) => {
- try {
- setIsLoading(true);
- const updatedAlbums = await moveAlbumDown(selectedInstance, albumsToUpdate[idx].albumId);
- const origAlbum = albumsToUpdate[idx];
- albumsToUpdate[idx] = albumsToUpdate[idx + 1];
- albumsToUpdate[idx + 1] = origAlbum;
- setAlbums(updatedAlbums);
- } catch (err) {
- console.error(err);
- } finally {
- setIsLoading(false);
- }
- }
-
- const handleMoveAlbumUp = async (idx) => {
- try {
- setIsLoading(true);
- const updatedAlbums = await moveAlbumUp(selectedInstance, albumsToUpdate[idx].albumId);
- const origAlbum = albumsToUpdate[idx];
- albumsToUpdate[idx] = albumsToUpdate[idx - 1];
- albumsToUpdate[idx - 1] = origAlbum;
- setAlbums(updatedAlbums);
- } catch (err) {
- console.error(err);
- } finally {
- setIsLoading(false);
- }
- }
-
- return <div id="portfolio-manager">
- <div id="page-title">
- <div id="left-part">
- <div className="title">Albums</div>
- {albums && <div className="photos-count">({albums.length} albums)</div>}
- </div>
- <div id="right-part">
- <Button id="page-save" variant="contained" color="success"
- onClick={() => navigate("new", {state: {album: new Album()}})}>
- Create
- </Button>
- </div>
- </div>
- {apiError && <div className="error-box">{apiError}</div>}
- {!apiError && albums?.length > 0 && <div id="album-list">
- {albumsToUpdate.map((album, idx) =>
- <div className="card-layout album-list-item" key={album.albumId}>
- <div className={`cover-photo ${(album.coverPhoto ? "" : "cover-photo--no-img")}`}
- onClick={() => navigate(album.albumId, {state: {album: albums[idx]}})}>
- {album.coverPhoto
- ? <img src={`${album.coverPhoto.url}?width=450&height=450&fit=cover`}
- alt={album.coverPhoto.name}/>
- : <AddAPhoto className="no-photos"/>
- }
- </div>
- <div className="card-details">
- <div className="title input-element">
- <TextField fullWidth={true} variant="standard"
- value={album.name} onChange={(e) => handleAlbumNameChange(idx, e)}
- />
- <Button endIcon={<KeyboardArrowRight/>} variant="contained"
- color="secondary"
- onClick={() => navigate(album.albumId, {state: {album: albums[idx]}})}>
- Photos
- </Button>
- </div>
- <div className="description input-element">
- <TextField multiline={true} fullWidth={true} rows={8}
- onChange={(e) => handleAlbumDescriptionChange(idx, e)}
- value={album.description || ""}
- />
- </div>
- <div className="input-buttons">
- <div className="left-buttons">
- <Button className="photo-save" variant="contained" color="error"
- onClick={(e) => handleDeleteAlbum(e, album.albumId)}>
- Delete
- </Button>
- <Button className="photo-save" variant="contained" color="info" disabled={!albumHasChanges(idx)}
- onClick={() => handleSaveAlbum(idx)}>
- Save
- </Button>
- </div>
- <div className="right-buttons">
- <Button
- style={{visibility: (idx > 0 ? "visible" : "hidden")}}
- startIcon={<MoveUp/>} variant="contained" color="action"
- onClick={() => handleMoveAlbumUp(idx)}>
- Move up
- </Button>
- <Button
- style={{visibility: (idx < albumsToUpdate.length - 1 ? "visible" : "hidden")}}
- startIcon={<MoveDown/>} variant="contained" color="action"
- onClick={(e) => handleMoveAlbumDown(idx)}>
- Move down
- </Button>
- </div>
- </div>
- </div>
- </div>
- )}
- </div>}
- {!apiError && albums?.length === 0 && <div><Link to="new" state={{album: new Album()}}>Click here</Link> to create your first album!</div>}
- <Loader loading={isLoading} />
- </div>
- }
-
- export default PortfolioManager;
|