Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
215 changes: 117 additions & 98 deletions mern/client/src/components/RecordList.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,109 +2,128 @@ import { useEffect, useState } from "react";
import { Link } from "react-router-dom";

const Record = (props) => (
<tr className="border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted">
<td className="p-4 align-middle [&amp;:has([role=checkbox])]:pr-0">
{props.record.name}
</td>
<td className="p-4 align-middle [&amp;:has([role=checkbox])]:pr-0">
{props.record.position}
</td>
<td className="p-4 align-middle [&amp;:has([role=checkbox])]:pr-0">
{props.record.level}
</td>
<td className="p-4 align-middle [&amp;:has([role=checkbox])]:pr-0">
<div className="flex gap-2">
<Link
className="inline-flex items-center justify-center whitespace-nowrap text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 border border-input bg-background hover:bg-slate-100 h-9 rounded-md px-3"
to={`/edit/${props.record._id}`}
>
Edit
</Link>
<button
className="inline-flex items-center justify-center whitespace-nowrap text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 border border-input bg-background hover:bg-slate-100 hover:text-accent-foreground h-9 rounded-md px-3"
color="red"
type="button"
onClick={() => {
props.deleteRecord(props.record._id);
}}
>
Delete
</button>
</div>
</td>
</tr>
<tr className="border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted">
<td className="p-4 align-middle [&amp;:has([role=checkbox])]:pr-0">
{props.record.name}
</td>
<td className="p-4 align-middle [&amp;:has([role=checkbox])]:pr-0">
{props.record.position}
</td>
<td className="p-4 align-middle [&amp;:has([role=checkbox])]:pr-0">
{props.record.level}
</td>
<td className="p-4 align-middle [&amp;:has([role=checkbox])]:pr-0">
<div className="flex gap-2">
<Link
className="inline-flex items-center justify-center whitespace-nowrap text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 border border-input bg-background hover:bg-slate-100 h-9 rounded-md px-3"
to={`/edit/${props.record._id}`}
>
Edit
</Link>
<button
className="inline-flex items-center justify-center whitespace-nowrap text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 border border-input bg-background hover:bg-slate-100 hover:text-accent-foreground h-9 rounded-md px-3"
color="red"
type="button"
onClick={() => {
props.deleteRecord(props.record._id);
}}
>
Delete
</button>
</div>
</td>
</tr>
);

export default function RecordList() {
const [records, setRecords] = useState([]);
const [records, setRecords] = useState([]);
const [search, setSearch] = useState("");
const [debouncedSearch, setDebouncedSearch] = useState("");

// This method fetches the records from the database.
useEffect(() => {
async function getRecords() {
const response = await fetch(`http://localhost:5050/record/`);
if (!response.ok) {
const message = `An error occurred: ${response.statusText}`;
console.error(message);
return;
}
const records = await response.json();
setRecords(records);
}
getRecords();
return;
}, [records.length]);
// This method fetches the records from the database.
useEffect(() => {
async function getRecords() {
const response = await fetch(
`http://localhost:5050/record?search=${debouncedSearch}`
);
if (!response.ok) {
const message = `An error occurred: ${response.statusText}`;
console.error(message);
return;
}
const records = await response.json();
setRecords(records);
}
getRecords();
return;
}, [records.length, debouncedSearch]);

// This method will delete a record
async function deleteRecord(id) {
await fetch(`http://localhost:5050/record/${id}`, {
method: "DELETE",
});
const newRecords = records.filter((el) => el._id !== id);
setRecords(newRecords);
}
useEffect(() => {
const timeout = setTimeout(() => {
setDebouncedSearch(search);
}, 300);
return () => clearTimeout(timeout);
}, [search]);

// This method will map out the records on the table
function recordList() {
return records.map((record) => {
return (
<Record
record={record}
deleteRecord={() => deleteRecord(record._id)}
key={record._id}
/>
);
});
}
// This method will delete a record
async function deleteRecord(id) {
await fetch(`http://localhost:5050/record/${id}`, {
method: "DELETE",
});
const newRecords = records.filter((el) => el._id !== id);
setRecords(newRecords);
}

// This following section will display the table with the records of individuals.
return (
<>
<h3 className="text-lg font-semibold p-4">Employee Records</h3>
<div className="border rounded-lg overflow-hidden">
<div className="relative w-full overflow-auto">
<table className="w-full caption-bottom text-sm">
<thead className="[&amp;_tr]:border-b">
<tr className="border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted">
<th className="h-12 px-4 text-left align-middle font-medium text-muted-foreground [&amp;:has([role=checkbox])]:pr-0">
Name
</th>
<th className="h-12 px-4 text-left align-middle font-medium text-muted-foreground [&amp;:has([role=checkbox])]:pr-0">
Position
</th>
<th className="h-12 px-4 text-left align-middle font-medium text-muted-foreground [&amp;:has([role=checkbox])]:pr-0">
Level
</th>
<th className="h-12 px-4 text-left align-middle font-medium text-muted-foreground [&amp;:has([role=checkbox])]:pr-0">
Action
</th>
</tr>
</thead>
<tbody className="[&amp;_tr:last-child]:border-0">
{recordList()}
</tbody>
</table>
</div>
</div>
</>
);
// This method will map out the records on the table
function recordList() {
return records.map((record) => {
return (
<Record
record={record}
deleteRecord={() => deleteRecord(record._id)}
key={record._id}
/>
);
});
}

// This following section will display the table with the records of individuals.
return (
<>
<h3 className="text-lg font-semibold p-4">Employee Records</h3>
<div className="flex justify-between p-4">
<input
className="w-1/2 p-2 border rounded-md"
type="text"
placeholder="Search"
onChange={(e) => setSearch(e.target.value)}
/>
</div>
<div className="border rounded-lg overflow-hidden">
<div className="relative w-full overflow-auto">
<table className="w-full caption-bottom text-sm">
<thead className="[&amp;_tr]:border-b">
<tr className="border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted">
<th className="h-12 px-4 text-left align-middle font-medium text-muted-foreground [&amp;:has([role=checkbox])]:pr-0">
Name
</th>
<th className="h-12 px-4 text-left align-middle font-medium text-muted-foreground [&amp;:has([role=checkbox])]:pr-0">
Position
</th>
<th className="h-12 px-4 text-left align-middle font-medium text-muted-foreground [&amp;:has([role=checkbox])]:pr-0">
Level
</th>
<th className="h-12 px-4 text-left align-middle font-medium text-muted-foreground [&amp;:has([role=checkbox])]:pr-0">
Action
</th>
</tr>
</thead>
<tbody className="[&amp;_tr:last-child]:border-0">
{recordList()}
</tbody>
</table>
</div>
</div>
</>
);
}
106 changes: 60 additions & 46 deletions mern/server/routes/record.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,72 +13,86 @@ const router = express.Router();

