Add History Drawer & Clean up APIs. Will clean up more when I am home and have updated the iOS app.
This commit is contained in:
		@@ -1,6 +1,7 @@
 | 
				
			|||||||
"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';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Technician = {
 | 
					type Technician = {
 | 
				
			||||||
  name: string;
 | 
					  name: string;
 | 
				
			||||||
@@ -10,27 +11,30 @@ type Technician = {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
export const GET = async (request: Request) => {
 | 
					export const GET = async (request: Request) => {
 | 
				
			||||||
  try {
 | 
					  try {
 | 
				
			||||||
    const url = new URL(request.url);
 | 
					    const session = await auth();
 | 
				
			||||||
    const apiKey = url.searchParams.get('apikey');
 | 
					    if (!session) {
 | 
				
			||||||
    if (apiKey !== process.env.API_KEY)
 | 
					      const url = new URL(request.url);
 | 
				
			||||||
      return NextResponse.json(
 | 
					      const apiKey = url.searchParams.get('apikey');
 | 
				
			||||||
        { message: 'Unauthorized' },
 | 
					      if (apiKey !== process.env.API_KEY)
 | 
				
			||||||
        { status: 401 }
 | 
					        return NextResponse.json(
 | 
				
			||||||
      );
 | 
					          { message: 'Unauthorized' },
 | 
				
			||||||
    const employees = await getEmployees();
 | 
					          { status: 401 }
 | 
				
			||||||
    // Necessary because I haven't updated the iOS app
 | 
					        );
 | 
				
			||||||
    // yet to expect updatedAt rather than time
 | 
					      else {
 | 
				
			||||||
    const formattedEmployees = employees.map((employee: Technician) => ({
 | 
					        const employees = await getEmployees();
 | 
				
			||||||
      name: employee.name,
 | 
					        const formattedEmployees = employees.map((employee: Technician) => ({
 | 
				
			||||||
      status: employee.status,
 | 
					          name: employee.name,
 | 
				
			||||||
      time: employee.updatedAt
 | 
					          status: employee.status,
 | 
				
			||||||
    }));
 | 
					          time: employee.updatedAt
 | 
				
			||||||
    return NextResponse.json(formattedEmployees, { status: 200 });
 | 
					        }));
 | 
				
			||||||
 | 
					        return NextResponse.json(formattedEmployees, { status: 200 });
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      const employees = await getEmployees();
 | 
				
			||||||
 | 
					      return NextResponse.json(employees, { status: 200 });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  } catch (error) {
 | 
					  } catch (error) {
 | 
				
			||||||
    console.error('Error fetching employees:', error);
 | 
					    console.error('Error fetching employees:', error);
 | 
				
			||||||
    return NextResponse.json(
 | 
					    return NextResponse.json({ message: 'Internal server error' }, { status: 500 });
 | 
				
			||||||
      { message: 'Internal server error' },
 | 
					 | 
				
			||||||
      { status: 500 }
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										44
									
								
								src/app/api/update_status_by_id/route.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								src/app/api/update_status_by_id/route.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,44 @@
 | 
				
			|||||||
 | 
					// Update Employee Status by IDs
 | 
				
			||||||
 | 
					"use server";
 | 
				
			||||||
 | 
					import { NextResponse } from 'next/server';
 | 
				
			||||||
 | 
					import type { NextRequest } from 'next/server';
 | 
				
			||||||
 | 
					import { updateEmployeeStatus } from '~/server/functions';
 | 
				
			||||||
 | 
					import { auth } from '~/auth';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type UpdateStatusBody = {
 | 
				
			||||||
 | 
					  employeeIds: string[];
 | 
				
			||||||
 | 
					  newStatus: string;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const POST = async (req: NextRequest) => {
 | 
				
			||||||
 | 
					  const session = await auth();
 | 
				
			||||||
 | 
					    if (!session) {
 | 
				
			||||||
 | 
					      const url = new URL(req.url);
 | 
				
			||||||
 | 
					      const apiKey = url.searchParams.get('apikey');
 | 
				
			||||||
 | 
					      if (apiKey !== process.env.API_KEY)
 | 
				
			||||||
 | 
					        return NextResponse.json(
 | 
				
			||||||
 | 
					          { message: 'Unauthorized' },
 | 
				
			||||||
 | 
					          { status: 401 }
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      const { employeeIds, newStatus } = await req.json() as UpdateStatusBody;
 | 
				
			||||||
 | 
					      if (!Array.isArray(employeeIds) || typeof newStatus !== 'string')
 | 
				
			||||||
 | 
					        return NextResponse.json(
 | 
				
			||||||
 | 
					          { message: 'Invalid input' },
 | 
				
			||||||
 | 
					          { status: 400 }
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					      try {
 | 
				
			||||||
 | 
					        await updateEmployeeStatus(employeeIds, newStatus);
 | 
				
			||||||
 | 
					        return NextResponse.json(
 | 
				
			||||||
 | 
					          { message: 'Status updated successfully' },
 | 
				
			||||||
 | 
					          { status: 200 }
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					      } catch (error) {
 | 
				
			||||||
 | 
					        console.error('Error updating status:', error);
 | 
				
			||||||
 | 
					        return NextResponse.json(
 | 
				
			||||||
 | 
					          { message: 'Internal server error' },
 | 
				
			||||||
 | 
					          { status: 500 }
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@@ -1,8 +1,9 @@
 | 
				
			|||||||
 | 
					// Update Employee Status by Names
 | 
				
			||||||
"use server";
 | 
					"use server";
 | 
				
			||||||
import { NextResponse } from 'next/server';
 | 
					import { NextResponse } from 'next/server';
 | 
				
			||||||
import { updateEmployeeStatusByName } from '~/server/functions';
 | 
					import { updateEmployeeStatusByName } from '~/server/functions';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface Technician {
 | 
					type Technician = {
 | 
				
			||||||
  name: string;
 | 
					  name: string;
 | 
				
			||||||
  status: string;
 | 
					  status: string;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,17 +0,0 @@
 | 
				
			|||||||
"use server";
 | 
					 | 
				
			||||||
import { NextResponse } from 'next/server';
 | 
					 | 
				
			||||||
import { getEmployees } from '~/server/functions';
 | 
					 | 
				
			||||||
import { auth } from '~/auth';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const GET = async () => {
 | 
					 | 
				
			||||||
  try {
 | 
					 | 
				
			||||||
    const session = await auth();
 | 
					 | 
				
			||||||
    if (!session)
 | 
					 | 
				
			||||||
      return NextResponse.json({ message: 'Unauthorized' }, { status: 401 });
 | 
					 | 
				
			||||||
    const employees = await getEmployees();
 | 
					 | 
				
			||||||
    return NextResponse.json(employees, { status: 200 });
 | 
					 | 
				
			||||||
  } catch (error) {
 | 
					 | 
				
			||||||
    console.error('Error fetching employees:', error);
 | 
					 | 
				
			||||||
    return NextResponse.json({ message: 'Internal server error' }, { status: 500 });
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
@@ -1,38 +0,0 @@
 | 
				
			|||||||
"use server";
 | 
					 | 
				
			||||||
import { NextResponse } from 'next/server';
 | 
					 | 
				
			||||||
import type { NextRequest } from 'next/server';
 | 
					 | 
				
			||||||
import { updateEmployeeStatus } from '~/server/functions';
 | 
					 | 
				
			||||||
import { auth } from '~/auth';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type UpdateStatusBody = {
 | 
					 | 
				
			||||||
  employeeIds: string[];
 | 
					 | 
				
			||||||
  newStatus: string;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const POST = async (req: NextRequest) => {
 | 
					 | 
				
			||||||
  const session = await auth();
 | 
					 | 
				
			||||||
  if (!session) 
 | 
					 | 
				
			||||||
    return NextResponse.json(
 | 
					 | 
				
			||||||
      { message: 'Unauthorized' },
 | 
					 | 
				
			||||||
      { status: 401 }
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
  const { employeeIds, newStatus } = await req.json() as UpdateStatusBody;
 | 
					 | 
				
			||||||
  if (!Array.isArray(employeeIds) || typeof newStatus !== 'string')
 | 
					 | 
				
			||||||
    return NextResponse.json(
 | 
					 | 
				
			||||||
      { message: 'Invalid input' },
 | 
					 | 
				
			||||||
      { status: 400 }
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
  try {
 | 
					 | 
				
			||||||
    await updateEmployeeStatus(employeeIds, newStatus);
 | 
					 | 
				
			||||||
    return NextResponse.json(
 | 
					 | 
				
			||||||
      { message: 'Status updated successfully' },
 | 
					 | 
				
			||||||
      { status: 200 }
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
  } catch (error) {
 | 
					 | 
				
			||||||
    console.error('Error updating status:', error);
 | 
					 | 
				
			||||||
    return NextResponse.json(
 | 
					 | 
				
			||||||
      { message: 'Internal server error' },
 | 
					 | 
				
			||||||
      { status: 500 }
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
@@ -1,27 +1,87 @@
 | 
				
			|||||||
import { Button } from "~/components/ui/shadcn/button";
 | 
					 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
  Drawer,
 | 
					 | 
				
			||||||
  DrawerClose,
 | 
					  DrawerClose,
 | 
				
			||||||
  DrawerContent,
 | 
					  DrawerContent,
 | 
				
			||||||
  DrawerDescription,
 | 
					 | 
				
			||||||
  DrawerFooter,
 | 
					  DrawerFooter,
 | 
				
			||||||
  DrawerHeader,
 | 
					  DrawerHeader,
 | 
				
			||||||
  DrawerTitle,
 | 
					  DrawerTitle,
 | 
				
			||||||
  DrawerTrigger,
 | 
					 | 
				
			||||||
} from "~/components/ui/shadcn/drawer";
 | 
					} from "~/components/ui/shadcn/drawer";
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  Table,
 | 
				
			||||||
 | 
					  TableBody,
 | 
				
			||||||
 | 
					  TableCell,
 | 
				
			||||||
 | 
					  TableHead,
 | 
				
			||||||
 | 
					  TableHeader,
 | 
				
			||||||
 | 
					  TableRow,
 | 
				
			||||||
 | 
					} from "~/components/ui/shadcn/table";
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  Pagination,
 | 
				
			||||||
 | 
					  PaginationContent,
 | 
				
			||||||
 | 
					  PaginationEllipsis,
 | 
				
			||||||
 | 
					  PaginationItem,
 | 
				
			||||||
 | 
					  PaginationLink,
 | 
				
			||||||
 | 
					  PaginationNext,
 | 
				
			||||||
 | 
					  PaginationPrevious,
 | 
				
			||||||
 | 
					} from "~/components/ui/shadcn/pagination";
 | 
				
			||||||
 | 
					//import { Button } from "~/components/ui/shadcn/button";
 | 
				
			||||||
 | 
					import Image from "next/image";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<Drawer>
 | 
					export default function History_Drawer() {
 | 
				
			||||||
  <DrawerTrigger>Open</DrawerTrigger>
 | 
					  //const 
 | 
				
			||||||
  <DrawerContent>
 | 
					  return (
 | 
				
			||||||
    <DrawerHeader>
 | 
					    <DrawerContent>
 | 
				
			||||||
      <DrawerTitle>Are you absolutely sure?</DrawerTitle>
 | 
					      <DrawerHeader>
 | 
				
			||||||
      <DrawerDescription>This action cannot be undone.</DrawerDescription>
 | 
					        <DrawerTitle>
 | 
				
			||||||
    </DrawerHeader>
 | 
					          <div className="flex flex-row items-center text-center
 | 
				
			||||||
    <DrawerFooter>
 | 
					            sm:justify-center sm:ml-0 py-4">
 | 
				
			||||||
      <Button>Submit</Button>
 | 
					            <Image src="/images/tech_tracker_logo.png"
 | 
				
			||||||
      <DrawerClose>
 | 
					              alt="Tech Tracker Logo" width={60} height={60}
 | 
				
			||||||
        <Button variant="outline">Cancel</Button>
 | 
					              className="max-w-[40px] md:max-w-[120px]"
 | 
				
			||||||
      </DrawerClose>
 | 
					            />
 | 
				
			||||||
    </DrawerFooter>
 | 
					            <h1 className="title-text text-sm md:text-2xl lg:text-6xl
 | 
				
			||||||
  </DrawerContent>
 | 
					              bg-gradient-to-r from-[#bec8e6] via-[#F0EEE4] to-[#FFF8E7]
 | 
				
			||||||
</Drawer>
 | 
					              font-bold pl-2 md:pl-4 text-transparent bg-clip-text">
 | 
				
			||||||
 | 
					              History
 | 
				
			||||||
 | 
					            </h1>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					        </DrawerTitle>
 | 
				
			||||||
 | 
					      </DrawerHeader>
 | 
				
			||||||
 | 
					      <Table className="w-5/6 lg:w-1/2 m-auto"
 | 
				
			||||||
 | 
					      >
 | 
				
			||||||
 | 
					        <TableHeader>
 | 
				
			||||||
 | 
					          <TableRow>
 | 
				
			||||||
 | 
					            <TableHead className="">Name</TableHead>
 | 
				
			||||||
 | 
					            <TableHead>Status</TableHead>
 | 
				
			||||||
 | 
					            <TableHead>Updated At</TableHead>
 | 
				
			||||||
 | 
					          </TableRow>
 | 
				
			||||||
 | 
					        </TableHeader>
 | 
				
			||||||
 | 
					        <TableBody>
 | 
				
			||||||
 | 
					          <TableRow>
 | 
				
			||||||
 | 
					            <TableCell className="font-medium">INV001</TableCell>
 | 
				
			||||||
 | 
					            <TableCell>Paid</TableCell>
 | 
				
			||||||
 | 
					            <TableCell>Credit Card</TableCell>
 | 
				
			||||||
 | 
					          </TableRow>
 | 
				
			||||||
 | 
					        </TableBody>
 | 
				
			||||||
 | 
					      </Table>
 | 
				
			||||||
 | 
					      <DrawerFooter>
 | 
				
			||||||
 | 
					        <Pagination>
 | 
				
			||||||
 | 
					          <PaginationContent>
 | 
				
			||||||
 | 
					            <PaginationItem>
 | 
				
			||||||
 | 
					              <PaginationPrevious href="#" />
 | 
				
			||||||
 | 
					            </PaginationItem>
 | 
				
			||||||
 | 
					            <PaginationItem>
 | 
				
			||||||
 | 
					              <PaginationLink href="#">1</PaginationLink>
 | 
				
			||||||
 | 
					            </PaginationItem>
 | 
				
			||||||
 | 
					            <PaginationItem>
 | 
				
			||||||
 | 
					              <PaginationEllipsis />
 | 
				
			||||||
 | 
					            </PaginationItem>
 | 
				
			||||||
 | 
					            <PaginationItem>
 | 
				
			||||||
 | 
					              <PaginationNext href="#" />
 | 
				
			||||||
 | 
					            </PaginationItem>
 | 
				
			||||||
 | 
					          </PaginationContent>
 | 
				
			||||||
 | 
					        </Pagination>
 | 
				
			||||||
 | 
					        <DrawerClose>
 | 
				
			||||||
 | 
					        </DrawerClose>
 | 
				
			||||||
 | 
					      </DrawerFooter>
 | 
				
			||||||
 | 
					    </DrawerContent>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,9 +3,10 @@ import { useState, useEffect, useCallback } from 'react';
 | 
				
			|||||||
import { useSession } from "next-auth/react";
 | 
					import { useSession } from "next-auth/react";
 | 
				
			||||||
import Loading from "~/components/ui/Loading";
 | 
					import Loading from "~/components/ui/Loading";
 | 
				
			||||||
import { useTVMode } from "~/components/context/TVModeContext";
 | 
					import { useTVMode } from "~/components/context/TVModeContext";
 | 
				
			||||||
 | 
					import { Drawer, DrawerTrigger } from "~/components/ui/shadcn/drawer";
 | 
				
			||||||
 | 
					import History_Drawer from "~/components/ui/History_Drawer";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Define the Employee interface to match data fetched on the server
 | 
					type Employee = {
 | 
				
			||||||
interface Employee {
 | 
					 | 
				
			||||||
  id: number;
 | 
					  id: number;
 | 
				
			||||||
  name: string;
 | 
					  name: string;
 | 
				
			||||||
  status: string;
 | 
					  status: string;
 | 
				
			||||||
@@ -22,7 +23,7 @@ export default function Tech_Table({ employees }: { employees: Employee[] }) {
 | 
				
			|||||||
  const [employeeData, setEmployeeData] = useState(employees);
 | 
					  const [employeeData, setEmployeeData] = useState(employees);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const fetch_employees = useCallback(async (): Promise<Employee[]> => {
 | 
					  const fetch_employees = useCallback(async (): Promise<Employee[]> => {
 | 
				
			||||||
    const res = await fetch('/api/v2/get_employees', {
 | 
					    const res = await fetch('/api/technicians', {
 | 
				
			||||||
      method: 'GET',
 | 
					      method: 'GET',
 | 
				
			||||||
      headers: {
 | 
					      headers: {
 | 
				
			||||||
        'Authorization': `Bearer ${process.env.API_KEY}`
 | 
					        'Authorization': `Bearer ${process.env.API_KEY}`
 | 
				
			||||||
@@ -35,12 +36,10 @@ export default function Tech_Table({ employees }: { employees: Employee[] }) {
 | 
				
			|||||||
    if (!session) {
 | 
					    if (!session) {
 | 
				
			||||||
      alert("You must be signed in to update status.");
 | 
					      alert("You must be signed in to update status.");
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    } else if (selectedIds.length === 0 && employeeStatus.trim() !== '') {
 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    if (selectedIds.length === 0 && employeeStatus.trim() !== '') {
 | 
					 | 
				
			||||||
      const cur_user = employees.find(employee => employee.name === session.user?.name);
 | 
					      const cur_user = employees.find(employee => employee.name === session.user?.name);
 | 
				
			||||||
      if (cur_user) {
 | 
					      if (cur_user) {
 | 
				
			||||||
        await fetch('/api/v2/update_status', {
 | 
					        await fetch('/api/update_status_by_id', {
 | 
				
			||||||
          method: 'POST',
 | 
					          method: 'POST',
 | 
				
			||||||
          headers: {
 | 
					          headers: {
 | 
				
			||||||
            'Content-Type': 'application/json',
 | 
					            'Content-Type': 'application/json',
 | 
				
			||||||
@@ -50,7 +49,7 @@ export default function Tech_Table({ employees }: { employees: Employee[] }) {
 | 
				
			|||||||
        });
 | 
					        });
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    } else if (employeeStatus.trim() !== '') {
 | 
					    } else if (employeeStatus.trim() !== '') {
 | 
				
			||||||
      await fetch('/api/v2/update_status', {
 | 
					      await fetch('/api/update_status_by_id', {
 | 
				
			||||||
        method: 'POST',
 | 
					        method: 'POST',
 | 
				
			||||||
        headers: {
 | 
					        headers: {
 | 
				
			||||||
          'Content-Type': 'application/json',
 | 
					          'Content-Type': 'application/json',
 | 
				
			||||||
@@ -165,9 +164,10 @@ export default function Tech_Table({ employees }: { employees: Employee[] }) {
 | 
				
			|||||||
              )}
 | 
					              )}
 | 
				
			||||||
              <th className="border border-[#3e4446] py-3">Name</th>
 | 
					              <th className="border border-[#3e4446] py-3">Name</th>
 | 
				
			||||||
              <th className="border border-[#3e4446] py-3">
 | 
					              <th className="border border-[#3e4446] py-3">
 | 
				
			||||||
                <button>
 | 
					                <Drawer>
 | 
				
			||||||
                  Status
 | 
					                  <DrawerTrigger>Status</DrawerTrigger>
 | 
				
			||||||
                </button>
 | 
					                    <History_Drawer />
 | 
				
			||||||
 | 
					                </Drawer>
 | 
				
			||||||
              </th>
 | 
					              </th>
 | 
				
			||||||
              <th className="border border-[#3e4446] py-3">Updated At</th>
 | 
					              <th className="border border-[#3e4446] py-3">Updated At</th>
 | 
				
			||||||
            </tr>
 | 
					            </tr>
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user