Add legacy APIs so that I can migrate new app to techtracker.gibbyb.com and keep iOS app working
This commit is contained in:
		
							
								
								
									
										23
									
								
								src/app/api/history/route.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								src/app/api/history/route.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,23 @@
 | 
				
			|||||||
 | 
					"use server";
 | 
				
			||||||
 | 
					import { NextResponse } from 'next/server';
 | 
				
			||||||
 | 
					import { legacyGetHistory } from '~/server/functions';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const GET = async (request: Request) => {
 | 
				
			||||||
 | 
					  try {
 | 
				
			||||||
 | 
					    const url = new URL(request.url);
 | 
				
			||||||
 | 
					    const apiKey = url.searchParams.get('apikey');
 | 
				
			||||||
 | 
					    const page = Number(url.searchParams.get('page')) || 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (apiKey !== 'zAf4vYVN2pszrK') {
 | 
				
			||||||
 | 
					      return NextResponse.json({ message: 'Unauthorized' }, { status: 401 });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const perPage = 50; // You can adjust the perPage value as needed
 | 
				
			||||||
 | 
					    const historyData = await legacyGetHistory(page, perPage);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return NextResponse.json(historyData, { status: 200 });
 | 
				
			||||||
 | 
					  } catch (error) {
 | 
				
			||||||
 | 
					    console.error('Error fetching history data:', error);
 | 
				
			||||||
 | 
					    return NextResponse.json({ message: 'Internal server error' }, { status: 500 });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										33
									
								
								src/app/api/technicians/route.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								src/app/api/technicians/route.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,33 @@
 | 
				
			|||||||
 | 
					"use server";
 | 
				
			||||||
 | 
					import { NextResponse } from 'next/server';
 | 
				
			||||||
 | 
					import { legacyGetEmployees } from '~/server/functions';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Technician = {
 | 
				
			||||||
 | 
					  name: string;
 | 
				
			||||||
 | 
					  status: string;
 | 
				
			||||||
 | 
					  updatedAt: Date;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const GET = async (request: Request) => {
 | 
				
			||||||
 | 
					  try {
 | 
				
			||||||
 | 
					    const url = new URL(request.url);
 | 
				
			||||||
 | 
					    const apiKey = url.searchParams.get('apikey');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (apiKey !== 'zAf4vYVN2pszrK') {
 | 
				
			||||||
 | 
					      return NextResponse.json({ message: 'Unauthorized' }, { status: 401 });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const employees = await legacyGetEmployees();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const formattedEmployees = employees.map((employee: Technician) => ({
 | 
				
			||||||
 | 
					      name: employee.name,
 | 
				
			||||||
 | 
					      status: employee.status,
 | 
				
			||||||
 | 
					      time: employee.updatedAt
 | 
				
			||||||
 | 
					    }));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return NextResponse.json(formattedEmployees, { status: 200 });
 | 
				
			||||||
 | 
					  } catch (error) {
 | 
				
			||||||
 | 
					    console.error('Error fetching employees:', error);
 | 
				
			||||||
 | 
					    return NextResponse.json({ message: 'Internal server error' }, { status: 500 });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										44
									
								
								src/app/api/update_technicians/route.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								src/app/api/update_technicians/route.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,44 @@
 | 
				
			|||||||
 | 
					// src/app/api/update_technicians/route.ts
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"use server";
 | 
				
			||||||
 | 
					import { NextResponse } from 'next/server';
 | 
				
			||||||
 | 
					import { legacyUpdateEmployeeStatusByName } from '~/server/functions';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface Technician {
 | 
				
			||||||
 | 
					  name: string;
 | 
				
			||||||
 | 
					  status: string;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Type guard to check if an object is a Technician
 | 
				
			||||||
 | 
					const isTechnician = (technician: any): technician is Technician => {
 | 
				
			||||||
 | 
					  return typeof technician.name === 'string' && typeof technician.status === 'string';
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const POST = async (request: Request) => {
 | 
				
			||||||
 | 
					  try {
 | 
				
			||||||
 | 
					    const url = new URL(request.url);
 | 
				
			||||||
 | 
					    const apiKey = url.searchParams.get('apikey');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (apiKey !== 'zAf4vYVN2pszrK') {
 | 
				
			||||||
 | 
					      return NextResponse.json({ message: 'Unauthorized' }, { status: 401 });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const { technicians } = await request.json() as { technicians: Technician[] };
 | 
				
			||||||
 | 
					    if (!Array.isArray(technicians) || technicians.length === 0) {
 | 
				
			||||||
 | 
					      return NextResponse.json({ message: 'Invalid input: expecting an array of technicians.' }, { status: 400 });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (const technician of technicians) {
 | 
				
			||||||
 | 
					      if (!isTechnician(technician)) {
 | 
				
			||||||
 | 
					        return NextResponse.json({ message: 'Invalid input: missing name or status for a technician.' }, { status: 400 });
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    await legacyUpdateEmployeeStatusByName(technicians);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return NextResponse.json({ message: 'Technicians updated successfully.' }, { status: 200 });
 | 
				
			||||||
 | 
					  } catch (error) {
 | 
				
			||||||
 | 
					    console.error('Error updating technicians:', error);
 | 
				
			||||||
 | 
					    return NextResponse.json({ message: 'Internal server error' }, { status: 500 });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@@ -22,7 +22,7 @@ export default function Table({ employees }: { employees: Employee[] }) {
 | 
				
			|||||||
  }, [employees]);
 | 
					  }, [employees]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const fetchEmployees = useCallback(async (): Promise<Employee[]> => {
 | 
					  const fetchEmployees = useCallback(async (): Promise<Employee[]> => {
 | 
				
			||||||
    const res = await fetch('/api/get_employees', {
 | 
					    const res = await fetch('/api/v2/get_employees', {
 | 
				
			||||||
      method: 'GET',
 | 
					      method: 'GET',
 | 
				
			||||||
      headers: {
 | 
					      headers: {
 | 
				
			||||||
        'Authorization': `Bearer ${process.env.API_KEY}`
 | 
					        'Authorization': `Bearer ${process.env.API_KEY}`
 | 
				
			||||||
@@ -86,7 +86,7 @@ export default function Table({ employees }: { employees: Employee[] }) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  const handleSubmit = async () => {
 | 
					  const handleSubmit = async () => {
 | 
				
			||||||
    if (selectedIds.length > 0 && status.trim() !== '') {
 | 
					    if (selectedIds.length > 0 && status.trim() !== '') {
 | 
				
			||||||
      await fetch('/api/update_status', {
 | 
					      await fetch('/api/v2/update_status', {
 | 
				
			||||||
        method: 'POST',
 | 
					        method: 'POST',
 | 
				
			||||||
        headers: {
 | 
					        headers: {
 | 
				
			||||||
          'Content-Type': 'application/json',
 | 
					          'Content-Type': 'application/json',
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -32,3 +32,114 @@ export const updateEmployeeStatus = async (employeeIds: string[], newStatus: str
 | 
				
			|||||||
    throw new Error("Failed to update status");
 | 
					    throw new Error("Failed to update status");
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Legacy Functions for Legacy API for iOS App
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Type definitions
 | 
				
			||||||
 | 
					interface HistoryEntry {
 | 
				
			||||||
 | 
					  name: string;
 | 
				
			||||||
 | 
					  status: string;
 | 
				
			||||||
 | 
					  time: Date;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface PaginatedHistory {
 | 
				
			||||||
 | 
					  data: HistoryEntry[];
 | 
				
			||||||
 | 
					  meta: {
 | 
				
			||||||
 | 
					    current_page: number;
 | 
				
			||||||
 | 
					    per_page: number;
 | 
				
			||||||
 | 
					    total_pages: number;
 | 
				
			||||||
 | 
					    total_count: number;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Function to Convert Date to UTC
 | 
				
			||||||
 | 
					const convertToUTC = (date: Date): Date => {
 | 
				
			||||||
 | 
					  const utcDate = new Date(date.setHours(date.getUTCHours() - 15));
 | 
				
			||||||
 | 
					  return utcDate;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const legacyGetEmployees = async () => {
 | 
				
			||||||
 | 
					  const employees = await db.query.users.findMany({
 | 
				
			||||||
 | 
					    orderBy: (model, { asc }) => asc(model.id),
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					  if (employees.length === 0) {
 | 
				
			||||||
 | 
					    return [];
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  for (const employee of employees) {
 | 
				
			||||||
 | 
					    const date = new Date(employee.updatedAt);
 | 
				
			||||||
 | 
					    employee.updatedAt = convertToUTC(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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Raw SQL queries
 | 
				
			||||||
 | 
					  const historyQuery = sql`
 | 
				
			||||||
 | 
					    SELECT u.name, h.status, h.updatedAt
 | 
				
			||||||
 | 
					    FROM history h
 | 
				
			||||||
 | 
					    JOIN users u ON h.user_id = u.id
 | 
				
			||||||
 | 
					    ORDER BY h.id DESC
 | 
				
			||||||
 | 
					    LIMIT ${perPage} OFFSET ${offset}
 | 
				
			||||||
 | 
					  `;
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  const countQuery = sql`
 | 
				
			||||||
 | 
					    SELECT COUNT(*) AS total_count
 | 
				
			||||||
 | 
					    FROM history
 | 
				
			||||||
 | 
					  `;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const [historyResults, countResults] = await Promise.all([
 | 
				
			||||||
 | 
					    db.execute(historyQuery), 
 | 
				
			||||||
 | 
					    db.execute(countQuery),
 | 
				
			||||||
 | 
					  ]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Get the results properly as an array of rows
 | 
				
			||||||
 | 
					  const historyRows = historyResults[0] as { name: string, status: string, updatedAt: Date }[];
 | 
				
			||||||
 | 
					  const countRow = countResults[0] as { total_count: number }[];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const totalCount = countRow[0]?.total_count || 0;
 | 
				
			||||||
 | 
					  const totalPages = Math.ceil(totalCount / perPage);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Format and map results
 | 
				
			||||||
 | 
					  const formattedResults: HistoryEntry[] = historyRows.map(row => ({
 | 
				
			||||||
 | 
					    name: row.name,
 | 
				
			||||||
 | 
					    status: row.status,
 | 
				
			||||||
 | 
					    time: convertToUTC(new Date(row.updatedAt)),
 | 
				
			||||||
 | 
					  }));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return {
 | 
				
			||||||
 | 
					    data: formattedResults,
 | 
				
			||||||
 | 
					    meta: {
 | 
				
			||||||
 | 
					      current_page: page,
 | 
				
			||||||
 | 
					      per_page: perPage,
 | 
				
			||||||
 | 
					      total_pages: totalPages,
 | 
				
			||||||
 | 
					      total_count: totalCount,
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 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 date = new Date();
 | 
				
			||||||
 | 
					      const utcdate: Date = new Date(date.setHours(date.getUTCHours() - 12));
 | 
				
			||||||
 | 
					      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");
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user