diff --git a/src/components/Cards/assignee-badge.tsx b/src/components/Cards/assignee-badge.tsx index edc49e1f..8c23d45a 100644 --- a/src/components/Cards/assignee-badge.tsx +++ b/src/components/Cards/assignee-badge.tsx @@ -1,29 +1,130 @@ +import { SyntheticEvent, useState } from "react"; import Image from "next/image"; +import { useRouter } from "next/router"; +import { RepairStatus } from "@prisma/client"; + +import Button from "@/components/Button"; +import Circle from "@/components/Cards/circle"; +import VolunteerCard from "@/components/Cards/volunteer-card"; +import Modal from "@/components/Modal"; +import { useRepairers } from "@/hooks/events"; +import { useUpdateRepairRequest } from "@/hooks/repair-request"; type Props = { - firstName?: string; - lastName?: string; - avatar?: string; + firstName: string | undefined; + lastName: string | undefined | null; + avatar?: string | undefined; + assignedTo?: string; + repairRequestId?: number; }; -export default function AssigneeBadge({ firstName, lastName, avatar }: Props) { +export default function AssigneeBadge({ + firstName, + lastName, + avatar, + assignedTo, + repairRequestId +}: Props) { + const [showAssigneeModal, setShowAssigneeModal] = useState(false); + const { + query: { id: eventId } + } = useRouter(); + const { data: repairers } = useRepairers(eventId as string); + const { mutate: updateRepairRequest } = + useUpdateRepairRequest(repairRequestId); + + const handleClick = (event: SyntheticEvent) => { + event.stopPropagation(); + setShowAssigneeModal(true); + }; + + const handleKeyDown = (event: React.KeyboardEvent) => { + if (event.key === "Enter" || event.key === " ") { + event.preventDefault(); + handleClick(event as SyntheticEvent); + } + }; + + const handleUnassignVolunteer = () => { + updateRepairRequest({ + assignedTo: "null", + status: RepairStatus.PENDING + }); + setShowAssigneeModal(false); + }; + + // Sort repairers to ensure the assigned repairer is displayed first + const sortedRepairers = repairers?.sort((a, b) => { + if (a.userId === assignedTo) return -1; + if (b.userId === assignedTo) return 1; + return 0; + }); + return ( -
-
-
- avatar -
-

{firstName}

- {!lastName ? "" :

{lastName}

} + <> +
+
+
+ avatar +
+

+ {firstName} {lastName ?? ""} +

+
-
+ +
+

Assign Volunteer

+
+ +

Task Assigned

+
+
+
+ {repairRequestId && + sortedRepairers && + sortedRepairers.map((repairer, index) => ( + + ))} +
+
+ + +
+
+ ); } diff --git a/src/components/Cards/card.tsx b/src/components/Cards/card.tsx new file mode 100644 index 00000000..29ef4f3a --- /dev/null +++ b/src/components/Cards/card.tsx @@ -0,0 +1,115 @@ +import { useState } from "react"; +import Image from "next/image"; +import { SubmitHandler } from "react-hook-form"; + +import AssigneeBadge from "@/components/Cards/assignee-badge"; +import StatusPill from "@/components/Cards/status-pill"; +import PrepopulatedRepairAttemptForm from "@/components/Forms/prepopulated-repair-request-form"; +import Modal from "@/components/Modal/index"; +import { useUpdateRepairRequest } from "@/hooks/repair-request"; +import { GeneralRepairAttempt, RepairRequestResponse } from "@/types"; + +export type CardProps = { + title?: number; + description?: string; + image?: string; + status?: string; + firstName?: string; + lastName?: string | null; + avatar?: string; + assignedTo?: string; + handleClick?: () => void; + repairRequestProps: RepairRequestResponse; +}; + +export default function Card({ props }: { props: CardProps }) { + function handleClick() { + setShowModal(true); + } + + const { mutate: updateRepairRequest } = useUpdateRepairRequest(props.title); + + const [showModal, setShowModal] = useState(false); + + const onSubmit: SubmitHandler = async (data) => { + updateRepairRequest(data, { + onSuccess: () => { + setShowModal(false); + } + }); + }; + + return ( +
+ +

+ Repair ID + {props.title} +

+ + + + } + setShowPopup={setShowModal} + showModal={showModal} + > +
+
+ +
+
+
+
+ hello +
+
+
+
+

+ Repair ID: +

+ +
+ +
+
+

{props.title}

+
+
+

+ {props.description} +

+
+
+ +
+
+
+ ); +} diff --git a/src/components/Cards/circle.tsx b/src/components/Cards/circle.tsx new file mode 100644 index 00000000..9cf7888e --- /dev/null +++ b/src/components/Cards/circle.tsx @@ -0,0 +1,11 @@ +type Props = { + numberOfTasks?: number; +}; + +export default function Circle({ numberOfTasks }: Props) { + return ( + + {numberOfTasks ?? ""} + + ); +} diff --git a/src/components/Cards/repair-request-card.tsx b/src/components/Cards/repair-request-card.tsx index 8f971013..a8cb40fd 100644 --- a/src/components/Cards/repair-request-card.tsx +++ b/src/components/Cards/repair-request-card.tsx @@ -130,7 +130,12 @@ export default function RepairRequestCard({
diff --git a/src/components/Cards/volunteer-card.tsx b/src/components/Cards/volunteer-card.tsx new file mode 100644 index 00000000..df35375d --- /dev/null +++ b/src/components/Cards/volunteer-card.tsx @@ -0,0 +1,143 @@ +import { useState } from "react"; +import { Inter } from "next/font/google"; +import Image from "next/image"; +import { RepairStatus } from "@prisma/client"; + +import Button from "@/components/Button"; +import Circle from "@/components/Cards/circle"; +import Modal from "@/components/Modal"; +import { useUpdateRepairRequest } from "@/hooks/repair-request"; + +type Props = { + userId: string; + firstName: string; + lastName: string; + email: string; + avatar: string; + acceptedTasksCount: number; + repairRequestId: number | undefined; + assigned: boolean; +}; + +const inter = Inter({ subsets: ["latin"] }); + +export default function VolunteerCard({ + userId, + firstName, + lastName, + avatar, + acceptedTasksCount, + repairRequestId, + assigned +}: Props) { + const { mutate: updateRepairRequest } = + useUpdateRepairRequest(repairRequestId); + const [showConfirmation, setShowConfirmation] = useState(false); + + const handleClick = () => { + setShowConfirmation(true); + }; + + const handleKeyDown = (event: React.KeyboardEvent) => { + if (event.key === "Enter" || event.key === " ") { + event.preventDefault(); + handleClick(); + } + }; + + const handleAssignVolunteer = () => { + updateRepairRequest({ + assignedTo: userId, + status: RepairStatus.ACCEPTED + }); + setShowConfirmation(false); + }; + + return ( +
+
+ {/* LEFT: Avatar of volunteer */} +
+ avatar +
+ + {/* MIDDLE */} +
+ {/* Name of volunteer*/} +

+ {firstName} {lastName ?? ""} +

+ {/* Skills */} +

+ Woodworking +

+

+ Bike Repair +

+
+ + {/* RIGHT: #. of assigned tasks */} +
+ +
+
+ + +
+

Assign Volunteer

+ +
+

+ Are you sure you want to assign this task to {firstName} + {lastName ? " " : ""} + {lastName ?? ""}? +

+ +
+ + + +
+
+
+
+
+ ); +} diff --git a/src/components/DropDown/skill-dropdown.tsx b/src/components/DropDown/skill-dropdown.tsx index f035b688..832efbc8 100644 --- a/src/components/DropDown/skill-dropdown.tsx +++ b/src/components/DropDown/skill-dropdown.tsx @@ -1,7 +1,8 @@ -import React, { useState, Fragment, useRef, useEffect } from "react"; +import React, { Fragment, useEffect, useRef, useState } from "react"; import { Menu, Transition } from "@headlessui/react"; +import { GoChevronDown, GoChevronUp } from "react-icons/go"; + import SelectedOption from "@/components/Tag/tag"; -import { GoChevronUp, GoChevronDown } from "react-icons/go"; // Define skills const options = [ diff --git a/src/components/FormFields/field-radio.tsx b/src/components/FormFields/field-radio.tsx index 829c4b23..64ff5765 100644 --- a/src/components/FormFields/field-radio.tsx +++ b/src/components/FormFields/field-radio.tsx @@ -13,6 +13,8 @@ export interface FormProps id?: string; label?: string; width?: string; + trueValue: string; + falseValue: string; } /* @@ -28,6 +30,8 @@ export default function FieldRadio({ id, label, width = "w-full", + trueValue, + falseValue, ...props }: FormProps) { const { field, fieldState } = useController(props); @@ -49,9 +53,9 @@ export default function FieldRadio({ Yes @@ -60,9 +64,9 @@ export default function FieldRadio({ No diff --git a/src/components/Forms/prepopulated-repair-request-form.tsx b/src/components/Forms/prepopulated-repair-request-form.tsx index e670f759..29e55e52 100644 --- a/src/components/Forms/prepopulated-repair-request-form.tsx +++ b/src/components/Forms/prepopulated-repair-request-form.tsx @@ -1,14 +1,25 @@ import { zodResolver } from "@hookform/resolvers/zod"; +import { RepairStatus } from "@prisma/client"; import { SubmitHandler, useForm } from "react-hook-form"; import Button from "@/components/Button"; +import FieldCheckbox from "@/components/check-box"; import FieldInput from "@/components/FormFields/field-input"; -import FieldRadio from "@/components/FormFields/field-radio"; import FieldSingleSelect from "@/components/FormFields/field-single-select"; import FieldTextArea from "@/components/FormFields/field-text-area"; import { ItemType, useItemTypes } from "@/hooks/item-types"; import { updateRepairRequestSchema } from "@/schema/repair-request"; -import type { GeneralRepairAttempt, RepairRequestResponse } from "@/types"; +import type { + GeneralRepairAttempt, + Option, + RepairRequestResponse +} from "@/types"; + +const REPAIR_STATUS_OPTIONS: Option[] = [ + { id: RepairStatus.PENDING, text: "Pending" }, + { id: RepairStatus.REPAIRED, text: "Repaired" }, + { id: RepairStatus.FAILED, text: "Failed" } +]; export default function PrepopulatedRepairAttemptForm({ props, @@ -19,16 +30,6 @@ export default function PrepopulatedRepairAttemptForm({ }) { const { data: itemTypes } = useItemTypes(); - let status; - switch (props.status) { - case "REPAIRED": - status = "true"; - break; - case "FAILED": - case "PENDING": - status = "false"; - } - let isSparePartsNeeded; props.spareParts == "" ? (isSparePartsNeeded = "false") @@ -37,11 +38,11 @@ export default function PrepopulatedRepairAttemptForm({ const { watch, control, handleSubmit } = useForm({ resolver: zodResolver(updateRepairRequestSchema), defaultValues: { - item: props.itemType, + itemType: props.itemType, itemBrand: props.itemBrand, itemMaterial: props.itemMaterial, hoursWorked: Number(props.hoursWorked), - isRepaired: status, + status: props.status, isSparePartsNeeded: isSparePartsNeeded, spareParts: props.spareParts, repairComment: props.repairComment @@ -55,7 +56,7 @@ export default function PrepopulatedRepairAttemptForm({ {/* ID, Item */}
- - ({ resolver: zodResolver(updateRepairRequestSchema), defaultValues: { - item: "", + itemType: "", itemBrand: "", itemMaterial: "", hoursWorked: undefined, - isRepaired: undefined, + status: RepairStatus.PENDING, isSparePartsNeeded: undefined, spareParts: "", repairComment: "" @@ -66,7 +72,7 @@ export default function RepairAttemptForm({ {/* ID, Item */}
- - {children}
+ {children}