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

Badge on submission invitations #528

Merged
merged 10 commits into from
Apr 2, 2024
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
69 changes: 69 additions & 0 deletions cypress/e2e/app/api/dashboard/requestedBadge.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { TIMEOUT } from '../../../../utils/constants'

describe('test requested submission required API', () => {

context('Logged out', () => {
it('should reject any request if not logged in', () => {
cy.request({
url: '/api/submission-box/requestedsubmissions/require-submission',
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
failOnStatusCode: false,
}).then(async (response) => {
expect(response.status).to.eq(401)
expect(response.body.error).to.eq('Unauthorized')
})
})
})

context('Logged in', () => {
const email = '[email protected]'
beforeEach(() => {
cy.task('clearDB')
const password = 'Pass1234'
cy.task('createUser', { email, password })
cy.visit('/login')
cy.get('[data-cy=email]').type(email)
cy.get('[data-cy=password]').type(password)
cy.get('[data-cy=submit]').click()
cy.url({ timeout: TIMEOUT.EXTRA_LONG }).should('not.contain', 'login')
cy.reload()
})

it('should return nothing when user does not have any requests', () => {
cy.request({
url: '/api/submission-box/requestedsubmissions/require-submission',
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
}).then(async (response) => {
expect(response.status).to.eq(200)
expect(response.body.requiredCount).to.eq(0)
})
})

it('should return the number of requested submissions needing to be submitted to', () => {
const submissionBoxTitle = 'multiple submissions'
cy.task('getUserId', email).then((userId) => {
cy.task('createRequestSubmissionForUser', { userId, submissionBoxTitle })
cy.task('createRequestSubmissionForUser', { userId, submissionBoxTitle })
cy.task('createRequestSubmissionForUser', { userId, submissionBoxTitle })
cy.task('createRequestSubmissionForUser', { userId, submissionBoxTitle })
})
cy.reload()
cy.request({
url: '/api/submission-box/requestedsubmissions/require-submission',
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
}).then(async (response) => {
expect(response.status).to.eq(200)
expect(response.body.requiredCount).to.eq(4)
})
})
})
})
121 changes: 121 additions & 0 deletions cypress/e2e/app/dashboard/requestedBadge.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import { TIMEOUT } from '../../../utils/constants'

