task-managment / src / app / dashboard / stock / _components / DialogUserTools.tsx
DialogUserTools.tsx
Raw
import { Button } from "@/components/ui/button";
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
  DialogTrigger,
} from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import React, { useEffect, useState } from "react";
import { trpc } from "@/app/_trpc/client";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";
import { useFormatZodErrors } from "@/hooks/useFormatZodErrors";
import Loading from "@/components/Loading";
import { useToast } from "@/components/ui/use-toast";
import { Tool } from "@/server/tool/domain/models";
import { SelectedTool } from "../types";

interface DialogAsignToolsProps{
  userId?:string,
  mode:'assign' | 'edit'
  selectedTools:SelectedTool[],
  setSelectedTools:React.Dispatch<React.SetStateAction<SelectedTool[]>>
}


export default function DialogUserTools({ userId:defaultUserId,mode,selectedTools, setSelectedTools }:DialogAsignToolsProps) {
  
  const {toast}=useToast()
  const {data:users,isFetching:isUserFetching}=trpc.users.getUsers.useQuery()

  const utils = trpc.useUtils();
  const [open, setOpen] = useState<boolean>(false);
  const {
    mutate: assignToolsToUsers,
    isPending:isPendingCreate,
    error,
  } = trpc.tools.assignToolsToUsers.useMutation({
    onSuccess: () => {
      setOpen(false);
      utils.tools.getTools.invalidate();
      toast({
        title:'Exito',
        description:'Herramienta asignada con exito',
      })
    },
    onError:(err)=>{
      toast({
        title:'Error',
        description:'Error al asignar herrramientas',
        variant:'destructive'
      })
    }
  });

  const { mutate: updateAssignedUserTools, isPending:isPendingUpdate } =
  trpc.users.updateAssignedUserTools.useMutation({
    onSuccess: () => {
      setOpen(false);
      utils.tools.getUserTools.invalidate();
    },
    onError(err){
      console.log('erro updating',err.data?.zodError)
    }
  });


  const {formatedErrors}=useFormatZodErrors(error)


  const handleAssignMaterials = (e:React.FormEvent<HTMLFormElement>) => {
    e.preventDefault();
    const formData = new FormData(e.currentTarget);
    const userId = formData.get('userId')as string ;
    const tools = selectedTools?.map(({ id, quantity,name }) => ({
      toolId: id,
      toolName:name,
      quantity,
      userId:userId || defaultUserId!,
    })) ?? []

    if(mode === 'assign'){
      assignToolsToUsers({ tools });
      return
    }
    updateAssignedUserTools({tools})
  };


  return (
    <Dialog open={open} onOpenChange={setOpen}>
      <DialogTrigger asChild className="w-full p-0 !m-0"> 
        <Button variant="outline" className="w-full " size="sm" disabled={selectedTools.length <= 0}>
          {mode === 'assign' ? 'Asignar':'Modificar'}
        </Button>
      </DialogTrigger>
      <DialogContent className="sm:max-w-[425px]">
        <DialogHeader>
          <DialogTitle>
            </DialogTitle>
            {mode === 'assign' ? 'Asignar herramientas':'Reasignar herramientas'}
          <DialogDescription>
            Asigna los materiales a tus empleados aqui.
          </DialogDescription>
        </DialogHeader>

        <form className="relative" onSubmit={handleAssignMaterials}>
          {
            isUserFetching  && (
              <div className="absolute  grid place-content-center inset-0">
              <Loading size={50}/>
           </div>
            )
          }
        
        {formatedErrors?.tools && <p className="text-destructive font-semibold text-sm mt-1">{formatedErrors.tools[0]}</p>}
          {
            selectedTools?.map((tool) => {
              return (
                <div key={tool.id} className="flex flex-col  py-4">
                  <div className="grid grid-cols-4 items-center gap-4">
                    <Label
                      htmlFor={`${tool}-${tool.id}`}
                      className="text-right capitalize"
                    >
                      {tool.name}
                    </Label>
                    <Input
                      id={`${tool}-${tool.id}`}
                      name="quantity"
                      type="number"
                      min={0}
                      max={tool?.inStock - parseInt(tool.totalAssignedUsers as any)}
                      defaultValue={0}
                      disabled={parseInt(tool.totalAssignedUsers as any)>= tool?.inStock}
                      className="col-span-3"
                      onChange={(e) => {
                        setSelectedTools((prev) => {
                          return prev.map((item) => {
                            if (item.id === tool.id) {
                              const updatedItem = item;
                              updatedItem.quantity = parseInt(e.target.value);
                              return updatedItem;
                            }
                            return item;
                          });
                        });
                      }}
                    />
                    <input type="hidden" name="toolId" value={tool.id}></input>
                  </div>


                  <div className=" col-span-2 text-end">
                    {tool.totalAssignedUsers >= tool?.inStock && (
                      <span className="text-xs text-red-600 font-semibold">
                        Todos los articulos ya estan asignados a otros usuarios
                      </span>
                    )}
                  </div>
                </div>
              );
            })}
          <div className="flex-1 flex gap-8 items-center gap">
            <Label className="block mb-1">Empleado</Label>
            <Select disabled={mode === 'edit'} name="userId" defaultValue={defaultUserId}>
                <SelectTrigger>
                  <SelectValue placeholder="Seleccionar empleado" />
                </SelectTrigger>
              <SelectContent>
                {users?.map((user) => (
                  <SelectItem key={user?.id} value={user?.id}>
                    {user?.firstName}
                  </SelectItem>
                ))}
              </SelectContent>
            </Select>
          </div>
          <DialogFooter className="mt-3">
            <Button type="submit" disabled={isPendingCreate || isPendingUpdate}>
              {isPendingCreate || isPendingUpdate ? <span>Guardando</span> : <span>Guardar</span>}
            </Button>
          </DialogFooter>
        </form>
      </DialogContent>
    </Dialog>
  );
}