144 lines
4.6 KiB
TypeScript
144 lines
4.6 KiB
TypeScript
import React, { useState, useEffect } from "react";
|
|
import { DragDropContext, Droppable, DropResult } from "react-beautiful-dnd";
|
|
import Link, { EditableLink } from "components/Editor/Link";
|
|
import { useAuth } from "components/Login/AuthContext";
|
|
import Preview from "components/Preview";
|
|
|
|
import { useDragDrop } from "./useDragDrop";
|
|
import equal from "fast-deep-equal";
|
|
|
|
interface EditorProps {
|
|
links: EditableLink[];
|
|
setLinks: React.Dispatch<React.SetStateAction<EditableLink[]>>;
|
|
}
|
|
|
|
const Editor: React.FC<EditorProps> = ({ links, setLinks }) => {
|
|
const { displayDragDrop } = useDragDrop();
|
|
const { headers } = useAuth();
|
|
const [editableLinks, setEditableLinks] = useState<EditableLink[]>(links);
|
|
const [isSaving, setIsSaving] = useState(false);
|
|
|
|
useEffect(() => {
|
|
setEditableLinks(links);
|
|
}, [links]);
|
|
|
|
const handleOnDragEnd = (result: DropResult) => {
|
|
if (!result?.destination) return;
|
|
|
|
const items = Array.from(editableLinks);
|
|
const [reorderedItem] = items.splice(result.source.index, 1);
|
|
items.splice(result.destination.index, 0, reorderedItem);
|
|
|
|
setEditableLinks(items);
|
|
};
|
|
|
|
/*note that we need to make the new links name render with nothing*/
|
|
const handleOnClickAdd = () =>
|
|
setEditableLinks([
|
|
...editableLinks,
|
|
{
|
|
name: "",
|
|
url: "",
|
|
clicks: 0,
|
|
active: true,
|
|
},
|
|
]);
|
|
|
|
const onSubmit = async () => {
|
|
setIsSaving(true);
|
|
|
|
const res = await fetch("api/editor/links", {
|
|
method: "POST",
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
...headers,
|
|
},
|
|
body: JSON.stringify({ links: editableLinks }),
|
|
});
|
|
|
|
const updatedLinks = await res.json();
|
|
setLinks(updatedLinks);
|
|
|
|
setIsSaving(false);
|
|
};
|
|
|
|
const onCancel = () => {
|
|
setEditableLinks(links);
|
|
};
|
|
|
|
return (
|
|
<div className="flex flex-col bg-gray-100 md:h-full md:flex-row">
|
|
<div className="space-y-4 md:w-3/5 md:border-r md:border-gray-300 md:overflow-y-scroll">
|
|
<div className="m-8">
|
|
<button
|
|
className="block flex py-2 items-center justify-center rounded-lg bg-purple-600 hover:bg-purple-500 cursor-pointer text-white w-full"
|
|
onClick={handleOnClickAdd}
|
|
>
|
|
Add New Link
|
|
</button>
|
|
<div className="mb-8" />
|
|
{displayDragDrop && (
|
|
<DragDropContext onDragEnd={handleOnDragEnd}>
|
|
<Droppable droppableId="links">
|
|
{(provided) => (
|
|
<div
|
|
className="links"
|
|
{...provided.droppableProps}
|
|
ref={provided.innerRef}
|
|
>
|
|
{editableLinks.map((link, index) => (
|
|
<Link
|
|
key={index}
|
|
index={index}
|
|
link={link}
|
|
onChange={(newLink: EditableLink) =>
|
|
setEditableLinks([
|
|
...editableLinks.slice(0, index),
|
|
newLink,
|
|
...editableLinks.slice(index + 1),
|
|
])
|
|
}
|
|
onDelete={() =>
|
|
setEditableLinks([
|
|
...editableLinks.slice(0, index),
|
|
...editableLinks.slice(index + 1),
|
|
])
|
|
}
|
|
/>
|
|
))}
|
|
{provided.placeholder}
|
|
</div>
|
|
)}
|
|
</Droppable>
|
|
</DragDropContext>
|
|
)}
|
|
<div className="mb-8" />
|
|
<div className="flex">
|
|
<button
|
|
className="block flex py-2 items-center justify-center rounded-lg bg-purple-600 hover:bg-purple-500 cursor-pointer text-white w-full disabled:opacity-50"
|
|
onClick={onSubmit}
|
|
disabled={isSaving || equal(editableLinks, links)}
|
|
>
|
|
Submit
|
|
</button>
|
|
<div className="mr-4" />
|
|
<button
|
|
className="block flex py-2 items-center justify-center rounded-lg bg-purple-600 hover:bg-purple-500 cursor-pointer text-white w-full disabled:opacity-50"
|
|
onClick={onCancel}
|
|
disabled={isSaving || equal(editableLinks, links)}
|
|
>
|
|
Cancel
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div className="mb-8 md:none" />
|
|
<div className="flex items-center justify-center md:w-2/5">
|
|
<Preview links={editableLinks.filter((link) => link.active)} />
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default Editor;
|