// This section will help you get a list of all the records.
router.get("/", async (req, res) => {
let collection = await db.collection("records");
let results = await collection.find({}).toArray();
res.send(results).status(200);
let collection = await db.collection("records");
let searchQuery = req.query.search;
let results = [];
if (searchQuery) {
// Search among 2 parameters Name or Position
results = await collection
.find({
$or: [
{ name: { $regex: searchQuery, $options: "i" } },
{ position: { $regex: searchQuery, $options: "i" } },
],
})
.toArray();
} else {
results = await collection.find({}).toArray();
}
res.send(results).status(200);
});

// This section will help you get a single record by id
router.get("/:id", async (req, res) => {
let collection = await db.collection("records");
let query = { _id: new ObjectId(req.params.id) };
let result = await collection.findOne(query);
let collection = await db.collection("records");
let query = { _id: new ObjectId(req.params.id) };
let result = await collection.findOne(query);

if (!result) res.send("Not found").status(404);
else res.send(result).status(200);
if (!result) res.send("Not found").status(404);
else res.send(result).status(200);
});

// This section will help you create a new record.
router.post("/", async (req, res) => {
try {
let newDocument = {
name: req.body.name,
position: req.body.position,
level: req.body.level,
};
let collection = await db.collection("records");
let result = await collection.insertOne(newDocument);
res.send(result).status(204);
} catch (err) {
console.error(err);
res.status(500).send("Error adding record");
}
try {
let newDocument = {
name: req.body.name,
position: req.body.position,
level: req.body.level,
};
let collection = await db.collection("records");
let result = await collection.insertOne(newDocument);
res.send(result).status(204);
} catch (err) {
console.error(err);
res.status(500).send("Error adding record");
}
});

// This section will help you update a record by id.
router.patch("/:id", async (req, res) => {
try {
const query = { _id: new ObjectId(req.params.id) };
const updates = {
$set: {
name: req.body.name,
position: req.body.position,
level: req.body.level,
},
};
try {
const query = { _id: new ObjectId(req.params.id) };
const updates = {
$set: {
name: req.body.name,
position: req.body.position,
level: req.body.level,
},
};

let collection = await db.collection("records");
let result = await collection.updateOne(query, updates);
res.send(result).status(200);
} catch (err) {
console.error(err);
res.status(500).send("Error updating record");
}
let collection = await db.collection("records");
let result = await collection.updateOne(query, updates);
res.send(result).status(200);
} catch (err) {
console.error(err);
res.status(500).send("Error updating record");
}
});

// This section will help you delete a record
router.delete("/:id", async (req, res) => {
try {
const query = { _id: new ObjectId(req.params.id) };
try {
const query = { _id: new ObjectId(req.params.id) };

const collection = db.collection("records");
let result = await collection.deleteOne(query);
const collection = db.collection("records");
let result = await collection.deleteOne(query);

res.send(result).status(200);
} catch (err) {
console.error(err);
res.status(500).send("Error deleting record");
}
res.send(result).status(200);
} catch (err) {
console.error(err);
res.status(500).send("Error deleting record");
}
});

export default router;