Compare commits
4 Commits
debian12
...
debian12_v
Author | SHA1 | Date | |
---|---|---|---|
1b15cf96e8 | |||
bb7f66ecc7 | |||
59de6d69d9 | |||
478f03452d |
@@ -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 || {};
|
||||||
|
@@ -294,3 +294,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 };
|
||||||
|
};
|
||||||
|
@@ -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">
|
||||||
|
@@ -75,14 +75,17 @@ export const rmFromRemove = (itemID: number) => {
|
|||||||
|
|
||||||
export const createLoan = async (startDate: string, endDate: string) => {
|
export const createLoan = async (startDate: string, endDate: string) => {
|
||||||
const items = removeArr;
|
const items = removeArr;
|
||||||
const response = await fetch("https://backend.insta.the1s.de/api/createLoan", {
|
const response = await fetch(
|
||||||
method: "POST",
|
"https://backend.insta.the1s.de/api/createLoan",
|
||||||
headers: {
|
{
|
||||||
"Content-Type": "application/json",
|
method: "POST",
|
||||||
Authorization: `Bearer ${Cookies.get("token") || ""}`,
|
headers: {
|
||||||
},
|
"Content-Type": "application/json",
|
||||||
body: JSON.stringify({ items, startDate, endDate }),
|
Authorization: `Bearer ${Cookies.get("token") || ""}`,
|
||||||
});
|
},
|
||||||
|
body: JSON.stringify({ items, startDate, endDate }),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
myToast("Fehler beim Erstellen der Ausleihe", "error");
|
myToast("Fehler beim Erstellen der Ausleihe", "error");
|
||||||
@@ -100,3 +103,43 @@ export const createLoan = async (startDate: string, endDate: string) => {
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const onReturn = async (loanID: number) => {
|
||||||
|
const response = await fetch(
|
||||||
|
`https://backend.insta.the1s.de/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(
|
||||||
|
`https://backend.insta.the1s.de/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;
|
||||||
|
};
|
||||||
|
Reference in New Issue
Block a user