Clean up all code

This commit is contained in:
Gabriel Brown 2024-07-21 21:12:34 -05:00
parent 017c07a1cf
commit 88f36531b1
10 changed files with 256 additions and 258 deletions

View File

@ -1,23 +1,25 @@
"use server"; "use server";
import { NextResponse } from 'next/server'; import { NextResponse } from 'next/server';
import { legacyGetHistory } from '~/server/functions'; import { getHistory } from '~/server/functions';
export const GET = async (request: Request) => { export const GET = async (request: Request) => {
try { try {
const url = new URL(request.url); const url = new URL(request.url);
const apiKey = url.searchParams.get('apikey'); const apiKey = url.searchParams.get('apikey');
const page = Number(url.searchParams.get('page')) || 1; const page = Number(url.searchParams.get('page')) || 1;
if (apiKey !== process.env.API_KEY)
if (apiKey !== 'zAf4vYVN2pszrK') { return NextResponse.json(
return NextResponse.json({ message: 'Unauthorized' }, { status: 401 }); { message: 'Unauthorized' },
} { status: 401 }
);
const perPage = 50; // You can adjust the perPage value as needed const perPage = 50;
const historyData = await legacyGetHistory(page, perPage); const historyData = await getHistory(page, perPage);
return NextResponse.json(historyData, { status: 200 }); return NextResponse.json(historyData, { status: 200 });
} catch (error) { } catch (error) {
console.error('Error fetching history data:', error); console.error('Error fetching history data:', error);
return NextResponse.json({ message: 'Internal server error' }, { status: 500 }); return NextResponse.json(
{ message: 'Internal server error' },
{ status: 500 }
);
} }
}; };

View File

