Skip to content

Commit

Permalink
#12 Implement pitch, team dashboard in tab pane, sort by team size
Browse files Browse the repository at this point in the history
  • Loading branch information
varunsingh87 committed Jan 17, 2024
1 parent b040fd4 commit 4817550
Show file tree
Hide file tree
Showing 22 changed files with 444 additions and 294 deletions.
2 changes: 0 additions & 2 deletions Components/AlertProvider.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,6 @@ export function AlertProvider(props) {

const handleContinueClick = () => {
setOpen(false)
console.debug('[handleContinueClick] message: ' + message)
console.info('[handleContinueClick] onContinue: ' + onContinue)
onContinue()
}

Expand Down
103 changes: 103 additions & 0 deletions Components/CompetitionNavbar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import { Nav, NavItem, NavLink, TabContent, TabPane } from 'reactstrap'
import classnames from 'classnames'
import Link from 'next/link'
import { useState } from 'react'
import AuthenticatedCompetition from './authenticated/Competition'
import { useConvexAuth } from 'convex/react'

export default function CompetitionNavbar(props: any) {
const [activeTab, setActiveTab] = useState(props.tabId)

const { isAuthenticated } = useConvexAuth()

const toggle = (tab: number) => {
if (activeTab !== tab) setActiveTab(tab)
}
return (
<div className="mt-3">
{isAuthenticated ? <AuthenticatedCompetition {...props} /> : null}
<Nav tabs>
<NavItem>
<NavLink
className={classnames({ active: activeTab === 1 })}
tag={Link}
href={`/competitions/${props.id}`}
onClick={() => {
toggle(1)
}}
style={{ cursor: 'pointer' }}
>
Overview
</NavLink>
</NavItem>
<NavItem>
<NavLink
className={classnames({ active: activeTab === 2 })}
tag={Link}
href={`/competitions/${props.id}/rules`}
onClick={() => {
toggle(2)
}}
style={{ cursor: 'pointer' }}
>
Rules & Rubric
</NavLink>
</NavItem>
<NavItem>
<NavLink
className={classnames({ active: activeTab === 3 })}
tag={Link}
href={`/competitions/${props.id}/prizes`}
onClick={() => {
toggle(3)
}}
style={{ cursor: 'pointer' }}
>
Prizes
</NavLink>
</NavItem>
<NavItem>
<NavLink
className={classnames({ active: activeTab === 4 })}
tag={Link}
href={`/competitions/${props.id}/teams`}
onClick={() => {
toggle(4)
}}
style={{ cursor: 'pointer' }}
>
Find Teammates
</NavLink>
</NavItem>
<NavItem>
<NavLink
className={classnames({ active: activeTab === 5 })}
tag={Link}
href={`/competitions/${props.id}/gallery`}
onClick={() => {
toggle(5)
}}
style={{ cursor: 'pointer' }}
>
Music Gallery
</NavLink>
</NavItem>
<NavItem>
<NavLink
className={classnames({ active: activeTab === 6 })}
onClick={() => {
toggle(6)
}}
tag={Link}
href={`/competitions/${props.id}/team`}
>
My Team
</NavLink>
</NavItem>
</Nav>
<TabContent activeTab={activeTab}>
<TabPane tabId={props.tabId}>{props.children}</TabPane>
</TabContent>
</div>
)
}
99 changes: 91 additions & 8 deletions Components/Teams.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,20 @@
import { Button, Col, List, ListInlineItem, Row } from 'reactstrap'
import {
Button,
Col,
Input,
Label,
List,
ListInlineItem,
Modal,
ModalBody,
ModalFooter,
ModalHeader,
Row,
} from 'reactstrap'
import { useMutation, useQuery } from 'convex/react'
import { api } from '../convex/_generated/api'
import { useState } from 'react'
import InvitesAndJoinRequests from './authenticated/InvitesAndJoinRequests'
import InvitesAndJoinRequests from './authenticated/UserInvites'
import { Id } from '../convex/_generated/dataModel'

export default function Teams(props: any) {
Expand All @@ -14,15 +26,32 @@ export default function Teams(props: any) {
const [inviteButtonMessage, setInviteBtnMsg] = useState('Invite to Team')

const handleJoinClick = (id: Id<'teams'>) => {
setRequestJoinModal(false)
requestJoin({ id })
setJoinButtonMessage('Join requested!')
}

const handleJoinModalOpen = () => {
setRequestJoinModal(true)
}

const [modal, setModal] = useState(false)
const [requestJoinModal, setRequestJoinModal] = useState(false)

const handleInviteClick = (joinerId: Id<'users'>) => {
setModal(false)
invite({ joinerId, competitionId: props.competitionId })
setInviteBtnMsg('Invite sent!')
}

const handleInviteModalOpen = () => {
setModal(true)
}

const toggle = () => setModal(!modal)

const toggleJoinRequestModal = () => setRequestJoinModal(!requestJoinModal)

return (
<Row>
<Col md={6}>
Expand All @@ -48,12 +77,68 @@ export default function Teams(props: any) {
participant &&
participant.userMembership.team == item._id
}
onClick={() => {
handleInviteClick(member._id)
}}
onClick={handleInviteModalOpen}
>
{inviteButtonMessage}
</Button>
<Modal isOpen={modal} toggle={toggle}>
<ModalHeader toggle={toggle}>
Invite {member.name}
</ModalHeader>
<ModalBody>
<Label>
A polite, helpful message will help this participant
decide if this team is a good fit
</Label>
<Input
type="text"
placeholder="Make sure to include contact information"
/>
</ModalBody>
<ModalFooter>
<Button
color="primary"
onClick={() => handleInviteClick(member.user._id)}
>
Invite
</Button>{' '}
<Button color="secondary" onClick={toggle}>
Cancel
</Button>
</ModalFooter>
</Modal>
<Modal
isOpen={requestJoinModal}
toggle={toggleJoinRequestModal}
>
<ModalHeader toggle={toggleJoinRequestModal}>
Request to Join
</ModalHeader>
<ModalBody>
<Label>
Pitch your skills and interests to this team to
persuade them to let you join them
</Label>
<Input
type="text"
placeholder="Make sure to include contact information"
/>
</ModalBody>
<ModalFooter>
<Button
color="primary"
onClick={() => handleJoinClick(item._id)}
>
Join
</Button>{' '}
<Button
color="secondary"
onClick={toggleJoinRequestModal}
>
Cancel
</Button>
</ModalFooter>
</Modal>
</ListInlineItem>
))}
</List>
Expand All @@ -63,9 +148,7 @@ export default function Teams(props: any) {
}
disabled={!participant}
color="primary"
onClick={() => {
handleJoinClick(item._id)
}}
onClick={handleJoinModalOpen}
>
{joinButtonMessage}
</Button>
Expand Down
2 changes: 1 addition & 1 deletion Components/User.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Doc } from '../convex/_generated/dataModel'
export function UserBubble(sender: Doc<'users'>) {
return (
<img
className="rounded-circle me-2 mb-2"
className="rounded-circle m-2"
title={sender.name}
src={sender.pictureURL}
width={50}
Expand Down
8 changes: 0 additions & 8 deletions Components/authenticated/Competition.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { Button, Container } from 'reactstrap'
import Link from 'next/link'
import { useMutation, useQuery } from 'convex/react'
import { api } from '../../convex/_generated/api'
import { useAlert } from '../AlertProvider'
Expand Down Expand Up @@ -27,12 +26,6 @@ export default function AuthenticatedCompetition(props) {
<h2>{props.name}</h2>
{participation ? (
<>
<Link
href={`/submissions/new?competition=${props.id}`}
className="btn btn-outline-primary me-2"
>
Enter Submission
</Link>
<Button color="danger" onClick={handleLeaveCompetitionClick}>
Leave Competition
</Button>
Expand All @@ -53,7 +46,6 @@ export default function AuthenticatedCompetition(props) {
>
Delete Competition
</Button>
<Link href={`./${props.id}/team`}>View Team</Link>
</Container>
)
}
7 changes: 0 additions & 7 deletions Components/authenticated/InvitesAndJoinRequests.tsx

This file was deleted.

7 changes: 7 additions & 0 deletions Components/authenticated/UserInvites.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export default function UserInvites() {
return (
<>
<h1>Invites</h1>
</>
)
}
1 change: 1 addition & 0 deletions convex/competition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ export const deleteCompetition = mutation({
args: { id: v.id('competitions') },
handler: async ({ db }, { id }) => {
await db.delete(id)
// TODO: New table for submissions attached to a team so these can be separated
},
})

Expand Down
2 changes: 1 addition & 1 deletion convex/lib/team.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { GenericDatabaseReader, GenericDatabaseWriter } from 'convex/server'
import { DataModel, Doc, Id } from '../_generated/dataModel'
import { RequestValidity } from '../../shared/info'
import { RequestValidity } from '../../lib/shared'
import { ConvexError } from 'convex/values'
import { convertToUserDocumentArray, fulfillAndFlatten } from './helpers'

Expand Down
26 changes: 21 additions & 5 deletions convex/participant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
addUserToTeam,
validateTeamJoinRequest,
} from './lib/team'
import { RequestValidity } from '../shared/info'
import { RequestValidity } from '../lib/shared'

/**
* @inheritDoc team.findTeamOfUser
Expand Down Expand Up @@ -65,8 +65,11 @@ export const joinCompetition = mutation({
* @param id The id of the team that the user would like to join
*/
export const requestJoin = mutation({
args: { id: v.id('teams') },
handler: async ({ db, auth }, { id }) => {
args: { id: v.id('teams'), pitch: v.optional(v.string()) },
handler: async (
{ db, auth },
{ id, pitch = 'Hey there! I would like to join your team.' }
) => {
const user = await verifyUser(db, auth)
const inviterTeam = await db.get(id)
if (!inviterTeam) {
Expand All @@ -84,6 +87,7 @@ export const requestJoin = mutation({
user: user._id,
userConsent: true,
teamConsent: false,
pitch,
})
return await db.replace(inviterTeam._id, inviterTeam)
case RequestValidity.INVITED:
Expand All @@ -105,8 +109,19 @@ export const requestJoin = mutation({
* @param competitionId The id of the competition that the team is in
*/
export const inviteToTeam = mutation({
args: { joinerId: v.id('users'), competitionId: v.id('competitions') },
handler: async ({ db, auth }, { joinerId, competitionId }) => {
args: {
joinerId: v.id('users'),
competitionId: v.id('competitions'),
pitch: v.optional(v.string()),
},
handler: async (
{ db, auth },
{
joinerId,
competitionId,
pitch = 'Hey there! We would love for you to join our team. ',
}
) => {
const inviter = await verifyUser(db, auth)
const inviterTeam = await findTeamOfUser(db, inviter, competitionId)
if (!inviterTeam) {
Expand All @@ -129,6 +144,7 @@ export const inviteToTeam = mutation({
user: joiner._id,
userConsent: false,
teamConsent: true,
pitch,
})
return await db.patch(inviterTeam._id, {
joinRequests: inviterTeam.joinRequests,
Expand Down
1 change: 1 addition & 0 deletions convex/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export const joinRequest = {
user: v.id('users'),
teamConsent: v.boolean(),
userConsent: v.boolean(),
pitch: v.string(),
}

const team = {
Expand Down
4 changes: 3 additions & 1 deletion convex/team.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ import { includeUserDocument } from './lib/helpers'
export const list = query({
args: { competitionId: v.id('competitions') },
handler: async ({ db, auth }, { competitionId }) => {
return await listCompetitionTeams(db, competitionId)
const competitionTeams = await listCompetitionTeams(db, competitionId)
competitionTeams.sort((a, b) => a.members.length - b.members.length)
return competitionTeams
},
})

Expand Down
Loading

0 comments on commit 4817550

Please sign in to comment.