Snai3i-MarketPlace / frontend / src / components / AssignTeachers / index.tsx
index.tsx
Raw
import {
  AlertDialog,
  AlertDialogAction,
  AlertDialogCancel,
  AlertDialogContent,
  // AlertDialogDescription,
  AlertDialogFooter,
  AlertDialogHeader,
  AlertDialogTitle,
  AlertDialogTrigger,
} from '@/components/ui/alert-dialog';
import {
  Select,
  SelectContent,
  SelectGroup,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from '@/components/ui/select';
import { Plus, Trash2Icon, XIcon } from 'lucide-react';
import { FC, MouseEventHandler, useState, useEffect } from 'react';
import { Button } from '@/components/ui/button';
import { useGetTachersBySchoolQuery } from '@/app/backend/endpoints/accounts';
import {
  useAssignTeacherMutation,
  useDeleteEnrollmentMutation,
  useGetAssignedTeachersByCourseAndSchoolQuery,
} from '@/app/backend/endpoints/enrollments';
import { toast } from 'sonner';
import { PlusIcon } from 'lucide-react';

type Props = {
  courseId: number;
  schoolId: number;
  maxNbTeachers: number;
  isSaving?: boolean;
  blue?: boolean;
  onClick?: MouseEventHandler<HTMLButtonElement> | undefined;
};

const AssignTeachers: FC<Props> = ({
  courseId,
  schoolId,
  maxNbTeachers,
  isSaving = false,
  onClick,
  blue = true,
}) => {
  const [fetch, setFetch] = useState<boolean>(false);
  const [assign, { isLoading: isAssigning }] = useAssignTeacherMutation();
  const [unassign, { isLoading: isUnassigning }] =
    useDeleteEnrollmentMutation();

  const { data: teachersData, isLoading: isTeachersLoading } =
    useGetTachersBySchoolQuery(schoolId, { skip: !fetch });
  const [teachers, setTeachers] = useState<TeacherI[] | undefined>([]);

  const {
    data: assignedTeachersData,
    // isLoading: isAssignedTeachersLoading,
    refetch: refetchAssignement,
  } = useGetAssignedTeachersByCourseAndSchoolQuery(
    { courseId, schoolId },
    { skip: !fetch }
  );

  const [assignements, setAssignements] = useState<
    {
      enrollment_id: number;
      teacher: TeacherI;
    }[]
  >([]);
  const assignedTeachers = assignements.map(
    (assignement) => assignement.teacher
  );

  const [selectedTeacher, setSelectedTeacher] = useState<
    number | null | undefined
  >(null);

  const handleAssignement = () => {
    assign({
      courseId,
      schoolId,
      teacherId: selectedTeacher!,
    })
      .unwrap()
      .then((response) => {
        toast.success(response.message);
        refetchAssignement();
        setSelectedTeacher(null);
      })
      .catch((error: any) => {
        toast.error(error?.data?.message ?? error?.error.toString());
        refetchAssignement();
        setSelectedTeacher(null);
      });
  };

  const handleUnassignement = (teacherId: number) => {
    const enrollmentId = assignements.find(
      (assignement) => assignement.teacher.teacher_id === teacherId
    )?.enrollment_id;
    if (enrollmentId)
      unassign({ enrollmentId })
        .unwrap()
        .then((response) => {
          toast.success(response.message);
          refetchAssignement();
          setSelectedTeacher(null);
        })
        .catch((error: any) => {
          toast.error(error?.data?.message ?? error?.error.toString());
          refetchAssignement();
          setSelectedTeacher(null);
        });
  };

  useEffect(() => {
    if (assignedTeachersData) {
      setAssignements(assignedTeachersData.data);
    }
    if (teachersData) {
      // filter out teachers that are already assigned
      setTeachers(
        teachersData.data.filter((teacher) => {
          return !assignedTeachers.find(
            (assignedTeacher) =>
              assignedTeacher.teacher_id === teacher.teacher_id
          );
        })
      );
    }
    return () => {
      setSelectedTeacher(null);
    };
  }, [assignedTeachersData, teachersData, assignements]);

  return (
    <AlertDialog>
      <AlertDialogTrigger asChild>
          {blue ? (
            <Button
              size="sm"
              onClick={() => {
                setFetch(true);
              }}
              className=" bg-white text-slate-700 font-semibold rounded-md py-3 border-2 shadow-none hover:bg-slate-100 hover:border-slate-200"
            >
              Assign Teachers
            </Button>
          ) : (
            <Button
              onClick={() => {
                setFetch(true);
              }}
              className="w-full flex flex-row gap-2 hover:bg-amber-600 rounded-xl"
            >
              <PlusIcon /> Assign Teachers
            </Button>
          )}
      </AlertDialogTrigger>
      <AlertDialogContent className="m-0 p-0 max-w-2xl">
        <AlertDialogHeader className="bg-slate-100 px-5 py-4 rounded-md">
          <div className="flex justify-between items-center rounded-md">
            <AlertDialogTitle className="font-inter">
              Assign Teachers
            </AlertDialogTitle>
            <AlertDialogCancel
              onClick={() => {
                setSelectedTeacher(null);
              }}
              className="w-fit h-fit p-0 m-0 rounded-md border-none bg-transparent shadow-none"
            >
              <XIcon className="h-4 w-4" />
            </AlertDialogCancel>
          </div>
        </AlertDialogHeader>
        {/* <AlertDialogDescription className="px-5"> */}
        <div className="space-y-3 px-5">
          {assignedTeachers.map((teacher) => (
            <div key={teacher.teacher_id}>
              <div className="flex justify-between p-2 py-3 border rounded-md">
                <div className="flex items-center space-x-3">
                  <img
                    draggable={false}
                    src="/teacher.png"
                    alt="teacher"
                    className="w-8 h-8 rounded-full"
                  />
                  <div className="flex flex-col">
                    <span className="font-inter text-xs font-semibold text-slate-800">
                      {teacher.firstName} {teacher.lastName}
                    </span>
                    <span className="font-inter text-xs">{teacher.email}</span>
                  </div>
                </div>
                <Button
                  onClick={() => handleUnassignement(teacher.teacher_id!)}
                  variant="outline"
                  size="sm"
                  className="rounded-md p-2"
                >
                  <Trash2Icon className="text-destructive" size={17} />
                </Button>
              </div>
            </div>
          ))}
          <div className="space-y-2">
            <span className="font-inter text-xs font-semibold text-slate-800">
              Teacher {assignedTeachers.length + 1}
            </span>
            <Select
              disabled={teachers?.length === 0}
              onValueChange={(value) => {
                setSelectedTeacher(Number(value));
              }}
              value={selectedTeacher?.toString() ?? ''}
            >
              <SelectTrigger>
                <SelectValue
                  placeholder={
                    isTeachersLoading
                      ? 'Loading...'
                      : teachers?.length === 0
                      ? 'No teachers available to assign'
                      : 'Select teacher'
                  }
                />
              </SelectTrigger>
              <SelectContent>
                <SelectGroup>
                  {teachers?.map((teacher) => (
                    <SelectItem
                      key={teacher.teacher_id}
                      value={teacher.teacher_id?.toString()}
                    >
                      {teacher.firstName} {teacher.lastName}
                    </SelectItem>
                  ))}
                </SelectGroup>
              </SelectContent>
            </Select>
            <div className="flex items-center justify-between text-xs text-slate-800 font-medium">
              <Button
                size="sm"
                onClick={handleAssignement}
                disabled={
                  assignedTeachers.length >= maxNbTeachers ||
                  isSaving ||
                  teachers?.length === 0 ||
                  selectedTeacher === null
                }
                className=" flex items-center space-x-1 px-2 bg-white text-slate-700 font-medium  rounded-md py-3 border shadow-none hover:bg-slate-100 hover:border-slate-200"
              >
                <Plus size={15} /> <span className="font-inter">Assign</span>
              </Button>
              <span className="font-inter">
                {/* // if bellows teachers.length < maxNbTeachers then show 0 */}
                You can add{' '}
                {maxNbTeachers - assignedTeachers.length > 0
                  ? maxNbTeachers - assignedTeachers.length
                  : 0}{' '}
                more teachers
              </span>
            </div>
          </div>
        </div>
        {/* </AlertDialogDescription> */}
        <AlertDialogFooter className="px-5 pb-7">
          <AlertDialogAction
            onClick={onClick}
            className="rounded-md h-8"
            disabled={isSaving || isAssigning || isUnassigning}
          >
            Save
          </AlertDialogAction>
        </AlertDialogFooter>
      </AlertDialogContent>
    </AlertDialog>
  );
};

export default AssignTeachers;