Fixed admin client
This commit is contained in:
+27
-18
@@ -1,5 +1,5 @@
|
||||
import * as React from "react";
|
||||
import {useRef, useState} from "react";
|
||||
import {useEffect, useRef, useState} from "react";
|
||||
import {NavLink, useNavigate} from "react-router-dom";
|
||||
import {Button, IconButton, InputAdornment, TextField} from "@mui/material";
|
||||
import {useAuth} from "../services/authentication/use-auth";
|
||||
@@ -7,13 +7,13 @@ import {useInstances} from "../services/instances/use-instances";
|
||||
import {Instance} from "../models/instance";
|
||||
import {
|
||||
AddAPhoto, AddCircle,
|
||||
ArrowRightAltOutlined, RemoveCircle
|
||||
ArrowRightAltOutlined, Edit, RemoveCircle
|
||||
} from "@mui/icons-material";
|
||||
|
||||
import "./instance-selector-page.scss";
|
||||
import "./instances-page.scss";
|
||||
import DragAndDrop from "../components/drag-and-drop/drag-and-drop";
|
||||
|
||||
export function InstanceSelectorPage() {
|
||||
export function InstancesPage() {
|
||||
const navigate = useNavigate();
|
||||
const {
|
||||
instances,
|
||||
@@ -23,14 +23,14 @@ export function InstanceSelectorPage() {
|
||||
uploadCoverPhoto,
|
||||
instanceApiError
|
||||
} = useInstances();
|
||||
const [instancesToUpdate, setInstancesToUpdate] = useState(instances?.map(inst => new Instance(inst)) || []);
|
||||
const [instancesToUpdate, setInstancesToUpdate] = useState(null);
|
||||
const {userData} = useAuth();
|
||||
|
||||
const [newInstanceTitle, setNewInstanceTitle] = useState("");
|
||||
|
||||
// useEffect(() => {
|
||||
// setInstancesToUpdate(instances);
|
||||
// }, [instances]);
|
||||
useEffect(() => {
|
||||
setInstancesToUpdate(instances?.map(inst => new Instance(inst)) || []);
|
||||
}, [instances]);
|
||||
|
||||
let onNewInstanceTitleChanged = (e) => {
|
||||
setNewInstanceTitle(e.target.value);
|
||||
@@ -59,14 +59,15 @@ export function InstanceSelectorPage() {
|
||||
}
|
||||
|
||||
const instanceHasChanges = (idx) => {
|
||||
return (instancesToUpdate[idx].title || "") !== (instances[idx].title || "") ||
|
||||
(instancesToUpdate[idx].subtitle || "") !== (instances[idx].subtitle || "") ||
|
||||
JSON.stringify(instancesToUpdate[idx].urls) !== JSON.stringify(instances[idx].urls);
|
||||
return (instancesToUpdate[idx].title || "") !== (instances[idx]?.title || "") ||
|
||||
(instancesToUpdate[idx].subtitle || "") !== (instances[idx]?.subtitle || "") ||
|
||||
JSON.stringify(instancesToUpdate[idx].urls) !== JSON.stringify(instances[idx]?.urls);
|
||||
}
|
||||
const handleCreateInstance = async () => {
|
||||
await createInstance(new Instance({
|
||||
title: newInstanceTitle
|
||||
}));
|
||||
setNewInstanceTitle("");
|
||||
}
|
||||
const handleSaveInstance = async (idx) => {
|
||||
if (instanceHasChanges(idx)) {
|
||||
@@ -93,6 +94,11 @@ export function InstanceSelectorPage() {
|
||||
}
|
||||
|
||||
return <div id="instance-selector-page">
|
||||
<div id="page-title">
|
||||
<div id="left-part">
|
||||
<div className="title">Sites</div>
|
||||
</div>
|
||||
</div>
|
||||
{instanceApiError && <div className="error-box">{instanceApiError}</div>}
|
||||
<div>
|
||||
{userData?.profile?.resource_access?.photos?.roles?.indexOf("admin") >= 0 && <>
|
||||
@@ -122,8 +128,11 @@ export function InstanceSelectorPage() {
|
||||
onClick={(e) => fileInputRefs.current[idx].click(e)}
|
||||
isLoading={isUploading[idx]}>
|
||||
{!isUploading[idx] && instance.coverPhoto
|
||||
? <img src={`${instance.coverPhoto.url}?width=450&height=450&fit=cover`}
|
||||
? <>
|
||||
<img src={`${instance.coverPhoto.url}?width=450&height=450&fit=cover`}
|
||||
alt={instance.coverPhoto.name}/>
|
||||
<div className="btn-edit-photo"><Edit /></div>
|
||||
</>
|
||||
: <AddAPhoto className="no-photos"/>
|
||||
}
|
||||
</DragAndDrop>
|
||||
@@ -162,12 +171,12 @@ export function InstanceSelectorPage() {
|
||||
)
|
||||
}}/>
|
||||
<div className="instance-links">
|
||||
{instance.urls.map(url => <div className="instance-link">
|
||||
<IconButton color="error" onClick={(e) => handleDeleteUrl(e, idx, url)}>
|
||||
<RemoveCircle />
|
||||
</IconButton>
|
||||
<NavLink to={url}>{url}</NavLink>
|
||||
</div>)}
|
||||
{instance.urls.map(url => <div className="instance-link" key={url}>
|
||||
<IconButton color="error" onClick={(e) => handleDeleteUrl(e, idx, url)}>
|
||||
<RemoveCircle/>
|
||||
</IconButton>
|
||||
<NavLink to={url}>{url}</NavLink>
|
||||
</div>)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="input-buttons">
|
||||
+28
@@ -9,6 +9,32 @@
|
||||
|
||||
> .instance {
|
||||
|
||||
.cover-photo {
|
||||
img {
|
||||
position: relative;
|
||||
}
|
||||
.btn-edit-photo {
|
||||
display: none;
|
||||
}
|
||||
&:hover {
|
||||
.btn-edit-photo {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(255, 255, 255, 0.2);
|
||||
svg {
|
||||
color: white;
|
||||
font-size: 48px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
display: flex;
|
||||
|
||||
@@ -28,8 +54,10 @@
|
||||
.instance-links {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
div.instance-link {
|
||||
padding: 2px 0;
|
||||
|
||||
a {
|
||||
color: $accentColor;
|
||||
text-decoration: none;
|
||||
@@ -1,82 +0,0 @@
|
||||
import {Button, TextField} from "@mui/material";
|
||||
import * as React from "react";
|
||||
import {useState} from "react";
|
||||
import useInstancesApi from "../services/instances/instances-api";
|
||||
import {useInstances} from "../services/instances/use-instances";
|
||||
|
||||
export function ManageInstancePage() {
|
||||
const {selectedInstance, setSelectedInstance} = useInstances();
|
||||
const {updateInstance} = useInstancesApi();
|
||||
let [instanceToUpdate, setInstanceToUpdate] = useState({});
|
||||
const [apiError, setApiError] = useState(null);
|
||||
|
||||
const handleTitleChange = (e) => {
|
||||
instanceToUpdate.title = e.target.value;
|
||||
setInstanceToUpdate(instanceToUpdate);
|
||||
}
|
||||
const handleSubtitleChange = (e) => {
|
||||
instanceToUpdate.subtitle = e.target.value;
|
||||
setInstanceToUpdate(instanceToUpdate);
|
||||
}
|
||||
|
||||
const instanceHasChanges = () => {
|
||||
return (instanceToUpdate.title || "") !== (selectedInstance.title || "") ||
|
||||
(instanceToUpdate.subtitle || "") !== (selectedInstance.subtitle || "");
|
||||
}
|
||||
|
||||
const handleSaveInstance = async () => {
|
||||
try {
|
||||
setApiError(null);
|
||||
if (instanceHasChanges()) {
|
||||
const updatedInstance = await updateInstance(
|
||||
instanceToUpdate
|
||||
);
|
||||
setSelectedInstance(updatedInstance);
|
||||
setInstanceToUpdate(updatedInstance);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
setApiError("An error occurred trying to save the instance, contact the system administrator");
|
||||
}
|
||||
}
|
||||
|
||||
return <>
|
||||
<div className="card-layout photo">
|
||||
{apiError && <div className="error-box">{apiError}</div>}
|
||||
{selectedInstance && <>
|
||||
{selectedInstance.photo &&
|
||||
<div className="cover-photo">
|
||||
{<img src={`${selectedInstance.photo.url}?width=450&height=450&fit=cover`}
|
||||
alt={selectedInstance.photo.name}/>}
|
||||
<div className="file-name">
|
||||
{selectedInstance.photo.fileName}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<div className="card-details">
|
||||
<div className="title input-element">
|
||||
<TextField fullWidth={true} variant="standard"
|
||||
value={selectedInstance.title}
|
||||
onChange={handleTitleChange}
|
||||
/>
|
||||
</div>
|
||||
<div className="description input-element">
|
||||
<TextField multiline={true} fullWidth={true} rows={8}
|
||||
onChange={handleSubtitleChange}
|
||||
value={selectedInstance.subtitle || ""}
|
||||
/>
|
||||
</div>
|
||||
<div className="input-buttons">
|
||||
<div className="left-buttons">
|
||||
<Button className="photo-save" variant="contained" color="info"
|
||||
disabled={!instanceHasChanges()}
|
||||
onClick={handleSaveInstance}>
|
||||
Save
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>}
|
||||
</div>
|
||||
</>;
|
||||
}
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
MoveDown,
|
||||
MoveUp
|
||||
} from "@mui/icons-material";
|
||||
import {Link, useNavigate} from "react-router-dom";
|
||||
import {Link, Outlet, useNavigate} from "react-router-dom";
|
||||
import Loader from "../components/Loader";
|
||||
|
||||
import {Button, TextField} from "@mui/material";
|
||||
@@ -204,6 +204,7 @@ function PortfolioManager() {
|
||||
</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} />
|
||||
<Outlet />
|
||||
</div>
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user