diff --git a/api/server.js b/api/server.js
index 912d44e..a31dc96 100644
--- a/api/server.js
+++ b/api/server.js
@@ -13,6 +13,8 @@ const database = config.API.DB_NAME;
const collection = config.API.COLLECTION_NAME;
const client = new MongoClient(URI);
+const db = client.db(database);
+const list = db.collection(collection);
app.use(cors());
@@ -42,23 +44,39 @@ app.post('/api', async (req, res) => {
console.log(err);
insertDoc(req.body);
} finally {
- res.send('DONE!');
+ res.send('Posted!');
}
});
+app.put('/api', async (req, res) => {
+ const id = req.body._id;
+
+ await updateDoc(id, req.body);
+
+ res.send('Updated!');
+});
+
app.delete('/api', async (req, res) => {
- const id = req.body.id.toString();
+ const id = req.body.id;
await deleteDoc(id);
res.send(`Bookmark with _id:${id} deleted.`);
});
+async function updateDoc(id, updatedListing) {
+ try {
+ await list.updateOne({ _id: id }, { $set: updatedListing });
+ }
+
+ catch(err) {
+ console.log(err);
+ }
+}
+
async function insertDoc(doc) {
try {
- const db = client.db(database);
- const list = db.collection(collection);
- const result = await list.insertOne(doc);
+ await list.insertOne(doc);
}
catch(err) {
@@ -68,8 +86,6 @@ async function insertDoc(doc) {
async function getDoc() {
try {
- const db = client.db(database);
- const list = db.collection(collection);
const result = await list.find({}).toArray();
return result;
@@ -82,8 +98,6 @@ async function getDoc() {
async function deleteDoc(doc) {
try {
- const db = client.db(database);
- const list = db.collection(collection);
const result = await list.deleteOne({"_id": doc});
fs.unlink(config.API.STORAGE_LOCATION + '/LinkWarden/screenshot\'s/' + doc + '.png', (err) => {
diff --git a/src/App.js b/src/App.js
index fb28b4e..01bafcb 100644
--- a/src/App.js
+++ b/src/App.js
@@ -41,15 +41,15 @@ function App() {
}
function exitAdding() {
- setNewBox(!newBox);
+ setNewBox(false);
}
function exitFilter() {
- setFilterBox(!filterBox);
+ setFilterBox(false);
}
function exitSorting() {
- setSortBox(!sortBox);
+ setSortBox(false);
}
function search(e) {
@@ -59,8 +59,9 @@ function App() {
function sortByFunc(e) {
setSortBy(e)
}
-
+
const filteredData = filter(data, searchQuery, nameChecked, tagsChecked, descriptionChecked);
+ const tags = concatTags(data);
async function fetchData() {
const ADDRESS = config.API.ADDRESS + ":" + config.API.PORT;
@@ -91,7 +92,7 @@ function App() {
-
+
{numberOfResults === 0 ? : null}
@@ -114,7 +115,7 @@ function App() {
SetLoader={SetLoader}
onExit={exitAdding}
reFetch={fetchData}
- tags={() => concatTags(data)}
+ tags={() => tags}
/> : null}
{loader ? : null}
diff --git a/src/componets/AddItem.js b/src/componets/AddItem.js
index 16a85ee..6f878be 100644
--- a/src/componets/AddItem.js
+++ b/src/componets/AddItem.js
@@ -1,16 +1,16 @@
import { useState } from 'react';
import '../styles/AddItem.css';
import TagSelection from './TagSelection';
-import addItem from '../modules/addItem';
+import addItem from '../modules/send';
const AddItem = ({onExit, reFetch, tags, SetLoader}) => {
const [name, setName] = useState('');
const [link, setLink] = useState('');
const [tag, setTag] = useState([]);
-
+
function newItem() {
SetLoader(true)
- addItem(name, link, tag, reFetch, onExit, SetLoader);
+ addItem(name, link, tag, reFetch, onExit, SetLoader, "POST");
}
function SetName(e) {
diff --git a/src/componets/EditItem.js b/src/componets/EditItem.js
new file mode 100644
index 0000000..17a1ae7
--- /dev/null
+++ b/src/componets/EditItem.js
@@ -0,0 +1,61 @@
+import { useState } from 'react';
+import deleteEntity from '../modules/deleteEntity';
+import '../styles/AddItem.css';
+import TagSelection from './TagSelection';
+import editItem from '../modules/send';
+
+// deleteEntity(e._id, reFetch)
+
+const EditItem = ({tags, item, onExit, SetLoader, reFetch}) => {
+ const [name, setName] = useState(item.name);
+ const [tag, setTag] = useState(item.tag);
+
+ function EditItem() {
+ SetLoader(true)
+ editItem(name, item.link, tag, reFetch, onExit, SetLoader, "PUT", item._id);
+ }
+
+ function deleteItem() {
+ SetLoader(true)
+ deleteEntity(item._id, reFetch, onExit, SetLoader)
+ }
+
+ function SetName(e) {
+ setName(e.target.value);
+ }
+
+ function SetTags(value) {
+ setTag(value);
+ setTag(value.map(e => e.value.toLowerCase()));
+ }
+
+ function abort(e) {
+ if (e.target.className === "add-overlay") {
+ onExit();
+ }
+ }
+
+ const url = new URL(item.link);
+
+ return (
+ <>
+
+
+ >
+ )
+}
+
+export default EditItem
\ No newline at end of file
diff --git a/src/componets/List.js b/src/componets/List.js
index a832071..28475ba 100644
--- a/src/componets/List.js
+++ b/src/componets/List.js
@@ -1,44 +1,58 @@
import '../styles/List.css';
import LazyLoad from 'react-lazyload';
import ViewArchived from './ViewArchived';
-import deleteEntity from '../modules/deleteEntity';
+import EditItem from './EditItem';
+import { useState } from 'react'
-const List = ({data, reFetch}) => {
- return (
-
- {/* eslint-disable-next-line */}
- {data.map((e, i) => {
- try {
- const url = new URL(e.link);
- const favicon = 'http://www.google.com/s2/favicons?domain=' + url.hostname;
- return (
-
-
-
![]({favicon})
-
-
-
{e.title}
-
- {e.tag.map((e, i) => {
- return (
{e}
)
- })}
+const List = ({data, tags, reFetch, SetLoader}) => {
+ const [editBox, setEditBox] = useState(false)
+ const [editIndex, setEditIndex] = useState(0)
+
+ function edit(index) {
+ setEditBox(true);
+ setEditIndex(index);
+ }
+
+ function exitEditing() {
+ setEditBox(false);
+ }
+
+ return (
+
+ {/* eslint-disable-next-line */}
+ {data.map((e, i, array) => {
+ try {
+ const url = new URL(e.link);
+ const favicon = 'http://www.google.com/s2/favicons?domain=' + url.hostname;
+ return (
+
+
+
![]({favicon})
+
+
+
{e.title}
+
+ {e.tag.map((e, i) => {
+ return (
{e}
)
+ })}
+
+
+
+
+
-
-
-
deleteEntity(e._id, reFetch)}>
-
-
- )
- } catch (e) {
- console.log(e);
- }
- })}
-
- )
+ )
+ } catch (e) {
+ console.log(e);
+ }
+ })}
+ {editBox ?
tags} onExit={exitEditing} SetLoader={SetLoader} reFetch={reFetch} item={data[editIndex]} /> : null}
+
+ )
}
export default List
\ No newline at end of file
diff --git a/src/componets/TagSelection.js b/src/componets/TagSelection.js
index c41faf9..510a385 100644
--- a/src/componets/TagSelection.js
+++ b/src/componets/TagSelection.js
@@ -42,13 +42,17 @@ const customStyles = {
}),
}
-export default function TagSelection({setTags, tags}) {
+export default function TagSelection({setTags, tags, tag=[]}) {
const data = tags().map((e) => {
return { value: e, label: e }
})
+ const defaultTags = tag.map((e) => {
+ return { value: e, label: e }
+})
return (
{
+const deleteEntity = (id, reFetch, onExit, SetLoader) => {
const ADDRESS = config.API.ADDRESS + ":" + config.API.PORT;
fetch(ADDRESS + "/api", {
method: "DELETE",
@@ -11,7 +11,9 @@ const deleteEntity = (id, reFetch) => {
})
.then(res => res.text())
.then(message => {console.log(message)})
+ .then(() => onExit())
.then(() => reFetch())
+ .then(() => {SetLoader(false)});
}
export default deleteEntity;
\ No newline at end of file
diff --git a/src/modules/addItem.js b/src/modules/send.js
similarity index 69%
rename from src/modules/addItem.js
rename to src/modules/send.js
index 90450b8..fa1b0a2 100644
--- a/src/modules/addItem.js
+++ b/src/modules/send.js
@@ -1,7 +1,7 @@
import config from '../config';
import { nanoid } from 'nanoid';
-const addItem = async (name, link, tag, reFetch, onExit, SetLoader) => {
+const addItem = async (name, link, tag, reFetch, onExit, SetLoader, method, id=nanoid()) => {
function isValidHttpUrl(string) {
let url;
@@ -14,12 +14,12 @@ const addItem = async (name, link, tag, reFetch, onExit, SetLoader) => {
return url.protocol === "http:" || url.protocol === "https:";
}
- if(name !== '' && isValidHttpUrl(link) && tag !== '') {
+ if(isValidHttpUrl(link)) {
const ADDRESS = config.API.ADDRESS + ":" + config.API.PORT;
fetch(ADDRESS + "/api", {
- method: "POST",
+ method: method,
body: JSON.stringify({
- _id: nanoid(),
+ _id: id,
name: name,
title: '',
link: link,
@@ -30,17 +30,14 @@ const addItem = async (name, link, tag, reFetch, onExit, SetLoader) => {
}
})
.then(res => res.text())
- .then(message => {SetLoader(false)})
- .then(() => reFetch());
+ .then(() => reFetch())
+ .then(() => {SetLoader(false)});
onExit();
- } else if(name !== '' && link !== '' && tag !== '') {
+ } else {
+ SetLoader(false)
alert('Please make sure the link is valid.\n\n(i.e. starts with "http"/"https")');
}
-
- else {
- alert('Please fill all fields and make sure the link is valid.\n\n(i.e. starts with "http"/"https")');
- }
}
export default addItem;
\ No newline at end of file
diff --git a/src/styles/EditItem.css b/src/styles/EditItem.css
new file mode 100644
index 0000000..e69de29
diff --git a/src/styles/List.css b/src/styles/List.css
index 286bf0d..864c421 100644
--- a/src/styles/List.css
+++ b/src/styles/List.css
@@ -67,20 +67,28 @@
}
-.delete {
- color: white;
- cursor: pointer;
- transition: background-color 0.1s;
- font-family: 'Font Awesome 5 Free';
- padding: 10px;
- width: fit-content;
- height: fit-content;
- margin: 10px;
+.edit-btn {
+ position: relative;
border-radius: 100%;
+ margin: 20px 20px 20px 0px;
+ font-family: 'Font Awesome 5 Free';
+ width: 40px;
+ height: 40px;
+ padding: 10px;
+ font-size: 1.1rem;
+ cursor: pointer;
+ box-shadow: rgba(0, 0, 0, 0.4) 0px 2px 4px, rgba(0, 0, 0, 0.3) 0px 7px 13px -3px, rgba(0, 0, 0, 0.2) 0px -3px 0px inset;
+ color: #ffffffb6;
+ background-color: #1f2c38;
+ border: none;
+ transition: background-color 0.1s;
}
-.delete:hover {
- background-color: rgb(255, 123, 123);
+.edit-btn:hover {
+ background-color: rgb(76, 117, 170);
+}
+
+.edit-btn:active {
box-shadow: rgba(0, 0, 0, 0.16) 0px 3px 6px, rgba(0, 0, 0, 0.23) 0px 3px 6px;
}
@@ -111,7 +119,15 @@
font-size: 1rem;
}
-.options {
+.etc {
display: flex;
align-items: center;
}
+
+.delete {
+ float: right;
+}
+
+.delete:hover {
+ background-color: rgba(255, 65, 65, 0.8);
+}
\ No newline at end of file
diff --git a/src/styles/Loader.css b/src/styles/Loader.css
index 0451c27..29a84a1 100644
--- a/src/styles/Loader.css
+++ b/src/styles/Loader.css
@@ -1,6 +1,6 @@
.loader {
- position: absolute;
- bottom: 100px;
+ position: fixed;
+ bottom: 10%;
left: 30%;
right: 30%;
text-align: center;