Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue 176 assign volunteers to repair request #237

Open
wants to merge 33 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
c8512dd
initial commit
ellenxxxiao Jan 20, 2024
81e12a3
Remove the ESLint warning
Elefantat Jan 20, 2024
7c415c9
Merge branch 'main' of https://github.com/codersforcauses/repair-lab …
ellenxxxiao Jan 23, 2024
6a04d63
Merge branch 'main' of https://github.com/codersforcauses/repair-lab …
ellenxxxiao Jan 25, 2024
62e4cdd
Modify the style of volunteer card
Elefantat Jan 27, 2024
6ad25ff
Merge branch 'issue-176-Assign_volunteers_to_repair_request' of https…
Elefantat Jan 27, 2024
c3b248b
styling
ellenxxxiao Jan 27, 2024
ad57203
Merge branch 'main' of https://github.com/codersforcauses/repair-lab …
ellenxxxiao Feb 10, 2024
d28fb52
1. added endpoint for getting all repairers of a event
ellenxxxiao Feb 10, 2024
7201d7e
Merge branch 'main' of https://github.com/codersforcauses/repair-lab …
ellenxxxiao Feb 10, 2024
947486b
- display userId on the badge
ellenxxxiao Feb 14, 2024
cb1f27c
allowed changing volunteer with badge
ellenxxxiao Feb 17, 2024
c031540
Merge branch 'main' of https://github.com/codersforcauses/repair-lab …
ellenxxxiao Feb 17, 2024
484e979
deleted
ellenxxxiao Feb 17, 2024
a10735f
Merge branch 'main' of https://github.com/codersforcauses/repair-lab …
ellenxxxiao Feb 17, 2024
658aab0
changes using new `/events/[id]/repairers` endpoint
ellenxxxiao Feb 18, 2024
4720f94
rmved logs
ellenxxxiao Feb 18, 2024
654ed02
Merge branch 'main' of https://github.com/codersforcauses/repair-lab …
ellenxxxiao Feb 21, 2024
349f134
fix props requirement
ellenxxxiao Feb 21, 2024
931d625
Added accepted tasks count
ellenxxxiao Feb 21, 2024
a357ff5
once a volunteer is assigned, change status to "ACCEPTED"
ellenxxxiao Feb 21, 2024
f5abe53
Merge branch 'issue-176-Assign_volunteers_to_repair_request' of https…
ellenxxxiao Feb 21, 2024
f5141c4
add button to unassign a task
ellenxxxiao Feb 24, 2024
dade102
added code to test
ellenxxxiao Feb 24, 2024
e7373f4
Merge branch 'main' into issue-176-Assign_volunteers_to_repair_request
ellenxxxiao Feb 24, 2024
5218aa8
fixed type errors
ellenxxxiao Feb 24, 2024
886b4cc
Merge branch 'issue-176-Assign_volunteers_to_repair_request' of https…
ellenxxxiao Feb 24, 2024
9ea29dd
Merge branch 'main' into issue-176-Assign_volunteers_to_repair_request
ellenxxxiao Feb 27, 2024
45af26d
Merge branch 'main' of https://github.com/codersforcauses/repair-lab …
ellenxxxiao Mar 6, 2024
841b251
- removed `isRepaired`
ellenxxxiao Mar 7, 2024
5355754
Merge branch 'main' of https://github.com/codersforcauses/repair-lab …
dct0 Apr 29, 2024
2dda4db
Lint fix
dct0 Apr 29, 2024
439f942
Rename repairStatus to status
dct0 Apr 29, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
138 changes: 120 additions & 18 deletions src/components/Cards/assignee-badge.tsx
dct0 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -1,29 +1,131 @@
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?: string;
dct0 marked this conversation as resolved.
Show resolved Hide resolved
};

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 as string
ellenxxxiao marked this conversation as resolved.
Show resolved Hide resolved
);

const handleClick = (event: SyntheticEvent) => {
event.stopPropagation();
setShowAssigneeModal(true);
};

const handleKeyDown = (event: React.KeyboardEvent<HTMLDivElement>) => {
if (event.key === "Enter" || event.key === " ") {
event.preventDefault();
handleClick(event as SyntheticEvent);
}
};