describe('Dashboard requested submission badge count tests', () => {
// User information
const email = '[email protected]'
const password = 'Pass1234'
beforeEach(() => {
cy.task('clearDB')
cy.task('createUser', { email, password })
cy.visit('/login')
cy.get('[data-cy=email]').type(email)
cy.get('[data-cy=password]').type(password)
cy.get('[data-cy=submit]').click()
cy.url({ timeout: TIMEOUT.EXTRA_LONG }).should('not.contain', 'login')
cy.reload()
cy.visit('/dashboard')
})

it('should not have any badge when the user has no requested submissions', () => {
// Wait for api fetch
cy.wait(1000)
cy.get('[data-cy=requested-badge]').should('exist').should('contain', '')
})

SecondFeline marked this conversation as resolved.
Show resolved Hide resolved
it('should increment count when the user has a submission not yet submitted to and decrement it after submission', () => {
const submissionBoxTitle = 'Badge testing simulator'
const videoTitle = 'Get rid of the badge'
cy.task('getUserId', email).then((userId) => {
cy.task('createRequestSubmissionForUser', {userId, submissionBoxTitle}).then((requestedSubmissionId) => {
cy.reload()
// wait for api fetch
cy.wait(1000)
cy.get('[data-cy=requested-badge]').should('be.visible').should('contain', '1')
cy.task('createOneVideoAndRetrieveVideoId', {
title: videoTitle,
}).then((videoId) => {
cy.task('submitVideoToSubmissionBox', {
requestedSubmissionId,
videoId,
}).then(() => {
cy.reload()
cy.get('[data-cy=requested-badge]').should('exist').should('contain', '')
})
})
})
})
})

it('should increment the count after users remove the submission from a requested submission', () => {
const submissionBoxTitle = 'Badge testing simulator'
const videoTitle = 'Get rid of the badge'
cy.task('getUserId', email).then((userId) => {
cy.task('createRequestSubmissionForUser', {userId, submissionBoxTitle}).then((requestedSubmissionId) => {
cy.reload()
// wait for api fetch
cy.wait(1000)
cy.get('[data-cy=requested-badge]').should('be.visible').should('contain', '1')
cy.task('createOneVideoAndRetrieveVideoId', {
title: videoTitle,
ownerId: userId,
}).then((videoId) => {
cy.task('submitVideoToSubmissionBox', {
requestedSubmissionId,
videoId,
}).then(() => {
cy.reload()
cy.wait(1000)
cy.get('[data-cy=requested-badge]').should('be.visible').should('contain', '')
cy.visit('/dashboard?tab=my-invitations')
cy.get('[data-cy="My Invitations"]')
cy.wait(1000)
cy.get('[data-cy="My Invitations"]').click()
cy.get(`[data-cy="${ submissionBoxTitle }"]`)
cy.wait(1000)
cy.get(`[data-cy="${ submissionBoxTitle }"]`).click()
cy.wait(1000)
cy.get('[data-cy="unsubmit-button"]').should('be.visible').click()
cy.get('button').last().should('be.visible').and('have.text', 'Yes').click()

cy.visit('/dashboard')
cy.get('[data-cy=requested-badge]').should('be.visible').should('contain', '1')
SecondFeline marked this conversation as resolved.
Show resolved Hide resolved
})
})
})
})
})

it('should increment the count after users deletes the video submission of a requested submission', () => {
const submissionBoxTitle = 'Badge testing simulator'
const videoTitle = 'Get rid of the badge'
cy.task('getUserId', email).then((userId) => {
cy.task('createRequestSubmissionForUser', {userId, submissionBoxTitle}).then((requestedSubmissionId) => {
cy.reload()
// wait for api fetch
cy.wait(1000)
cy.get('[data-cy=requested-badge]').should('be.visible').should('contain', '1')
cy.task('createOneVideoAndRetrieveVideoId', {
title: videoTitle,
ownerId: userId,
}).then((videoId) => {
cy.task('submitVideoToSubmissionBox', {
requestedSubmissionId,
videoId,
}).then(() => {
cy.reload()
cy.wait(1000)
cy.get('[data-cy=requested-badge]').should('be.visible').should('contain', '')
cy.get('[data-cy="video-list"]').children().first().should('contain', videoTitle).click()
cy.wait(1000)
cy.get('[data-cy="edit-icon"]').click()
cy.get('[data-cy="detail-video-delete-button"]').click()
cy.get('[data-cy="detail-video-delete-confirm-button"]').click()

cy.visit('/dashboard')
cy.get('[data-cy=requested-badge]').should('be.visible').should('contain', '1')
})
})
})
})
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { NextResponse } from 'next/server'
import { getServerSession } from 'next-auth'
import logger from '@/utils/logger'
import prisma from '@/lib/prisma'

export async function GET() {
justino599 marked this conversation as resolved.
Show resolved Hide resolved
// This API will return the count of requested submissions that the user has not yet submitted to, call with GET
try {
// Check if a user is logged in
const session = await getServerSession()
if (!session || !session.user?.email) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
}
// Get userId
const userId: string = (
await prisma.user.findUniqueOrThrow({
where: {
email: session.user.email,
},
select: {
id: true,
},
})
).id
// This query returns the count of requested submissions with a videoVersions of none
const requiredCount = await prisma.requestedSubmission.aggregate({
where: {
userId: userId,
videoVersions: { none: {} },
},
_count: {
id: true,
},
})

return NextResponse.json({ requiredCount: requiredCount._count.id }, { status: 200 })
} catch (error) {
logger.error(error)
return NextResponse.json({ error: 'Internal Server Error' }, { status: 500 })
}
}
23 changes: 22 additions & 1 deletion src/components/DashboardSidebarSubmissionBoxes/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ import DashboardSidePanelOption from '@/components/DashboardSidePanelOption'
import AddCircleIcon from '@mui/icons-material/AddCircle'
import SendIcon from '@mui/icons-material/Send'
import Box from '@mui/material/Box'
import React from 'react'
import { useEffect, useState } from 'react'
import EditIcon from '@mui/icons-material/Edit'
import { SidebarOption } from '@/types/dashboard/sidebar'
import { Badge } from '@mui/material'
import { toast } from 'react-toastify'

export type DashboardSidebarSubmissionBoxesProps = {
onCreateNewClick: () => void
Expand All @@ -18,6 +20,17 @@ export type DashboardSidebarSubmissionBoxesProps = {

export default function DashboardSidebarSubmissionBoxes(props: DashboardSidebarSubmissionBoxesProps) {
const { sidebarSelectedOption } = props
const [count, setCount] = useState()
useEffect(() => {
fetch('/api/submission-box/requestedsubmissions/require-submission')
.then(async (res) => {
const { requiredCount } = await res.json()
setCount(requiredCount)
})
.catch(() => {
toast.error('An error occurred trying to access requested submission count')
})
})

return (
<>
Expand Down Expand Up @@ -47,6 +60,14 @@ export default function DashboardSidebarSubmissionBoxes(props: DashboardSidebarS
<Typography noWrap color={theme.palette.text.secondary} fontSize={'20px'} fontWeight={600} >
Submission Invitations
</Typography>
<Badge
badgeContent={count}
color='error'
anchorOrigin={{ vertical: 'top', horizontal: 'right' }}
style={{ transform: 'translate(-25px, 25px)'}}
max={99}
data-cy='requested-badge'
/>
<DashboardSidePanelOption
title={'My Invitations'}
icon={<SendIcon fontSize='small'/>}
Expand Down
Loading