1 Commits

Author SHA1 Message Date
478f03452d added take and return setter buttons 2025-08-28 21:12:58 +02:00
4 changed files with 147 additions and 5 deletions

View File

@@ -7,6 +7,8 @@ import {
deleteLoanFromDatabase, deleteLoanFromDatabase,
getBorrowableItemsFromDatabase, getBorrowableItemsFromDatabase,
createLoanInDatabase, createLoanInDatabase,
onTake,
onReturn,
} from "../services/database.js"; } from "../services/database.js";
import { authenticate, generateToken } from "../services/tokenService.js"; import { authenticate, generateToken } from "../services/tokenService.js";
const router = express.Router(); const router = express.Router();
@@ -85,6 +87,26 @@ router.post("/borrowableItems", authenticate, async (req, res) => {
} }
}); });
router.post("/takeLoan/:id", authenticate, async (req, res) => {
const loanId = req.params.id;
const result = await onTake(loanId);
if (result.success) {
res.status(200).json({ message: "Loan taken successfully" });
} else {
res.status(500).json({ message: "Failed to take loan" });
}
});
router.post("/returnLoan/:id", authenticate, async (req, res) => {
const loanId = req.params.id;
const result = await onReturn(loanId);
if (result.success) {
res.status(200).json({ message: "Loan returned successfully" });
} else {
res.status(500).json({ message: "Failed to return loan" });
}
});
router.post("/createLoan", authenticate, async (req, res) => { router.post("/createLoan", authenticate, async (req, res) => {
try { try {
const { items, startDate, endDate } = req.body || {}; const { items, startDate, endDate } = req.body || {};

View File

@@ -293,3 +293,29 @@ export const createLoanInDatabase = async (
conn.release(); conn.release();
} }
}; };
// These functions are only temporary, and will be deleted when the full bin is set up.
export const onTake = async (loanId) => {
const [result] = await pool.query(
"UPDATE loans SET take_date = NOW() WHERE id = ?",
[loanId]
);
if (result.affectedRows > 0) {
return { success: true };
}
return { success: false };
};
export const onReturn = async (loanId) => {
const [result] = await pool.query(
"UPDATE loans SET returned_date = NOW() WHERE id = ?",
[loanId]
);
if (result.affectedRows > 0) {
return { success: true };
}
return { success: false };
};

View File

@@ -4,6 +4,7 @@ import { handleDeleteLoan } from "../utils/userHandler";
import { useMutation, useQuery } from "@tanstack/react-query"; import { useMutation, useQuery } from "@tanstack/react-query";
import Cookies from "js-cookie"; import Cookies from "js-cookie";
import { queryClient } from "../utils/queryClient"; import { queryClient } from "../utils/queryClient";
import { onTake, onReturn } from "../utils/userHandler";
type Loan = { type Loan = {
id: number; id: number;
@@ -49,6 +50,20 @@ const Form4: React.FC = () => {
}, },
}); });
const takeMutation = useMutation({
mutationFn: (loanID: number) => onTake(loanID),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ["userLoans"] });
},
});
const returnMutation = useMutation({
mutationFn: (loanID: number) => onReturn(loanID),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ["userLoans"] });
},
});
const onDelete = (loanID: number) => deleteMutation.mutate(loanID); const onDelete = (loanID: number) => deleteMutation.mutate(loanID);
if (isFetching) { if (isFetching) {
@@ -99,11 +114,32 @@ const Form4: React.FC = () => {
</div> </div>
<div> <div>
<span className="text-slate-500">Abgeholt:</span>{" "} <span className="text-slate-500">Abgeholt:</span>{" "}
{formatDate(loan.take_date)} {loan.take_date ? (
formatDate(loan.take_date)
) : (
<button
className="inline-flex items-center rounded-md border border-blue-200 bg-blue-50 px-2 py-0.5 text-[11px] font-medium text-blue-700 hover:bg-blue-100 focus:outline-none focus:ring-2 focus:ring-blue-500/40 disabled:opacity-50"
onClick={() => takeMutation.mutate(loan.id)}
disabled={takeMutation.isPending}
>
{takeMutation.isPending ? "..." : "Abholen"}
</button>
)}
</div> </div>
<div> <div>
<span className="text-slate-500">Zurück:</span>{" "} <span className="text-slate-500">Zurück:</span>{" "}
{formatDate(loan.returned_date)} {loan.returned_date ? (
formatDate(loan.returned_date)
) : (
<button
className="inline-flex items-center rounded-md border border-emerald-200 bg-emerald-50 px-2 py-0.5 text-[11px] font-medium text-emerald-700 hover:bg-emerald-100 focus:outline-none focus:ring-2 focus:ring-emerald-500/40 disabled:opacity-50"
onClick={() => returnMutation.mutate(loan.id)}
disabled={returnMutation.isPending || !loan.take_date}
title={!loan.take_date ? "Erst abholen" : ""}
>
{returnMutation.isPending ? "..." : "Zurückgeben"}
</button>
)}
</div> </div>
</div> </div>
<div className="mt-2 text-xs text-slate-700"> <div className="mt-2 text-xs text-slate-700">
@@ -170,10 +206,31 @@ const Form4: React.FC = () => {
{formatDate(loan.end_date)} {formatDate(loan.end_date)}
</td> </td>
<td className="px-4 py-3 whitespace-nowrap font-mono tabular-nums text-slate-900"> <td className="px-4 py-3 whitespace-nowrap font-mono tabular-nums text-slate-900">
{formatDate(loan.take_date)} {loan.take_date ? (
formatDate(loan.take_date)
) : (
<button
className="inline-flex items-center rounded-md border border-blue-200 bg-blue-50 px-2 py-1 text-xs font-medium text-blue-700 hover:bg-blue-100 focus:outline-none focus:ring-2 focus:ring-blue-500/40 disabled:opacity-50"
onClick={() => takeMutation.mutate(loan.id)}
disabled={takeMutation.isPending}
>
{takeMutation.isPending ? "..." : "Abholen"}
</button>
)}
</td> </td>
<td className="px-4 py-3 whitespace-nowrap font-mono tabular-nums text-slate-900"> <td className="px-4 py-3 whitespace-nowrap font-mono tabular-nums text-slate-900">
{formatDate(loan.returned_date)} {loan.returned_date ? (
formatDate(loan.returned_date)
) : (
<button
className="inline-flex items-center rounded-md border border-emerald-200 bg-emerald-50 px-2 py-1 text-xs font-medium text-emerald-700 hover:bg-emerald-100 focus:outline-none focus:ring-2 focus:ring-emerald-500/40 disabled:opacity-50"
onClick={() => returnMutation.mutate(loan.id)}
disabled={returnMutation.isPending || !loan.take_date}
title={!loan.take_date ? "Erst abholen" : ""}
>
{returnMutation.isPending ? "..." : "Zurückgeben"}
</button>
)}
</td> </td>
<td className="px-4 py-3 whitespace-nowrap font-mono tabular-nums text-slate-900"> <td className="px-4 py-3 whitespace-nowrap font-mono tabular-nums text-slate-900">
{formatDate(loan.created_at)} {formatDate(loan.created_at)}
@@ -182,7 +239,7 @@ const Form4: React.FC = () => {
<div className="text-slate-900"> <div className="text-slate-900">
{Array.isArray(loan.loaned_items_name) {Array.isArray(loan.loaned_items_name)
? loan.loaned_items_name.join(", ") ? loan.loaned_items_name.join(", ")
: "-"} : ""}
</div> </div>
</td> </td>
<td className="px-4 py-3 text-right"> <td className="px-4 py-3 text-right">

View File

@@ -100,3 +100,40 @@ export const createLoan = async (startDate: string, endDate: string) => {
return true; return true;
}; };
export const onReturn = async (loanID: number) => {
const response = await fetch(
`http://localhost:8002/api/returnLoan/${loanID}`,
{
method: "POST",
headers: {
Authorization: `Bearer ${Cookies.get("token") || ""}`,
},
}
);
if (!response.ok) {
myToast("Fehler beim Zurückgeben der Ausleihe", "error");
return false;
}
myToast("Ausleihe erfolgreich zurückgegeben!", "success");
return true;
};
export const onTake = async (loanID: number) => {
const response = await fetch(`http://localhost:8002/api/takeLoan/${loanID}`, {
method: "POST",
headers: {
Authorization: `Bearer ${Cookies.get("token") || ""}`,
},
});
if (!response.ok) {
myToast("Fehler beim Ausleihen der Ausleihe", "error");
return false;
}
myToast("Ausleihe erfolgreich ausgeliehen!", "success");
return true;
};