const handleUnassignVolunteer = () => {
updateRepairRequest({
assignedTo: "null",
repairStatus: 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;
});

dct0 marked this conversation as resolved.
Show resolved Hide resolved
return (
<div className="rounded-lg bg-grey-200 p-2">
<div>
<div className="flex flex-row gap-2">
<Image
src={avatar || "/images/repair_lab_logo.jpg"}
className="object-fit h-8 w-8 rounded-full"
alt="avatar"
width={100}
height={100}
/>
<div className="flex flex-col justify-center">
<p className="text-xs font-bold">{firstName}</p>
{!lastName ? "" : <p className="text-xs">{lastName}</p>}
<>
<div
onClick={handleClick}
onKeyDown={handleKeyDown}
role="button"
tabIndex={0}
className="rounded-lg bg-grey-200 p-2 hover:cursor-pointer"
>
<div>
<div className="flex flex-row gap-2">
<Image
src={avatar ?? "/images/repair_lab_logo.jpg"}
className="object-fit h-8 w-8 rounded-full"
alt="avatar"
width={100}
height={100}
/>
<div className="flex flex-col justify-center">
<p className="text-xs font-bold">
{firstName} {lastName ?? ""}
</p>
</div>
</div>
</div>
</div>
</div>
<Modal
showModal={showAssigneeModal}
setShowPopup={setShowAssigneeModal}
height="h-3/4"
>
<div className="h-full flex flex-col gap-4 text-center">
<h1 className="text-xl font-bold">Assign Volunteer</h1>
<div className="flex space-x-2 items-center justify-center">
<Circle />
<p className="font-medium">Task Assigned</p>
</div>
<div className="h-3/4">
<div className="overflow-x-hidden overflow-y-auto mt-2 flex flex-row flex-wrap gap-5 justify-center ">
{repairRequestId &&
sortedRepairers &&
sortedRepairers.map((repairer, index) => (
<VolunteerCard
repairRequestId={repairRequestId}
userId={repairer.userId}
firstName={repairer.firstName}
lastName={repairer.lastName}
avatar={repairer.avatar}
acceptedTasksCount={repairer.acceptedTasksCount}
email={repairer.email}
key={index}
assigned={repairer.userId == assignedTo}
/>
))}
</div>
</div>

<Button
textSize="text-lg font-semibold"
onClick={handleUnassignVolunteer}
>
Unassign this task
</Button>
</div>
</Modal>
</>
);
}
31 changes: 20 additions & 11 deletions src/components/Cards/card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@ export type CardProps = {
image?: string;
status?: string;
firstName?: string;
lastName?: string;
lastName?: string | null;
avatar?: string;
assignedTo?: string;
handleClick?: () => void;
repairRequestProps: RepairRequestResponse;
};
Expand All @@ -40,10 +41,8 @@ export default function Card({ props }: { props: CardProps }) {

return (
<div
onClick={props.handleClick ? props.handleClick : handleClick}
onKeyDown={props.handleClick ? props.handleClick : handleClick}
role="presentation"
className="group col-span-1 max-w-xs flex-col overflow-hidden rounded-lg bg-grey-100 shadow-md transition hover:-translate-y-0.5 hover:cursor-pointer hover:bg-grey-50"
className="group col-span-1 max-w-xs flex-col overflow-hidden rounded-lg bg-grey-100 shadow-md transition hover:-translate-y-0.5 hover:bg-grey-50"
>
<Modal
title={
Expand Down Expand Up @@ -78,16 +77,24 @@ export default function Card({ props }: { props: CardProps }) {
/>
</div>
<div className="p-2">
<div className="flex flex-row items-start justify-between">
<h3 className="h-18 flex w-full flex-col self-start text-xl font-bold">
Repair ID:
</h3>
<div
onClick={props.handleClick ? props.handleClick : handleClick}
onKeyDown={props.handleClick ? props.handleClick : handleClick}
className="hover:cursor-pointer hover:underline"
role="button"
tabIndex={0}
>
<div className="flex flex-row items-start justify-between">
<h3 className="h-18 flex w-full flex-col self-start text-xl font-bold">
Repair ID:
</h3>

<div className="pr-2">
<StatusPill status={props.status} />
<div className="pr-2">
<StatusPill status={props.status} />
</div>
</div>
<p className="mb-3 w-full text-sm font-semibold">{props.title}</p>
</div>
<p className="mb-3 w-full text-sm font-semibold">{props.title}</p>
<div>
<p className="mb-3 h-32 overflow-y-scroll text-ellipsis text-sm font-light">
{props.description}
Expand All @@ -98,6 +105,8 @@ export default function Card({ props }: { props: CardProps }) {
firstName={props.firstName}
lastName={props.lastName}
avatar={props.avatar}
assignedTo={props.assignedTo}
repairRequestId={props.title}
/>
</div>
</div>
Expand Down
11 changes: 11 additions & 0 deletions src/components/Cards/circle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
type Props = {
numberOfTasks?: number;
};

export default function Circle({ numberOfTasks }: Props) {
return (
<span className="text-center text-lg font-semibold text-white inline-block rounded-full bg-app-primary w-8 h-8 leading-8">
{numberOfTasks ?? ""}
</span>
);
}
144 changes: 144 additions & 0 deletions src/components/Cards/volunteer-card.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
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: string | 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 as string
);
const [showConfirmation, setShowConfirmation] = useState(false);

const handleClick = () => {
setShowConfirmation(true);
};

const handleKeyDown = (event: React.KeyboardEvent<HTMLDivElement>) => {
if (event.key === "Enter" || event.key === " ") {
event.preventDefault();
handleClick();
}
};

const handleAssignVolunteer = () => {
updateRepairRequest({
assignedTo: userId,
repairStatus: RepairStatus.ACCEPTED
});
setShowConfirmation(false);
};

return (
<div
className={`${
inter.className
} relative w-64 rounded-lg p-2 hover:cursor-pointer
${assigned ? "bg-app-secondary-focus" : "bg-app-secondary"}`}
role="button"
onClick={handleClick}
onKeyDown={handleKeyDown}
tabIndex={0}
>
<div className="flex flex-row gap-2">
{/* LEFT: Avatar of volunteer */}
<div className="flex justify-center items-center">
<Image
src={avatar || "/images/repair_lab_logo.jpg"}
className="rounded-md h-[72px] w-[72px] m-auto"
alt="avatar"
width={80}
height={80}
/>
</div>

{/* MIDDLE */}
<div className="flex flex-col gap-y-1">
{/* Name of volunteer*/}
<p className="text-base font-semibold text-left">
{firstName} {lastName ?? ""}
</p>
{/* Skills */}
<p className="w-fit text-app-base-300 bg-app-accent rounded-lg px-1 text-sm">
Woodworking
</p>
<p className="w-fit text-app-base-300 bg-[#e6cffb] rounded-lg px-1 text-sm">
Bike Repair
</p>
</div>

{/* RIGHT: #. of assigned tasks */}
<div className="absolute right-2">
<Circle numberOfTasks={acceptedTasksCount} />
</div>
</div>

<Modal
showModal={showConfirmation}
setShowPopup={setShowConfirmation}
height="h-1/5"
width="w-96"
>
<div className="h-full flex flex-col gap-4 text-center ">
<h1 className="text-xl font-bold">Assign Volunteer</h1>

<div className="overflow-hidden mt-1 flex flex-col gap-6">
<p className="text-s font-semibold">
Are you sure you want to assign this task to {firstName}
{lastName ? " " : ""}
{lastName ?? ""}?
</p>

<div className="space-x-8">
<Button
height="h-9"
width="w-20 font-semibold"
color="bg-gray-200"
hover="hover:bg-gray-300"
textColor="black"
>
Cancel
</Button>

<Button
type="submit"
height="h-9"
width="w-20 font-semibold"
color="bg-app-secondary-focus"
textColor="black"
onClick={handleAssignVolunteer}
>
Confirm
</Button>
</div>
</div>
</div>
</Modal>
</div>
);
}
4 changes: 2 additions & 2 deletions src/components/Forms/prepopulated-repair-request-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export default function PrepopulatedRepairAttemptForm({
const { watch, control, handleSubmit } = useForm<GeneralRepairAttempt>({
resolver: zodResolver(updateRepairRequestSchema),
defaultValues: {
item: props.itemType,
itemType: props.itemType,
itemBrand: props.itemBrand,
itemMaterial: props.itemMaterial,
hoursWorked: Number(props.hoursWorked),
Expand All @@ -57,7 +57,7 @@ export default function PrepopulatedRepairAttemptForm({
{/* ID, Item */}
<div className="m-5 flex flex-wrap gap-2 max-[415px]:m-2">
<FieldSingleSelect
name="item"
name="itemType"
control={control}
rules={{ required: true }}
options={
Expand Down
Loading
Loading