diff --git a/backend/modules/project/controller.js b/backend/modules/project/controller.js
index 4ac023687..47e860a4b 100644
--- a/backend/modules/project/controller.js
+++ b/backend/modules/project/controller.js
@@ -213,10 +213,12 @@ controller.exportProjects = async projectIds => {
return exportData
}
-controller.getFinalists = event => {
- return Project.find({ _id: { $in: event.finalists } })
+controller.getFinalists = async event => {
+ const finalistProjects = await Project.find({
+ _id: { $in: event.finalists },
+ })
+ return finalistProjects
}
-module.exports = controller
controller.getDataForPartnerReviewing = async (event, user) => {
const data = {}
@@ -261,3 +263,5 @@ controller.getDataForPartnerReviewing = async (event, user) => {
}
return data
}
+
+module.exports = controller
diff --git a/backend/modules/project/model.js b/backend/modules/project/model.js
index 53754c608..4b45d2ca8 100644
--- a/backend/modules/project/model.js
+++ b/backend/modules/project/model.js
@@ -6,7 +6,7 @@ const AchievementSchema = require('../../common/schemas/Achievement')
const GavelController = require('../reviewing/gavel/controller')
const WebhookService = require('../../common/services/webhook')
const CustomAnswer = require('@hackjunction/shared/schemas/CustomAnswer')
-const ProjectDefaultFields = require('@hackjunction/shared/constants/project-default-fields')
+// const ProjectDefaultFields = require('@hackjunction/shared/constants/project-default-fields')
// const AnswersSchema = require('@hackjunction/shared/schemas/Answers')
const ProjectSchema = new mongoose.Schema({
@@ -70,11 +70,6 @@ const ProjectSchema = new mongoose.Schema({
submissionFormAnswers: {
type: [CustomAnswer.mongoose],
},
- // TODO default fields
- // enabledFields: {
- // type: [String],
- // default: ProjectDefaultFields,
- // },
})
ProjectSchema.set('timestamps', true)
diff --git a/backend/modules/winner-votes/controller.js b/backend/modules/winner-votes/controller.js
index d5cbc2283..3ab3712f3 100644
--- a/backend/modules/winner-votes/controller.js
+++ b/backend/modules/winner-votes/controller.js
@@ -1,8 +1,56 @@
const _ = require('lodash')
const WinnerVote = require('./model')
+const projectController = require('../project/controller')
+const tokenVotingController = require('../voting-token/controller')
const controller = {}
+controller.getFinalistProjectsWithAllVotes = async event => {
+ const finalistProjects = await projectController.getFinalists(event)
+ const finalistProjectsWithVotes = finalistProjects.map(project => {
+ const projectObject = project.toObject()
+ projectObject.votingData = {
+ totalVotes: 0,
+ userVotes: 0,
+ tokenVotes: 0,
+ }
+ return projectObject
+ })
+ const userVotes = await controller.getVotesForEvent(event)
+ const tokenVotes = await tokenVotingController.getVotesByProject(event._id)
+ if (userVotes) {
+ userVotes.map(v => {
+ const projectWithVotes = _.find(
+ finalistProjectsWithVotes,
+ project => project._id.toString() === v.project,
+ )
+ if (projectWithVotes) {
+ projectWithVotes.votingData.userVotes = v.votes
+ }
+ })
+ }
+ if (tokenVotes) {
+ tokenVotes.map(v => {
+ const projectWithVotes = _.find(
+ finalistProjectsWithVotes,
+ project => project._id.toString() === v.project,
+ )
+ if (projectWithVotes) {
+ projectWithVotes.votingData.tokenVotes = v.votes
+ }
+ })
+ }
+ finalistProjectsWithVotes.forEach(project => {
+ project.votingData.totalVotes =
+ project.votingData.userVotes + project.votingData.tokenVotes
+ })
+ const sortedProjects = _.sortBy(
+ finalistProjectsWithVotes,
+ n => -1 * n.votingData.totalVotes,
+ )
+ return sortedProjects
+}
+
controller.getVotesForEvent = async event => {
const votes = await WinnerVote.find({ event: event._id }).lean()
const grouped = _.groupBy(votes, 'project')
@@ -14,8 +62,7 @@ controller.getVotesForEvent = async event => {
})
return result
}, [])
- const sorted = _.sortBy(results, n => -1 * n.votes)
- return sorted
+ return results
}
module.exports = controller
diff --git a/backend/modules/winner-votes/routes.js b/backend/modules/winner-votes/routes.js
index 7581b8fe8..f7483e10a 100644
--- a/backend/modules/winner-votes/routes.js
+++ b/backend/modules/winner-votes/routes.js
@@ -12,55 +12,97 @@ const {
isEventOrganiser,
} = require('../../common/middleware/events')
+const votingController = require('./controller')
+
+const getProjectsWithVotesForEvent = asyncHandler(async (req, res) => {
+ const finalistProjectsWithAllVotes =
+ await votingController.getFinalistProjectsWithAllVotes(req.event)
+ return res.status(200).json(finalistProjectsWithAllVotes)
+})
+
+const getVote = asyncHandler(async (req, res) => {
+ const vote = await WinnerVote.findOne({
+ event: req.event._id,
+ user: req.user.sub,
+ })
+
+ return res.status(200).json(vote)
+})
+
+const submitVote = asyncHandler(async (req, res) => {
+ const vote = await WinnerVote.findOne({
+ event: req.event._id,
+ user: req.user.sub,
+ })
+ if (vote) {
+ vote.project = req.body.projectId
+ const result = await vote.save()
+ return res.status(200).json(result)
+ }
+ const newVote = new WinnerVote({
+ event: req.event._id,
+ user: req.user.sub,
+ project: req.body.projectId,
+ })
+ const result = await newVote.save()
+ return res.status(200).json(result)
+})
+
router
.route('/:slug')
.get(
hasToken,
hasRegisteredToEvent,
- asyncHandler(async (req, res) => {
- const vote = await WinnerVote.findOne({
- event: req.event._id,
- user: req.user.sub,
- })
+ getVote,
+ // asyncHandler(async (req, res) => {
+ // const vote = await WinnerVote.findOne({
+ // event: req.event._id,
+ // user: req.user.sub,
+ // })
- return res.status(200).json(vote)
- }),
+ // return res.status(200).json(vote)
+ // }),
)
.post(
hasToken,
hasRegisteredToEvent,
- asyncHandler(async (req, res) => {
- const vote = await WinnerVote.findOne({
- event: req.event._id,
- user: req.user.sub,
- })
- if (vote) {
- vote.project = req.body.projectId
- const result = await vote.save()
- return res.status(200).json(result)
- }
- const newVote = new WinnerVote({
- event: req.event._id,
- user: req.user.sub,
- project: req.body.projectId,
- })
- const result = await newVote.save()
- return res.status(200).json(result)
- }),
+ submitVote,
+ // asyncHandler(async (req, res) => {
+ // const vote = await WinnerVote.findOne({
+ // event: req.event._id,
+ // user: req.user.sub,
+ // })
+ // if (vote) {
+ // vote.project = req.body.projectId
+ // const result = await vote.save()
+ // return res.status(200).json(result)
+ // }
+ // const newVote = new WinnerVote({
+ // event: req.event._id,
+ // user: req.user.sub,
+ // project: req.body.projectId,
+ // })
+ // const result = await newVote.save()
+ // return res.status(200).json(result)
+ // }),
)
router.route('/:slug/results').get(
hasToken,
isEventOrganiser,
- asyncHandler(async (req, res) => {
- const votes = await WinnerVote.find({
- event: req.event._id,
- })
+ getProjectsWithVotesForEvent,
+ // asyncHandler(async (req, res) => {
+ // const votes = await WinnerVote.find({
+ // event: req.event._id,
+ // })
- const grouped = _.groupBy(votes, 'project')
+ // const grouped = _.groupBy(votes, 'project')
+ // console.log('Grouped votes:', grouped)
+ // getProjectsWithVotesForEvent(req, res)
- return res.status(200).json(grouped)
- }),
+ // return res.status(200).json(grouped)
+ // }
)
+// )
module.exports = router
diff --git a/frontend/src/components/inputs/ImageUpload copy/index.js b/frontend/src/components/inputs/ImageUpload copy/index.js
deleted file mode 100644
index 2517ba948..000000000
--- a/frontend/src/components/inputs/ImageUpload copy/index.js
+++ /dev/null
@@ -1,211 +0,0 @@
-import React, { useState, useCallback } from 'react'
-
-import Upload from 'antd/es/upload'
-import { useDispatch, useSelector } from 'react-redux'
-import { makeStyles } from '@material-ui/core/styles'
-import { Box, Typography, CircularProgress } from '@material-ui/core'
-import DeleteIcon from '@material-ui/icons/Delete'
-import VisibilityIcon from '@material-ui/icons/Visibility'
-
-import * as AuthSelectors from 'redux/auth/selectors'
-import * as SnackbarActions from 'redux/snackbar/actions'
-
-const useStyles = makeStyles(theme => ({
- wrapper: {
- position: 'absolute',
- top: 0,
- left: 0,
- width: '100%',
- height: '100%',
- background: '#f7fafc',
- },
- emptyWrapper: {
- position: 'absolute',
- top: 0,
- left: 0,
- width: '100%',
- height: '100%',
- display: 'flex',
- flexDirection: 'column',
- justifyContent: 'center',
- alignItems: 'center',
- cursor: 'pointer',
- },
- emptyWrapperText: {
- textAlign: 'center',
- color: 'black',
- userSelect: 'none',
- },
- image: ({ resizeMode }) => ({
- position: 'absolute',
- top: 0,
- left: 0,
- width: '100%',
- height: '100%',
- objectFit: resizeMode || 'contain',
- }),
- imageOverlay: {
- position: 'absolute',
- top: 0,
- left: 0,
- width: '100%',
- height: '100%',
- background: 'rgba(0,0,0,0.6)',
- opacity: 0,
- display: 'flex',
- flexDirection: 'column',
- justifyContent: 'center',
- alignItems: 'center',
- transition: 'opacity 0.2s ease',
- '&:hover': {
- opacity: 1,
- },
- cursor: 'pointer',
- },
- imageOverlayButton: {
- padding: theme.spacing(1),
- display: 'flex',
- flexDirection: 'row',
- alignItems: 'center',
- '&:hover': {
- background: 'rgba(255,255,255,0.2)',
- },
- },
-}))
-
-export default ({ value, onChange, uploadUrl, resizeMode = 'contain' }) => {
- const dispatch = useDispatch()
- const idToken = useSelector(AuthSelectors.getIdToken)
- const classes = useStyles({ resizeMode })
- const [loading, setLoading] = useState(false)
-
- if (!uploadUrl) {
- throw new Error('ImageUpload component must be supplied an upload url')
- }
-
- const beforeUpload = useCallback(
- file => {
- const isJpgOrPng =
- file.type === 'image/jpeg' || file.type === 'image/png'
- if (!isJpgOrPng) {
- dispatch(
- SnackbarActions.error('Please upload a .jpg or .png file'),
- )
- }
- const isLt2M = file.size / 1024 / 1024 < 2
- if (!isLt2M) {
- dispatch(
- SnackbarActions.error(
- 'Upload size cannot be more than 2MB',
- ),
- )
- }
- return isJpgOrPng && isLt2M
- },
- [dispatch],
- )
-
- const handleChange = useCallback(
- info => {
- if (info.file.status === 'uploading') {
- setLoading(true)
- return
- }
- if (info.file.status === 'done') {
- onChange(info.file.response)
- setLoading(false)
- }
-
- if (info.file.status === 'error') {
- const message =
- info?.file?.response?.message ??
- 'Something went wrong... Please try again'
- dispatch(SnackbarActions.error(message))
- setLoading(false)
- }
- },
- [dispatch, onChange],
- )
-
- const handleRemove = useCallback(
- e => {
- e.stopPropagation()
- onChange()
- },
- [onChange],
- )
-
- const renderLoading = () => {
- return (
-
-
-
- )
- }
- const renderImage = () => {
- return (
-
-
-
-
-
-
-
- Remove image
-
-
- window.open(value.url, '_blank')}
- >
-
-
-
- View original
-
-
-
-
- )
- }
-
- const renderEmpty = () => {
- return (
-
-
- Click or drag a file to upload
-
-
- )
- }
-
- return (
-
-
- {loading && renderLoading()}
- {value && renderImage()}
- {!loading && !value && renderEmpty()}
-
-
- )
-}
diff --git a/frontend/src/pages/_dashboard/renderDashboard/organiser/projects/winners/index.js b/frontend/src/pages/_dashboard/renderDashboard/organiser/projects/winners/index.js
index d8af9b851..c8eb2d7d2 100644
--- a/frontend/src/pages/_dashboard/renderDashboard/organiser/projects/winners/index.js
+++ b/frontend/src/pages/_dashboard/renderDashboard/organiser/projects/winners/index.js
@@ -1,6 +1,6 @@
import React, { useCallback, useEffect, useState } from 'react'
-import { Grid, Box, Dialog, Typography } from '@material-ui/core'
+import { Grid, Box, Dialog } from '@material-ui/core'
import { useSelector } from 'react-redux'
import PageHeader from 'components/generic/PageHeader'
@@ -11,12 +11,8 @@ import ProjectDetail from 'components/projects/ProjectDetail'
import * as OrganiserSelectors from 'redux/organiser/selectors'
import * as AuthSelectors from 'redux/auth/selectors'
-import EventsService from 'services/events'
-//import ProjectsService from 'services/projects'
-
import WinnerVoteService from 'services/winnerVote'
-import VotingTokenService from 'services/votingToken'
-import { debugGroup } from 'utils/debuggingTools'
+import _ from 'lodash'
export default () => {
const event = useSelector(OrganiserSelectors.event)
@@ -26,65 +22,35 @@ export default () => {
const [selected, setSelected] = useState(false)
const [projects, setProjects] = useState([])
- const [results, setResults] = useState({})
- const [tokenVoterResults, setTokenVoterResults] = useState([])
-
- const updateVote = useCallback(() => {
- return WinnerVoteService.getResults(idToken, event.slug)
- }, [idToken, event])
-
- const updateVotesWithToken = useCallback(() => {
- return VotingTokenService.getVotingTokenResults(
- idToken,
- event.slug,
- ).catch(error => {
- console.error(error?.response)
- })
- }, [idToken, event])
-
- // const updateProjects = useCallback(() => {
- // // TODO use EventsService
- // return ProjectsService.getProjectsByEvent(event.slug)
- // // return EventsService.getWinnerProjects(idToken, event.slug)
- // }, [event])
const update = useCallback(async () => {
- setLoading(true)
- if (event.overallReviewMethod === 'finalsManualSelection') {
- const vote = await updateVote()
- const partnerVotes = await updateVotesWithToken()
- const topProjects = await EventsService.getFinalists(
- idToken,
- event.slug,
- )
- setProjects(topProjects)
- if (vote) {
- setResults(vote)
- }
- if (partnerVotes) {
- setTokenVoterResults(partnerVotes)
+ try {
+ setLoading(true)
+ const finalistProjectsWithAllVotes =
+ await WinnerVoteService.getResults(idToken, event.slug)
+ if (
+ Array.isArray(finalistProjectsWithAllVotes) &&
+ finalistProjectsWithAllVotes.length > 0
+ ) {
+ setProjects(finalistProjectsWithAllVotes)
}
+ } catch (error) {
+ console.error(error)
+ } finally {
+ setLoading(false)
}
- setLoading(false)
- }, [
- event.overallReviewMethod,
- event.slug,
- updateVote,
- updateVotesWithToken,
- idToken,
- ])
+ }, [event, idToken])
useEffect(() => {
- update()
- }, [update])
-
- const getScoreText = projectId => {
- const scoreFromUsers = results[projectId]?.length ?? 0
- const scoreFromTokenVoters =
- tokenVoterResults.find(res => res.project === projectId)?.votes ?? 0
-
- const total = scoreFromUsers + scoreFromTokenVoters
+ if (event?.slug) {
+ update()
+ }
+ }, [event])
+ const getScoreText = project => {
+ const scoreFromUsers = project?.votingData?.userVotes ?? 0
+ const scoreFromTokenVoters = project?.votingData?.tokenVotes ?? 0
+ const total = project?.votingData?.totalVotes ?? 0
return (
<>
Total votes received: {total}
@@ -93,16 +59,16 @@ export default () => {
>
)
}
- debugGroup('Results', results)
return (
- {projects.map(project => (
+ {projects.map((project, index) => (
setSelected(project)}
showScore={true}
/>
diff --git a/frontend/src/pages/_dashboard/renderDashboard/participant/finalist-voting/index.js b/frontend/src/pages/_dashboard/renderDashboard/participant/finalist-voting/index.js
index 4272a9e3d..107bfde2d 100644
--- a/frontend/src/pages/_dashboard/renderDashboard/participant/finalist-voting/index.js
+++ b/frontend/src/pages/_dashboard/renderDashboard/participant/finalist-voting/index.js
@@ -13,10 +13,7 @@ import * as DashboardSelectors from 'redux/dashboard/selectors'
import * as AuthSelectors from 'redux/auth/selectors'
import * as SnackbarActions from 'redux/snackbar/actions'
-import * as OrganiserSelectors from 'redux/organiser/selectors'
-
import EventsService from 'services/events'
-import ProjectsService from 'services/projects'
import WinnerVoteService from 'services/winnerVote'
@@ -32,97 +29,75 @@ export default () => {
const [vote, setVote] = useState(null)
const [hasVoted, setVoted] = useState(false)
- const updateVote = useCallback(() => {
+ const getCurrentVote = useCallback(() => {
return WinnerVoteService.getVote(idToken, event.slug)
}, [idToken, event])
- const updateProjects = useCallback(() => {
- // TODO use EventsService
- return ProjectsService.getProjectsByEvent(event.slug)
- // return EventsService.getWinnerProjects(idToken, event.slug)
- }, [event])
-
- const update = useCallback(async () => {
+ const getFinalists = useCallback(async () => {
setLoading(true)
- if (event.overallReviewMethod === 'finalsManualSelection') {
- const vote = await updateVote()
-
- const topProjects = await EventsService.getFinalists(
- idToken,
- event.slug,
- )
- setProjects(topProjects)
- if (vote) {
- setVote(vote.project)
- setVoted(true)
- }
- } else {
- //TODO holy shit redo this
- const topProjects = []
- const rankingsByTrack = useSelector(
- OrganiserSelectors.rankingsByTrack,
- )
- try {
- const [vote, projects] = await Promise.all([
- updateVote(),
- updateProjects(),
- ])
- if (rankingsByTrack) {
- Object.keys(rankingsByTrack).forEach(name =>
- topProjects?.push(
- projects?.find(
- x => x._id === rankingsByTrack[name][0],
- ),
- ),
- )
- }
- setProjects(topProjects)
- if (vote) {
- setVote(vote.project)
- }
- } catch (err) {
+ EventsService.getFinalists(idToken, event.slug)
+ .then(finalistProjects => {
+ setProjects(finalistProjects)
+ })
+ .catch(err => {
dispatch(
SnackbarActions.error(
- 'Oops, something went wrong... Please reload the page.',
+ 'Something went wrong... Please try again',
),
)
- }
- }
- setLoading(false)
- }, [
- event.overallReviewMethod,
- event.slug,
- updateVote,
- idToken,
- updateProjects,
- dispatch,
- ])
+ console.error(err)
+ })
+ .finally(() => {
+ setLoading(false)
+ })
+ }, [idToken, event])
useEffect(() => {
+ getFinalists()
update()
- }, [update])
+ }, [])
+
+ const update = useCallback(async () => {
+ try {
+ setLoading(true)
+ const vote = await getCurrentVote()
+ if (vote) {
+ setVote(vote.project)
+ setVoted(true)
+ }
+ } catch (err) {
+ dispatch(
+ SnackbarActions.error(
+ 'Something went wrong... Please try again',
+ ),
+ )
+ console.error(err)
+ } finally {
+ setLoading(false)
+ }
+ }, [event, idToken])
const handleSubmit = useCallback(async () => {
- setLoading(true)
try {
+ setLoading(true)
const result = await WinnerVoteService.submitVote(
idToken,
event.slug,
vote,
)
- setVote(result.project)
- setVoted(true)
- dispatch(SnackbarActions.success('Vote submitted!'))
+ if (result) {
+ dispatch(SnackbarActions.success('Vote submitted!'))
+ }
} catch (err) {
dispatch(
SnackbarActions.error(
'Something went wrong... Please try again',
),
)
+ } finally {
+ setLoading(false)
}
- setLoading(false)
- }, [idToken, event.slug, vote, dispatch])
-
+ }, [idToken, event, vote])
return (
{
- {projects.map(project => (
+ {projects.map((project, index) => (
setSelected(project)}