@ -1,6 +1,6 @@
"use server"; "use server";
import { NextResponse } from 'next/server'; import { NextResponse } from 'next/server';
import { legacyGetEmployees } from '~/server/functions'; import { getEmployees } from '~/server/functions';
type Technician = { type Technician = {
name: string; name: string;
@ -12,22 +12,25 @@ export const GET = async (request: Request) => {
try { try {
const url = new URL(request.url); const url = new URL(request.url);
const apiKey = url.searchParams.get('apikey'); const apiKey = url.searchParams.get('apikey');
if (apiKey !== process.env.API_KEY)
if (apiKey !== 'zAf4vYVN2pszrK') { return NextResponse.json(
return NextResponse.json({ message: 'Unauthorized' }, { status: 401 }); { message: 'Unauthorized' },
} { status: 401 }
);
const employees = await legacyGetEmployees(); const employees = await getEmployees();
// Necessary because I haven't updated the iOS app
// yet to expect updatedAt rather than time
const formattedEmployees = employees.map((employee: Technician) => ({ const formattedEmployees = employees.map((employee: Technician) => ({
name: employee.name, name: employee.name,
status: employee.status, status: employee.status,
time: employee.updatedAt time: employee.updatedAt
})); }));
return NextResponse.json(formattedEmployees, { status: 200 }); return NextResponse.json(formattedEmployees, { status: 200 });
} catch (error) { } catch (error) {
console.error('Error fetching employees:', error); console.error('Error fetching employees:', error);
return NextResponse.json({ message: 'Internal server error' }, { status: 500 }); return NextResponse.json(
{ message: 'Internal server error' },
{ status: 500 }
);
} }
}; };

View File

@ -1,8 +1,7 @@
"use server"; "use server";
import { NextResponse } from 'next/server'; import { NextResponse } from 'next/server';
import { legacyUpdateEmployeeStatusByName } from '~/server/functions'; import { updateEmployeeStatusByName } from '~/server/functions';
// Define the Technician type directly in the file
interface Technician { interface Technician {
name: string; name: string;
status: string; status: string;
@ -11,37 +10,42 @@ interface Technician {
// Type guard to check if an object is a Technician // Type guard to check if an object is a Technician
const isTechnician = (technician: unknown): technician is Technician => { const isTechnician = (technician: unknown): technician is Technician => {
if (typeof technician !== 'object' || technician === null) return false; if (typeof technician !== 'object' || technician === null) return false;
return 'name' in technician && typeof (technician as Technician).name === 'string' && return 'name' in technician &&
'status' in technician && typeof (technician as Technician).status === 'string'; typeof (technician as Technician).name === 'string' &&
'status' in technician &&
typeof (technician as Technician).status === 'string';
}; };
export const POST = async (request: Request) => { export const POST = async (request: Request) => {
try { try {
const url = new URL(request.url); const url = new URL(request.url);
const apiKey = url.searchParams.get('apikey'); const apiKey = url.searchParams.get('apikey');
if (apiKey !== process.env.API_KEY)
if (apiKey !== 'zAf4vYVN2pszrK') {
return NextResponse.json({ message: 'Unauthorized' }, { status: 401 }); return NextResponse.json({ message: 'Unauthorized' }, { status: 401 });
}
const body: unknown = await request.json(); const body: unknown = await request.json();
// Validate the body and its technicians property // Validate the body and its technicians property
if (typeof body !== 'object' || body === null || !Array.isArray((body as { technicians?: unknown[] }).technicians)) { if (typeof body !== 'object' || body === null ||
return NextResponse.json({ message: 'Invalid input: expecting an array of technicians.' }, { status: 400 }); !Array.isArray((body as { technicians?: unknown[] }).technicians))
} return NextResponse.json(
{ message: 'Invalid input: expecting an array of technicians.' },
{ status: 400 }
);
const technicians = (body as { technicians: unknown[] }).technicians; const technicians = (body as { technicians: unknown[] }).technicians;
if (!technicians.every(isTechnician))
if (!technicians.every(isTechnician)) { return NextResponse.json(
return NextResponse.json({ message: 'Invalid input: missing name or status for a technician.' }, { status: 400 }); { message: 'Invalid input: missing name or status for a technician.' },
} { status: 400 }
);
await legacyUpdateEmployeeStatusByName(technicians); await updateEmployeeStatusByName(technicians);
return NextResponse.json(
return NextResponse.json({ message: 'Technicians updated successfully.' }, { status: 200 }); { message: 'Technicians updated successfully.' },
{ status: 200 }
);
} catch (error) { } catch (error) {
console.error('Error updating technicians:', error); console.error('Error updating technicians:', error);
return NextResponse.json({ message: 'Internal server error' }, { status: 500 }); return NextResponse.json(
{ message: 'Internal server error' },
{ status: 500 }
);
} }
}; };

View File

@ -1,5 +1,4 @@
"use server"; "use server";
import { NextResponse } from 'next/server'; import { NextResponse } from 'next/server';
import { getEmployees } from '~/server/functions'; import { getEmployees } from '~/server/functions';
import { auth } from '~/auth'; import { auth } from '~/auth';

View File

@ -12,19 +12,27 @@ type UpdateStatusBody = {
export const POST = async (req: NextRequest) => { export const POST = async (req: NextRequest) => {
const session = await auth(); const session = await auth();
if (!session) if (!session)
return NextResponse.json({ message: 'Unauthorized' }, { status: 401 }); return NextResponse.json(
{ message: 'Unauthorized' },
{ status: 401 }
);
const { employeeIds, newStatus } = await req.json() as UpdateStatusBody; const { employeeIds, newStatus } = await req.json() as UpdateStatusBody;
if (!Array.isArray(employeeIds) || typeof newStatus !== 'string')
if (!Array.isArray(employeeIds) || typeof newStatus !== 'string') { return NextResponse.json(
return NextResponse.json({ message: 'Invalid input' }, { status: 400 }); { message: 'Invalid input' },
} { status: 400 }
);
try { try {
await updateEmployeeStatus(employeeIds, newStatus); await updateEmployeeStatus(employeeIds, newStatus);
return NextResponse.json({ message: 'Status updated successfully' }, { status: 200 }); return NextResponse.json(
{ message: 'Status updated successfully' },
{ status: 200 }
);
} catch (error) { } catch (error) {
console.error('Error updating status:', error); console.error('Error updating status:', error);
return NextResponse.json({ message: 'Internal server error' }, { status: 500 }); return NextResponse.json(
{ message: 'Internal server error' },
{ status: 500 }
);
} }
}; };

View File

@ -7,7 +7,8 @@ import Sign_Out from "~/components/auth/Sign_Out";
import { type Metadata } from "next"; import { type Metadata } from "next";
export const metadata: Metadata = { export const metadata: Metadata = {
title: "Tech Tracker", title: "Tech Tracker",
description: "App used by COG IT employees to update their status throughout the day.", description: "App used by COG IT employees to \
update their status throughout the day.",
icons: [ icons: [
{ {
rel: 'icon', rel: 'icon',

View File

@ -9,8 +9,8 @@ export default async function HomePage() {
return <No_Session /> return <No_Session />
} else { } else {
return ( return (
<main className="min-h-screen bg-gradient-to-b <main className="min-h-screen
from-[#111111] to-[#212325]"> bg-gradient-to-b from-[#111111] to-[#212325]">
<TT_Header /> <TT_Header />
<Techs /> <Techs />
</main> </main>

View File

@ -3,15 +3,15 @@ import Image from "next/image";
export default function TT_Header() { export default function TT_Header() {
return ( return (
<header className="w-full py-2 pt-6 md:py-5"> <header className="w-full py-2 pt-6 md:py-5">
<div className="flex flex-row items-center text-center sm:justify-center <div className="flex flex-row items-center text-center
ml-4 sm:ml-0 p-4"> sm:justify-center ml-4 sm:ml-0 p-4">
<Image src="/images/tech_tracker_logo.png" <Image src="/images/tech_tracker_logo.png"
alt="Tech Tracker Logo" width={100} height={100} alt="Tech Tracker Logo" width={100} height={100}
className="max-w-[40px] md:max-w-[120px]" className="max-w-[40px] md:max-w-[120px]"
/> />
<h1 className="title-text text-sm md:text-4xl lg:text-8xl font-bold pl-2 md:pl-12 <h1 className="title-text text-sm md:text-4xl lg:text-8xl
bg-gradient-to-r from-[#bec8e6] via-[#F0EEE4] to-[#FFF8E7] bg-gradient-to-r from-[#bec8e6] via-[#F0EEE4] to-[#FFF8E7]
text-transparent bg-clip-text"> font-bold pl-2 md:pl-12 text-transparent bg-clip-text">
Tech Tracker Tech Tracker
</h1> </h1>
</div> </div>

View File

@ -19,19 +19,7 @@ export default function Table({ employees }: { employees: Employee[] }) {
const [employeeStatus, setStatus] = useState(''); const [employeeStatus, setStatus] = useState('');
const [employeeData, setEmployeeData] = useState(employees); const [employeeData, setEmployeeData] = useState(employees);
useEffect(() => { const fetch_employees = useCallback(async (): Promise<Employee[]> => {
if (status !== "loading") {
setLoading(false);
}
}, [status]);
useEffect(() => {
// Refresh employee data if needed after state updates
setEmployeeData(employees);
}, [employees]);
const fetchEmployees = useCallback(async (): Promise<Employee[]> => {
const res = await fetch('/api/v2/get_employees', { const res = await fetch('/api/v2/get_employees', {
method: 'GET', method: 'GET',
headers: { headers: {
@ -41,28 +29,39 @@ export default function Table({ employees }: { employees: Employee[] }) {
return res.json() as Promise<Employee[]>; return res.json() as Promise<Employee[]>;
}, []); }, []);
useEffect(() => { const update_status = async () => {
const fetchAndUpdateEmployees = async () => { if (!session) {
const updatedEmployees = await fetchEmployees(); alert("You must be signed in to update status.");
setEmployeeData(updatedEmployees); return;
}; }
// If no employee is selected and status is not empty
fetchAndUpdateEmployees() if (selectedIds.length === 0 && employeeStatus.trim() !== '') {
.catch((error) => { const cur_user = employees.find(employee => employee.name === session.user?.name);
console.error('Error fetching employees:', error); if (cur_user) {
}); await fetch('/api/v2/update_status', {
method: 'POST',
const intervalId = setInterval(() => { headers: {
(async () => { 'Content-Type': 'application/json',
await fetchAndUpdateEmployees(); 'Authorization': `Bearer ${process.env.API_KEY}`
})() },
.catch((error) => { body: JSON.stringify({ employeeIds: [cur_user.id], newStatus: employeeStatus }),
console.error('Error fetching employees:', error); });
}
} else if (employeeStatus.trim() !== '') {
await fetch('/api/v2/update_status', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${process.env.API_KEY}`
},
body: JSON.stringify({ employeeIds: selectedIds, newStatus: employeeStatus }),
}); });
}, 10000); // Poll every 10 seconds }
const updatedEmployees = await fetch_employees();
return () => clearInterval(intervalId); // Clear interval on component unmount setEmployeeData(updatedEmployees);
}, [fetchEmployees]); setSelectedIds([]);
setStatus('');
};
const handleCheckboxChange = (id: number) => { const handleCheckboxChange = (id: number) => {
setSelectedIds((prevSelected) => setSelectedIds((prevSelected) =>
@ -82,59 +81,18 @@ export default function Table({ employees }: { employees: Employee[] }) {
} }
}; };
useEffect(() => {
if (selectedIds.length === employeeData.length && employeeData.length > 0) {
setSelectAll(true);
} else {
setSelectAll(false);
}
}, [selectedIds, employeeData]);
const handleStatusChange = (e: React.ChangeEvent<HTMLInputElement>) => { const handleStatusChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setStatus(e.target.value); setStatus(e.target.value);
}; };
const handleSubmit = async () => { const handleKeyDown = async (e: React.KeyboardEvent<HTMLInputElement>) => {
if (!session) {
alert("You must be signed in to update status.");
return;
}
// If no employee is selected and status is not empty
if (selectedIds.length === 0 && employeeStatus.trim() !== '') {
const cur_user = employees.find(employee => employee.name === session.user?.name);
if (cur_user) {
await fetch('/api/v2/update_status', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${process.env.API_KEY}`
},
body: JSON.stringify({ employeeIds: [cur_user.id], newStatus: employeeStatus }),
});
}
} else if (employeeStatus.trim() !== '') {
await fetch('/api/v2/update_status', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${process.env.API_KEY}`
},
body: JSON.stringify({ employeeIds: selectedIds, newStatus: employeeStatus }),
});
}
// Optionally refresh data on the client-side after update
const updatedEmployees = await fetchEmployees();
setEmployeeData(updatedEmployees);
setSelectedIds([]);
setStatus('');
};
const handleKeyPress = async (e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === 'Enter') { if (e.key === 'Enter') {
await handleSubmit(); await update_status();
// if key is i then focus text input
} }
}; };
// Format time for display
const formatTime = (timestamp: Date) => { const formatTime = (timestamp: Date) => {
const date = new Date(timestamp); const date = new Date(timestamp);
const time = date.toLocaleTimeString('en-US', { const time = date.toLocaleTimeString('en-US', {
@ -145,64 +103,121 @@ const handleSubmit = async () => {
const month = date.toLocaleString('default', { month: 'long' }); const month = date.toLocaleString('default', { month: 'long' });
return `${time} - ${month} ${day}`; return `${time} - ${month} ${day}`;
}; };
// Loading bar while we wait for auth
useEffect(() => {
if (status !== "loading") {
setLoading(false);
}
}, [status]);
// Refresh employee data if needed after state updates
useEffect(() => {
setEmployeeData(employees);
}, [employees]);
// Fetch employees from the server every 10 seconds
useEffect(() => {
const fetchAndUpdateEmployees = async () => {
const updatedEmployees = await fetch_employees();
setEmployeeData(updatedEmployees);
};
fetchAndUpdateEmployees()
.catch((error) => {
console.error('Error fetching employees:', error);
});
const intervalId = setInterval(() => {
(async () => {
await fetchAndUpdateEmployees();
})()
.catch((error) => {
console.error('Error fetching employees:', error);
});
}, 10000); // Poll every 10 seconds
return () => clearInterval(intervalId); // Clear interval on component unmount
}, [fetch_employees]);
// Handle checkbox changes
useEffect(() => {
if (selectedIds.length === employeeData.length && employeeData.length > 0) {
setSelectAll(true);
} else {
setSelectAll(false);
}
}, [selectedIds, employeeData]);
if (loading) return <Loading interval_amount={3} />; if (loading) return <Loading interval_amount={3} />;
return ( else {
<div> return (
<table className="techtable rounded-2xl w-5/6 m-auto text-center text-[42px]"> <div>
<thead className="bg-gradient-to-b from-[#282828] to-[#383838]"> <table className="techtable rounded-2xl w-5/6 m-auto text-center text-[42px]">
<tr> <thead className="tabletitles border border-[#3e4446]
<th className="tabletitles p-4 border border-[#3e4446] text-[48px]"> bg-gradient-to-b from-[#282828] to-[#383838] text-[48px]">
<input <tr>
type="checkbox" <th className="py-3 px-4 border border-[#3e4446]">
className="m-0 cursor-pointer transform scale-150"
checked={selectAll}
onChange={handleSelectAllChange}
/>
</th>
<th className="tabletitles p-2 border border-[#3e4446] text-[48px]">Name</th>
<th className="tabletitles p-2 border border-[#3e4446] text-[48px]">Status</th>
<th className="tabletitles p-2 border border-[#3e4446] text-[48px]">Updated At</th>
</tr>
</thead>
<tbody>
{employeeData.map((employee) => (
<tr className="even:bg-gradient-to-br from-[#272727] to-[#313131]
odd:bg-gradient-to-bl odd:from-[#252525] odd:to-[#212125]" key={employee.id}>
<td className="p-1 border border-[#3e4446]">
<input <input
type="checkbox" type="checkbox"
className="m-0 cursor-pointer transform scale-150" className="m-auto cursor-pointer transform scale-150"
checked={selectedIds.includes(employee.id)} checked={selectAll}
onChange={() => handleCheckboxChange(employee.id)} onChange={handleSelectAllChange}
/> />
</td> </th>
<td className="n-column px-1 md:py-5 border border-[#3e4446]">{employee.name}</td> <th className="border border-[#3e4446]">Name</th>
<td className="s-column px-1 md:py-5 border border-[#3e4446]">{employee.status}</td> <th className="border border-[#3e4446]">Status</th>
<td className="ua-column px-1 md:py-5 border border-[#3e4446]">{formatTime(employee.updatedAt)}</td> <th className="border border-[#3e4446]">Updated At</th>
</tr> </tr>
))} </thead>
</tbody> <tbody>
</table> {employeeData.map((employee) => (
<div className="m-auto flex flex-row items-center justify-center py-5"> <tr className="even:bg-gradient-to-br from-[#272727] to-[#313131]
<input odd:bg-gradient-to-bl odd:from-[#252525] odd:to-[#212125]"
type="text" key={employee.id}
placeholder="New Status" >
className="min-w-[120px] lg:min-w-[400px] bg-[#F9F6EE] py-2 px-3 border-none rounded-xl text-[#111111] lg:text-2xl" <td className="p-1 border border-[#3e4446]">
value={employeeStatus} <input
onChange={handleStatusChange} type="checkbox"
onKeyDown={handleKeyPress} className="m-0 cursor-pointer transform scale-150"
/> checked={selectedIds.includes(employee.id)}
<button onChange={() => handleCheckboxChange(employee.id)}
type="submit" />
className="min-w-[100px] lg:min-w-[160px] m-2 p-2 border-none rounded-xl text-center </td>
font-semibold lg:text-2xl hover:text-slate-300 <td className="n-column px-1 md:py-5 border border-[#3e4446]">
hover:bg-gradient-to-bl hover:from-[#484848] hover:to-[#333333] {employee.name}
bg-gradient-to-br from-[#595959] to-[#444444]" </td>
onClick={handleSubmit} <td className="s-column px-1 md:py-5 border border-[#3e4446]">
> {employee.status}
Update </td>
</button> <td className="ua-column px-1 md:py-5 border border-[#3e4446]">
{formatTime(employee.updatedAt)}
</td>
</tr>
))}
</tbody>
</table>
<div className="m-auto flex flex-row items-center justify-center py-5">
<input
autoFocus
type="text"
placeholder="New Status"
className="min-w-[120px] lg:min-w-[400px] bg-[#F9F6EE]
py-2 px-3 border-none rounded-xl text-[#111111] lg:text-2xl"
value={employeeStatus}
onChange={handleStatusChange}
onKeyDown={handleKeyDown}
/>
<button
type="submit"
className="min-w-[100px] lg:min-w-[160px] m-2 p-2 border-none
rounded-xl text-center font-semibold lg:text-2xl hover:text-slate-300
hover:bg-gradient-to-bl hover:from-[#484848] hover:to-[#333333]
bg-gradient-to-br from-[#595959] to-[#444444]"
onClick={update_status}
>
Update
</button>
</div>
</div> </div>
</div> );
); }
} }

View File

@ -2,37 +2,29 @@ import "server-only";
import { db } from "~/server/db"; import { db } from "~/server/db";
import { sql } from "drizzle-orm"; import { sql } from "drizzle-orm";
// Function to Get Employees
export const getEmployees = async () => { export const getEmployees = async () => {
return await db.query.users.findMany({ return await db.query.users.findMany({
orderBy: (model, { asc }) => asc(model.id), orderBy: (model, { asc }) => asc(model.id),
}); });
}; };
// Uncomment this and change updatedAt below if using localhost and you want correct time. // Update Employee Status uses Raw SQL because Drizzle ORM doesn't support
// I dont know why it is like this. // update with MySQL
//const convertToUTC = (date: Date) => { export const updateEmployeeStatus =
//return new Date(date.setHours(date.getUTCHours())+ 5); async (employeeIds: string[], newStatus: string) => {
//};
// Function to Update Employee Status using Raw SQL
export const updateEmployeeStatus = async (employeeIds: string[], newStatus: string) => {
try { try {
// Convert array of ids to a format suitable for SQL query (comma-separated string) // Convert array of ids to a format suitable for SQL query (comma-separated string)
const idList = employeeIds.map(id => parseInt(id, 10)); const idList = employeeIds.map(id => parseInt(id, 10));
//const updatedAt = convertToUTC(new Date()); let updatedAt = new Date();
const updatedAt = new Date(); // Do not change for PROD! It acts different on PROD // Not sure why but localhost is off by 5 hours
if (process.env.NODE_ENV === 'development')
// Prepare the query using drizzle-orm's template-like syntax for escaping variables updatedAt = new Date(updatedAt.setHours(updatedAt.getUTCHours())+ 5);
const query = sql` const query = sql`
UPDATE users UPDATE users
SET status = ${newStatus}, updatedAt = ${updatedAt} SET status = ${newStatus}, updatedAt = ${updatedAt}
WHERE id IN ${idList} WHERE id IN ${idList}
`; `;
// Execute the query
await db.execute(query); await db.execute(query);
return { success: true }; return { success: true };
} catch (error) { } catch (error) {
console.error("Error updating employee status:", error); console.error("Error updating employee status:", error);
@ -40,15 +32,32 @@ export const updateEmployeeStatus = async (employeeIds: string[], newStatus: str
} }
}; };
// Legacy Functions for Legacy API for iOS App // Function to Update Employee Status by Name using Raw SQL
export const updateEmployeeStatusByName =
async (technicians:{ name: string, status: string }[]) => {
try {
for (const technician of technicians) {
const { name, status } = technician;
const query = sql`
UPDATE users
SET status = ${status}, updatedAt = ${new Date()}
WHERE name = ${name}
`;
await db.execute(query);
}
return { success: true };
} catch (error) {
console.error("Error updating employee status by name:", error);
throw new Error("Failed to update status by name");
}
};
// Type definitions // Type definitions for Paginated History API
interface HistoryEntry { interface HistoryEntry {
name: string; name: string;
status: string; status: string;
time: Date; time: Date;
} }
interface PaginatedHistory { interface PaginatedHistory {
data: HistoryEntry[]; data: HistoryEntry[];
meta: { meta: {
@ -59,25 +68,9 @@ interface PaginatedHistory {
} }
} }
export const legacyGetEmployees = async () => { export const getHistory =
const employees = await db.query.users.findMany({ async (page: number, perPage: number): Promise<PaginatedHistory> => {
orderBy: (model, { asc }) => asc(model.id),
});
if (employees.length === 0) {
return [];
}
for (const employee of employees) {
const date = new Date(employee.updatedAt);
employee.updatedAt = date;
}
return employees;
};
// Function to Get History Data with Pagination using Raw SQL
export const legacyGetHistory = async (page: number, perPage: number): Promise<PaginatedHistory> => {
const offset = (page - 1) * perPage; const offset = (page - 1) * perPage;
// Raw SQL queries
const historyQuery = sql` const historyQuery = sql`
SELECT u.name, h.status, h.updatedAt SELECT u.name, h.status, h.updatedAt
FROM history h FROM history h
@ -85,31 +78,26 @@ export const legacyGetHistory = async (page: number, perPage: number): Promise<P
ORDER BY h.id DESC ORDER BY h.id DESC
LIMIT ${perPage} OFFSET ${offset} LIMIT ${perPage} OFFSET ${offset}
`; `;
const countQuery = sql` const countQuery = sql`
SELECT COUNT(*) AS total_count SELECT COUNT(*) AS total_count
FROM history FROM history
`; `;
const [historyResults, countResults] = await Promise.all([ const [historyResults, countResults] = await Promise.all([
db.execute(historyQuery), db.execute(historyQuery),
db.execute(countQuery), db.execute(countQuery),
]); ]);
// Safely cast results // Safely cast results
const historyRows = historyResults[0] as unknown as { name: string, status: string, updatedAt: Date }[]; const historyRows = historyResults[0] as unknown as
{ name: string, status: string, updatedAt: Date }[];
const countRow = countResults[0] as unknown as { total_count: number }[]; const countRow = countResults[0] as unknown as { total_count: number }[];
const totalCount = countRow[0]?.total_count ?? 0; const totalCount = countRow[0]?.total_count ?? 0;
const totalPages = Math.ceil(totalCount / perPage); const totalPages = Math.ceil(totalCount / perPage);
// Format and map results // Format and map results
const formattedResults: HistoryEntry[] = historyRows.map(row => ({ const formattedResults: HistoryEntry[] = historyRows.map(row => ({
name: row.name, name: row.name,
status: row.status, status: row.status,
time: new Date(row.updatedAt), time: new Date(row.updatedAt),
})); }));
return { return {
data: formattedResults, data: formattedResults,
meta: { meta: {
@ -121,25 +109,3 @@ export const legacyGetHistory = async (page: number, perPage: number): Promise<P
}; };
}; };
// Function to Update Employee Status by Name using Raw SQL
export const legacyUpdateEmployeeStatusByName = async (technicians: { name: string, status: string }[]) => {
try {
// Prepare and execute the queries for each technician
for (const technician of technicians) {
const { name, status } = technician;
const utcdate: Date = new Date();
const query = sql`
UPDATE users
SET status = ${status}, updatedAt = ${utcdate}
WHERE name = ${name}
`;
await db.execute(query);
}
return { success: true };
} catch (error) {
console.error("Error updating employee status by name:", error);
throw new Error("Failed to update status by name");
}
};