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

feat(app): Developer role added that can see applications on all supervisor proposals #21

Merged
merged 3 commits into from
Dec 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 5 additions & 3 deletions src/components/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,16 @@ import NewProposalButton from './NewProposalButton'
export default function Header() {
const { data: session } = useSession()

const isSupervisor = session?.user?.role === UserRole.SUPERVISOR
const isSupervisor =
session?.user?.role === UserRole.SUPERVISOR ||
session?.user?.role === UserRole.DEVELOPER

return (
<header className="bg-slate-100 flex flex-col p-4 text-gray-600 md:justify-between md:flex-row flex-none">
<header className="flex flex-col flex-none p-4 text-gray-600 bg-slate-100 md:justify-between md:flex-row">
<div>
<NewProposalButton isSupervisor={isSupervisor} />
</div>
<div className="flex flex-col md:flex-row md:items-center gap-2">
<div className="flex flex-col gap-2 md:flex-row md:items-center">
{session?.user && (
<div className="text-sm md:pr-2">
Signed in as {session.user.email} ({session.user.role})
Expand Down
16 changes: 7 additions & 9 deletions src/components/ProposalApplication.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { H2, Table } from '@uzh-bf/design-system'
import { add, format, parseISO } from 'date-fns'
import { useSession } from 'next-auth/react'
import { useState } from 'react'
import useUserRole from 'src/lib/hooks/useUserRole'
import { trpc } from 'src/lib/trpc'
import { ApplicationDetails, ProposalDetails } from 'src/types/app'
import ApplicationDetailsModal from './ApplicationDetailsModal'
Expand All @@ -10,16 +11,12 @@ import ConfirmationModal from './ConfirmationModal'

interface ProposalApplicationProps {
proposalDetails: ProposalDetails
isStudent: boolean
isSupervisor: boolean
refetch: () => void
setFilters: (filters: { status: string }) => void
}

export default function ProposalApplication({
proposalDetails,
isStudent,
isSupervisor,
refetch,
setFilters,
}: ProposalApplicationProps) {
Expand All @@ -28,8 +25,8 @@ export default function ProposalApplication({
useState<boolean>(false)

const { data: session } = useSession()
const { isStudent, isSupervisor, isDeveloper } = useUserRole()
const acceptApplication = trpc.acceptProposalApplication.useMutation()

if (proposalDetails?.typeKey === 'SUPERVISOR') {
return (
<div className="p-4">
Expand All @@ -40,10 +37,11 @@ export default function ProposalApplication({
proposalId={proposalDetails.id}
/>
)}
{isSupervisor &&
(session?.user?.email === proposalDetails?.ownedByUserEmail ||
session?.user.email ===
proposalDetails?.supervisedBy?.[0].supervisorEmail) ? (
{isDeveloper ||
(isSupervisor &&
(session?.user?.email === proposalDetails?.ownedByUserEmail ||
session?.user.email ===
proposalDetails?.supervisedBy?.[0].supervisorEmail)) ? (
<div className="pt-4">
<H2>Applications</H2>
{proposalDetails?.applications?.length === 0 &&
Expand Down
3 changes: 2 additions & 1 deletion src/components/ProposalCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ export default function ProposalCard({
const { data: session } = useSession()

const hasFeedback =
session?.user?.role === UserRole.SUPERVISOR &&
(session?.user?.role === UserRole.SUPERVISOR ||
session?.user?.role === UserRole.DEVELOPER) &&
proposal.receivedFeedbacks?.length > 0

return (
Expand Down
9 changes: 4 additions & 5 deletions src/components/ProposalFeedback.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
import { faComment } from '@fortawesome/free-solid-svg-icons'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import useUserRole from 'src/lib/hooks/useUserRole'
import { ProposalDetails } from 'src/types/app'

interface ProposalFeedbackProps {
proposalDetails: ProposalDetails
isSupervisor: boolean
isAdmin: boolean
}

export default function ProposalFeedback({
proposalDetails,
isSupervisor,
isAdmin,
}: ProposalFeedbackProps) {
const { isSupervisor, isDeveloper } = useUserRole()

if (
proposalDetails?.receivedFeedbacks?.length > 0 &&
(isSupervisor || isAdmin)
(isSupervisor || isDeveloper)
) {
return (
<div>
Expand Down
4 changes: 3 additions & 1 deletion src/components/ProposalStatusForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,9 @@ export default function ProposalStatusForm({
} else if (
(proposalDetails?.typeKey === 'STUDENT' &&
proposalDetails?.statusKey === 'MATCHED') ||
proposalDetails?.receivedFeedbacks?.length > 0 ||
(proposalDetails?.receivedFeedbacks?.length > 0 &&
proposalDetails?.receivedFeedbacks?.user?.[0].userEmail ===
session?.user?.email) ||
providedFeedback
) {
return (
Expand Down
7 changes: 4 additions & 3 deletions src/components/SupervisorProposals.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,27 @@
import { H2 } from '@uzh-bf/design-system'
import { RefObject } from 'react'
import useUserRole from 'src/lib/hooks/useUserRole'
import { ProposalDetails } from 'src/types/app'
import ProposalCard from './ProposalCard'

interface SupervisorProposalsProps {
isSupervisor: boolean
data: ProposalDetails[]
selectedProposal: string | null
setSelectedProposal: (proposalId: string | null) => void
buttonRef: RefObject<HTMLButtonElement>
}

export default function SupervisorProposals({
isSupervisor,
data,
selectedProposal,
setSelectedProposal,
buttonRef,
}: SupervisorProposalsProps) {
const { isSupervisor, isDeveloper } = useUserRole()

return (
<div>
{isSupervisor && (
{(isSupervisor || isDeveloper) && (
<H2 className={{ root: 'mt-2' }}>Supervisor Proposals</H2>
)}
<div className="flex flex-row flex-wrap grid-cols-3 gap-2">
Expand Down
2 changes: 1 addition & 1 deletion src/lib/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export enum ProposalFeedbackType {
export enum UserRole {
STUDENT = 'STUDENT',
SUPERVISOR = 'SUPERVISOR',
ADMIN = 'ADMIN',
DEVELOPER = 'DEVELOPER',
}

export enum TopicAreas {
Expand Down
6 changes: 3 additions & 3 deletions src/lib/hooks/useUserRole.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ import { UserRole } from '../constants'
function useUserRole() {
const { data: session } = useSession()

const isAdmin = session?.user?.role === UserRole.ADMIN
const isSupervisor = session?.user?.role === UserRole.SUPERVISOR
const isStudent = !isAdmin && !isSupervisor
const isDeveloper = session?.user?.role === UserRole.DEVELOPER
const isStudent = !isSupervisor && !isDeveloper

return {
isAdmin,
isSupervisor,
isDeveloper,
isStudent,
}
}
Expand Down
20 changes: 6 additions & 14 deletions src/pages/[[...proposalId]].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,11 @@ export default function Index() {
status: ProposalStatusFilter.OPEN_PROPOSALS,
})

const { isAdmin, isStudent, isSupervisor } = useUserRole()
const { isSupervisor, isDeveloper } = useUserRole()

const { data, isLoading, isError, isFetching, refetch } =
trpc.proposals.useQuery({
filters,
})
const { data, isLoading, refetch } = trpc.proposals.useQuery({
filters,
})

useEffect(() => {
if (!router.query.proposalId && data?.[0]?.id) {
Expand Down Expand Up @@ -67,7 +66,7 @@ export default function Index() {
return (
<div className="grid flex-1 grid-cols-1 gap-2 m-4 md:grid-cols-2">
<div className="flex-initial pb-4 space-y-4 md:flex-1">
{isSupervisor && (
{(isSupervisor || isDeveloper) && (
<StudentProposals
data={data}
selectedProposal={proposalId}
Expand All @@ -79,7 +78,6 @@ export default function Index() {
)}

<SupervisorProposals
isSupervisor={isSupervisor}
data={data}
selectedProposal={proposalId}
setSelectedProposal={setSelectedProposal}
Expand All @@ -94,16 +92,10 @@ export default function Index() {
<ProposalMeta proposalDetails={proposalDetails} />
<ProposalApplication
proposalDetails={proposalDetails}
isStudent={isStudent}
isSupervisor={isSupervisor}
refetch={refetch}
setFilters={setFilters}
/>
<ProposalFeedback
proposalDetails={proposalDetails}
isSupervisor={isSupervisor}
isAdmin={isAdmin}
/>
<ProposalFeedback proposalDetails={proposalDetails} />
<ProposalStatusForm proposalDetails={proposalDetails} />
</>
)}
Expand Down
16 changes: 15 additions & 1 deletion src/server/routers/_app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,20 @@ async function getSupervisorProposals({ ctx, filters }) {
},
},
}
} else if (ctx.user?.role === UserRole.DEVELOPER) {
where = {
...where,
typeKey: {
in: ['SUPERVISOR', 'STUDENT'],
},
}
applications = {
include: {
attachments: true,
status: true,
},
}
receivedFeedbacks = {}
} else {
where = {
...where,
Expand Down Expand Up @@ -242,7 +256,7 @@ export const appRouter = router({
.query(({ input, ctx }) => {
if (
ctx.user?.role &&
[UserRole.ADMIN, UserRole.SUPERVISOR].includes(ctx.user.role)
[UserRole.SUPERVISOR, UserRole.DEVELOPER].includes(ctx.user.role)
) {
return getSupervisorProposals({ ctx, filters: input.filters })
}
Expand Down