Files
lst_v3/frontend/src/routes/admin/scanUsers.tsx

267 lines
6.3 KiB
TypeScript

import { useMutation, useSuspenseQuery } from "@tanstack/react-query";
import { createFileRoute, redirect } from "@tanstack/react-router";
import { createColumnHelper } from "@tanstack/react-table";
import { format } from "date-fns-tz";
import { Trash } from "lucide-react";
import { Suspense, useState } from "react";
import { toast } from "sonner";
import { Button } from "../../components/ui/button";
import { Spinner } from "../../components/ui/spinner";
import { api } from "../../lib/apiHelper";
import { authClient } from "../../lib/auth-client";
import { getScanUsers } from "../../lib/queries/getScanUsers";
import EditableCellInput from "../../lib/tableStuff/EditableCellInput";
import LstTable from "../../lib/tableStuff/LstTable";
import SearchableHeader from "../../lib/tableStuff/SearchableHeader";
import SkellyTable from "../../lib/tableStuff/SkellyTable";
import NewScanUser from "./-components/NewScanUser";
export const Route = createFileRoute("/admin/scanUsers")({
beforeLoad: async ({ location }) => {
const { data: session } = await authClient.getSession();
//const allowedRole = ["systemAdmin", "admin", "manager"];
const canAccess = await authClient.admin.hasPermission({
permissions: {
mobile: ["create"],
},
});
if (!session?.user) {
throw redirect({
to: "/",
search: {
redirect: location.href,
},
});
}
//if (!allowedRole.includes(session.user.role as string)) {
if (!canAccess) {
throw redirect({
to: "/",
});
}
return { user: session.user };
},
component: RouteComponent,
});
const updateSettings = async (
id: string,
data: Record<string, string | number | boolean | null>,
) => {
//console.log(id, data);
try {
const res = await api.patch(`/mobile/auth/user/${id}`, data, {
withCredentials: true,
timeout: 15000,
validateStatus: () => true,
});
toast.success(`User was just updated`);
return res;
} catch (err) {
toast.error("Error in updating the user");
return err;
}
};
const ScanUserTable = () => {
const { data, refetch } = useSuspenseQuery(getScanUsers());
const columnHelper = createColumnHelper<any>();
const updateSetting = useMutation({
mutationFn: ({
id,
field,
value,
}: {
id: string;
field: string;
value: string | number | boolean | null;
}) => updateSettings(id, { [field]: value }),
onSuccess: () => {
// refetch or update cache
refetch();
},
});
const columns = [
columnHelper.accessor("name", {
header: ({ column }) => (
<SearchableHeader column={column} title="Name" searchable={true} />
),
filterFn: "includesString",
cell: (i) => i.getValue(),
}),
columnHelper.accessor("scannerId", {
header: ({ column }) => (
<SearchableHeader
column={column}
title="Scanner ID"
searchable={false}
/>
),
filterFn: "includesString",
cell: (i) => i.getValue(),
}),
columnHelper.accessor("pinNumber", {
header: ({ column }) => (
<SearchableHeader column={column} title="Pin Number" />
),
filterFn: "includesString",
cell: ({ row, getValue }) => (
<div className="flex flex-row gap-2">
<div>
<EditableCellInput
value={getValue()}
id={row.original.id}
field="pinNumber"
onSubmit={({ id, field, value }) => {
updateSetting.mutate({ id, field, value });
}}
/>
</div>
<div className="">
<Button
type="button"
onClick={async () => {
const { data } = await api.get("/mobile/pin/new");
updateSetting.mutate({
id: row.original.id,
field: "pinNumber",
value: data.data[0].pin,
});
}}
>
New Pin
</Button>
</div>
</div>
),
}),
columnHelper.accessor("lastScan", {
header: ({ column }) => (
<SearchableHeader column={column} title="Last Scan" />
),
cell: (i) => <span>{format(i.getValue(), "M/d/yyyy HH:mm")}</span>,
}),
columnHelper.accessor("excludedCommand", {
header: ({ column }) => (
<SearchableHeader column={column} title="Command id's Not Allowed" />
),
cell: (i) => {
const commands = i.getValue().join();
return (
<span>{commands === "" ? "All commands allowed" : commands}</span>
);
},
}),
columnHelper.accessor("deleteUser", {
header: ({ column }) => (
<SearchableHeader
column={column}
title="Delete User"
searchable={false}
/>
),
filterFn: "includesString",
cell: (i) => {
// biome-ignore lint: just removing the lint for now to get this going will maybe fix later
const [activeToggle, setActiveToggle] = useState(false);
const onTrigger = async () => {
setActiveToggle(true);
try {
const res = await api.delete(
`/lst/api/mobile/auth/user/${i.row.original.id}`,
{
withCredentials: true,
timeout: 5000,
validateStatus: () => true,
},
);
if (res.data.success) {
toast.success(`${i.row.original.name} was deleted.`);
refetch();
setActiveToggle(false);
}
if (!res.data.success) {
toast.error(
`${i.row.original.name} encountered an error when trying to delete: ${res.data.message}`,
);
refetch();
setActiveToggle(false);
}
} catch (error) {
setActiveToggle(false);
console.error(error);
}
};
return (
<div>
<div className="flex items-center space-x-2">
<Button
variant="destructive"
disabled={activeToggle}
onClick={onTrigger}
>
{activeToggle ? (
<span>
<Spinner />
</span>
) : (
<span>
<Trash />
</span>
)}
</Button>
</div>
</div>
);
},
}),
];
return (
<div>
<div className="flex justify-end m-2">
<Suspense
fallback={
<div>
<p>Loading...</p>
</div>
}
>
<NewScanUser refetch={refetch} />
</Suspense>
</div>
<div>
<LstTable data={data} columns={columns} pageSize={50} />
</div>
</div>
);
};
// const NewUserForm = ()=>{
// const { data, refetch } = useSuspenseQuery(getScanUsers());
// }
function RouteComponent() {
//const { data: session } = useSession();
return (
<Suspense fallback={<SkellyTable />}>
<ScanUserTable />
</Suspense>
);
}