Skip to content

Commit

Permalink
Merge pull request #373 from STAPLE-verse/small-refactors
Browse files Browse the repository at this point in the history
Small refactors
  • Loading branch information
doomlab authored Nov 19, 2024
2 parents 31d1552 + e9de46a commit f716e07
Show file tree
Hide file tree
Showing 161 changed files with 2,503 additions and 2,757 deletions.
98 changes: 11 additions & 87 deletions src/contributors/components/ContributorForm.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
import React, { useState } from "react"
import React from "react"
import { Form, FormProps } from "src/core/components/fields/Form"
import { z } from "zod"
import { LabelSelectField } from "src/core/components/fields/LabelSelectField"
import { useQuery } from "@blitzjs/rpc"
import { MemberPrivileges } from "@prisma/client"
import getRoles from "src/roles/queries/getRoles"
import Modal from "src/core/components/Modal"
import CheckboxFieldTable from "src/core/components/fields/CheckboxFieldTable"
import LabeledTextField from "src/core/components/fields/LabeledTextField"
import { Tooltip } from "react-tooltip"
import getProjectManagers from "src/projectmembers/queries/getProjectManagers"
import AddRoleInput from "src/roles/components/AddRoleInput"
import getProjectManagerUserIds from "src/projectmembers/queries/getProjectManagerUserIds"

interface ContributorFormProps<S extends z.ZodType<any, any>> extends FormProps<S> {
projectId: number
Expand All @@ -25,59 +23,13 @@ export const MemberPrivilegesOptions = [
export function ContributorForm<S extends z.ZodType<any, any>>(props: ContributorFormProps<S>) {
const { projectId, isEdit = false, editedUserId, ...formProps } = props

// need all roles from all PMs for this project
// get all roles from all PMs
const [projectManagers] = useQuery(getProjectManagers, {
const [projectManagerUserIds] = useQuery(getProjectManagerUserIds, {
projectId: projectId!,
})

const pmIds = projectManagers.map((pm) => pm.userId)

// Check if the current user is the last project manager
const isLastProjectManager = isEdit && pmIds.length === 1 && pmIds[0] === editedUserId

const [{ roles }] = useQuery(getRoles, {
where: {
userId: {
in: pmIds, // Filter roles where userId is in the list of PM IDs
},
},
include: {
projectMembers: true, // Optional: include projectMember data if needed
user: true,
},
})

const roleMerged = roles.map((roles) => {
return {
pm: roles["user"]["username"],
role: roles["name"],
id: roles["id"],
}
})

const extraData = roleMerged.map((item) => ({
pm: item.pm,
}))

const roleOptions = roleMerged.map((item) => ({
label: item.role,
id: item.id,
}))

const extraColumns = [
{
id: "pm",
header: "Project Manager",
accessorKey: "pm",
cell: (info) => <span>{info.getValue()}</span>,
},
]

const [openRolesModal, setrolesModal] = useState(false)
const handleToggleRolesModal = () => {
setrolesModal((prev) => !prev)
}
const isLastProjectManager =
isEdit && projectManagerUserIds.length === 1 && projectManagerUserIds[0] === editedUserId

return (
<Form<S> {...formProps}>
Expand All @@ -92,13 +44,6 @@ export function ContributorForm<S extends z.ZodType<any, any>>(props: Contributo
place="right"
opacity={1}
/>
<Tooltip
id="role-tooltip"
content="Add roles to individual contributors (like administration)"
className="z-[1099] ourtooltips"
place="right"
opacity={1}
/>
{!isEdit && (
<LabeledTextField
name="email"
Expand All @@ -120,32 +65,11 @@ export function ContributorForm<S extends z.ZodType<any, any>>(props: Contributo
disabled={isLastProjectManager}
/>
<div className="mt-4">
<button
type="button"
className="btn btn-primary w-1/2"
data-tooltip-id="role-tooltip"
onClick={() => handleToggleRolesModal()}
>
Add Role
</button>
<Modal open={openRolesModal} size="w-7/8 max-w-xl">
<div className="">
<div className="flex justify-start mt-4">
<CheckboxFieldTable
name="rolesId"
options={roleOptions}
extraColumns={extraColumns}
extraData={extraData}
/>
</div>
{/* closes the modal */}
<div className="modal-action flex justify-end mt-4">
<button type="button" className="btn btn-primary" onClick={handleToggleRolesModal}>
Close
</button>
</div>
</div>
</Modal>
<AddRoleInput
projectManagerIds={projectManagerUserIds}
buttonLabel="Add Role"
tooltipContent="Add roles to individual contributors (like administration)"
/>
</div>
</Form>
)
Expand Down
74 changes: 74 additions & 0 deletions src/contributors/components/ContributorInformation.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { Routes } from "@blitzjs/next"
import Link from "next/link"
import { getPrivilegeText } from "src/core/utils/getPrivilegeText"
import { MemberPrivileges, User } from "db"
import Card from "src/core/components/Card"
import DeleteContributor from "./DeleteContributor"

interface ContributorInformationProps {
contributorId: number
projectId: number
privilege: MemberPrivileges
teamNames: (string | null)[]
contributorPrivilege: MemberPrivileges
contributorUser: User
}

const ContributorInformation = ({
contributorId,
projectId,
privilege,
teamNames,
contributorPrivilege,
contributorUser,
}: ContributorInformationProps) => {
const contributorName =
contributorUser.firstName && contributorUser.lastName
? `${contributorUser.firstName} ${contributorUser.lastName}`
: contributorUser.username

return (
<Card
title={contributorName}
className="w-full"
actions={
privilege === MemberPrivileges.PROJECT_MANAGER ? (
<div className="flex flex-row gap-2">
<Link
href={Routes.EditContributorPage({
projectId: projectId,
contributorId: contributorId,
})}
className="btn btn-primary"
>
Edit Contributor
</Link>
<DeleteContributor
projectId={projectId}
contributorUser={contributorUser}
contributorId={0}
/>
</div>
) : null
}
>
{contributorUser.firstName && contributorUser.lastName && (
<p>
<span className="font-semibold">Username:</span> {contributorUser.username}
</p>
)}
<p>
<span className="font-semibold">Email:</span> {contributorUser.email}
</p>
<p>
<span className="font-semibold">Privilege:</span> {getPrivilegeText(contributorPrivilege)}
</p>
<p>
<span className="font-semibold">Team Membership:</span>{" "}
{teamNames.length > 0 ? teamNames.join(", ") : "No team memberships"}
</p>
</Card>
)
}

export default ContributorInformation
38 changes: 38 additions & 0 deletions src/contributors/components/ContributorRolesList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { MemberPrivileges } from "db"
import Link from "next/link"
import { Routes } from "@blitzjs/next"
import Card from "src/core/components/Card"
import ProjectMemberRolesList from "src/projectmembers/components/ProjectMemberRolesList"
import { ContributorRolesListColumns } from "../tables/columns/ContributorRolesListColumns"
import { processContributorRolesList } from "../tables/processing/processContributorRolesList"

interface ContributorRolesListProps {
usersId: number[]
projectId: number
privilege: MemberPrivileges
}

export const ContributorRolesList = ({
usersId,
projectId,
privilege,
}: ContributorRolesListProps) => (
<Card
title={"Contributor Roles"}
className="w-full"
actions={
privilege === MemberPrivileges.PROJECT_MANAGER && (
<Link className="btn btn-primary" href={Routes.RolesPage({ projectId: projectId! })}>
Edit Roles
</Link>
)
}
>
<ProjectMemberRolesList
usersId={usersId}
projectId={projectId}
tableColumns={ContributorRolesListColumns}
dataProcessor={processContributorRolesList}
/>
</Card>
)
84 changes: 35 additions & 49 deletions src/contributors/components/ContributorTaskListDone.tsx
Original file line number Diff line number Diff line change
@@ -1,52 +1,38 @@
import { useQuery } from "@blitzjs/rpc"
import Table from "src/core/components/Table"
import getTasks from "src/tasks/queries/getTasks"
import { ProjectMember, Task, TaskLog } from "db"
import { FinishedTasksColumns } from "src/tasks/tables/columns/FinishedTasksColumns"
import { processFinishedTasks } from "src/tasks/tables/processing/processFinishedTasks"
import { MemberPrivileges } from "db"
import ProjectMemberTaskListDone from "src/projectmembers/components/ProjectMemberTaskListDone"
import Card from "src/core/components/Card"
import Link from "next/link"
import { Routes } from "@blitzjs/next"
import { ContributorTaskListDoneColumns } from "../tables/columns/ContributorTaskListDoneColumns"
import { processContributorTaskListDone } from "../tables/processing/processContributorTaskListDone"

type TaskWithLogs = Task & {
taskLogs: TaskLog[]
assignedMembers: ProjectMember[]
interface ContributorTaskListDoneProps {
contributorId: number
projectId: number
privilege: MemberPrivileges
}

export const ContributorTaskListDone = ({ contributor }) => {
const [{ tasks }] = useQuery(getTasks, {
where: {
assignedMembers: {
some: {
id: contributor.id, // Filter tasks assigned to this specific project member
},
},
},
include: {
taskLogs: {
where: {
assignedToId: contributor.id, // Ensure task logs are only for this project member
},
orderBy: { createdAt: "desc" }, // Order by createdAt, descending
},
assignedMembers: {
include: {
users: true, // Include user details for each assigned project member
},
},
project: true, // Include project details if needed
roles: true, // Include roles details if needed
},
orderBy: { id: "asc" }, // Order tasks by ID
}) as unknown as [{ tasks: TaskWithLogs[] }]

const completedTasks = tasks.filter((task) => {
const latestLog = task.taskLogs[0] // Since logs are ordered by createdAt desc, the first one is the latest
return latestLog && latestLog.status === "COMPLETED"
})

const processedTasks = processFinishedTasks(completedTasks)

return (
<div>
<Table columns={FinishedTasksColumns} data={processedTasks} addPagination={true} />
</div>
)
}
export const ContributorTaskListDone = ({
contributorId,
projectId,
privilege,
}: ContributorTaskListDoneProps) => (
<Card
title="Contributor Tasks"
className="w-full"
tooltipContent="Only completed tasks are included"
actions={
privilege === MemberPrivileges.PROJECT_MANAGER && (
<Link className="btn btn-primary" href={Routes.RolesPage({ projectId })}>
Edit Roles
</Link>
)
}
>
<ProjectMemberTaskListDone
projectMemberId={contributorId}
tableColumns={ContributorTaskListDoneColumns}
dataProcessor={processContributorTaskListDone}
/>
</Card>
)
53 changes: 53 additions & 0 deletions src/contributors/components/DeleteContributor.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { useRouter } from "next/router"
import { useMutation } from "@blitzjs/rpc"
import { Routes } from "@blitzjs/next"
import toast from "react-hot-toast"
import { useCurrentUser } from "src/users/hooks/useCurrentUser"
import deleteContributor from "../mutations/deleteContributor"
import { User } from "db"

interface DeleteContributorProps {
projectId: number
contributorUser: User
contributorId: number
}

const DeleteContributor = ({
projectId,
contributorUser,
contributorId,
}: DeleteContributorProps) => {
const [deleteContributorMutation] = useMutation(deleteContributor)
const router = useRouter()

const currentUser = useCurrentUser()

const handleDelete = async () => {
if (
window.confirm("This Contributor will be removed from the project. Are you sure to continue?")
) {
try {
await deleteContributorMutation({ id: contributorId })

// Navigate based on whether the current user was deleted
if (contributorUser.id === currentUser?.id) {
await router.push(Routes.ProjectsPage())
} else {
await router.push(Routes.ContributorsPage({ projectId }))
}

toast.success("Contributor successfully removed")
} catch (error) {
toast.error("Failed to delete contributor: " + error.message)
}
}
}

return (
<button className="btn btn-secondary" onClick={handleDelete}>
Delete Contributor
</button>
)
}

export default DeleteContributor
Loading

0 comments on commit f716e07

Please sign in to comment.