Skip to content

Instantly share code, notes, and snippets.

@Keshav13142
Created December 17, 2024 09:17
Show Gist options
  • Save Keshav13142/3eeea01eb9be47487f74f9c53a4a1818 to your computer and use it in GitHub Desktop.
Save Keshav13142/3eeea01eb9be47487f74f9c53a4a1818 to your computer and use it in GitHub Desktop.
Contest invite
"use client"
import { useState } from "react"
import { Button } from "@/components/ui/button"
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog"
import { Input } from "@/components/ui/input"
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
import { Checkbox } from "@/components/ui/checkbox"
import { Label } from "@/components/ui/label"
import { CalendarIcon, UsersIcon, TrophyIcon } from 'lucide-react'
import { Card, CardContent } from "@/components/ui/card"
// Mock functions and data
const validateInviteCode = async (code: string) => {
// Simulating API call
await new Promise(resolve => setTimeout(resolve, 1000))
return code === "VALID123"
}
const fetchContestDetails = async (code: string) => {
// Simulating API call
await new Promise(resolve => setTimeout(resolve, 1000))
return {
name: "Summer Coding Challenge",
description: "A 3-month long coding contest for all skill levels",
startDate: "2023-06-01",
endDate: "2023-08-31",
memberLimit: 3
}
}
const userTeams = [
{ id: "1", name: "Alpha Coders" },
{ id: "2", name: "Beta Builders" },
{ id: "3", name: "Gamma Devs" }
]
const teamMembers = [
{ id: "1", name: "Alice" },
{ id: "2", name: "Bob" },
{ id: "3", name: "Charlie" },
{ id: "4", name: "David" }
]
type Step = "invite" | "details" | "team" | "members"
const useDialogStep = (initialStep: Step) => {
const [step, setStep] = useState<Step>(initialStep)
const [inviteCode, setInviteCode] = useState("")
const [contestDetails, setContestDetails] = useState<any>(null)
const [selectedTeam, setSelectedTeam] = useState("")
const [selectedMembers, setSelectedMembers] = useState<string[]>([])
return {
step,
setStep,
inviteCode,
setInviteCode,
contestDetails,
setContestDetails,
selectedTeam,
setSelectedTeam,
selectedMembers,
setSelectedMembers
}
}
export function ContestInviteDialog() {
const [open, setOpen] = useState(false)
const {
step,
setStep,
inviteCode,
setInviteCode,
contestDetails,
setContestDetails,
selectedTeam,
setSelectedTeam,
selectedMembers,
setSelectedMembers
} = useDialogStep("invite")
const handleInviteSubmit = async () => {
const isValid = await validateInviteCode(inviteCode)
if (isValid) {
const details = await fetchContestDetails(inviteCode)
setContestDetails(details)
setStep("details")
} else {
alert("Invalid invite code")
}
}
const handleTeamSelect = (teamId: string) => {
setSelectedTeam(teamId)
setStep("members")
}
const handleMemberSelect = (memberId: string) => {
setSelectedMembers(prev => {
if (prev.includes(memberId)) {
return prev.filter(id => id !== memberId)
} else if (prev.length < contestDetails.memberLimit) {
return [...prev, memberId]
}
return prev
})
}
const handleJoinContest = () => {
console.log("Joining contest with:", { inviteCode, selectedTeam, selectedMembers })
setOpen(false)
// Reset state
setStep("invite")
setInviteCode("")
setContestDetails(null)
setSelectedTeam("")
setSelectedMembers([])
}
const handleBack = () => {
if (step === "details") setStep("invite");
else if (step === "team") setStep("details");
else if (step === "members") setStep("team");
};
return (
<Dialog open={open} onOpenChange={setOpen}>
<DialogTrigger asChild>
<Button variant="outline">Join Contest</Button>
</DialogTrigger>
<DialogContent className="sm:max-w-[425px]">
<DialogHeader>
<DialogTitle>
{step === "invite" && "Enter Invite Code"}
{step === "details" && "Contest Details"}
{step === "team" && "Select Team"}
{step === "members" && "Select Members"}
</DialogTitle>
</DialogHeader>
{step === "invite" && (
<div className="grid gap-4 py-4">
<div className="grid grid-cols-4 items-center gap-4">
<Label htmlFor="invite-code" className="text-right">
Invite Code
</Label>
<Input
id="invite-code"
value={inviteCode}
onChange={(e) => setInviteCode(e.target.value)}
className="col-span-3"
/>
</div>
<Button onClick={handleInviteSubmit}>Submit</Button>
</div>
)}
{step === "details" && contestDetails && (
<div className="grid gap-4 py-4">
<Card>
<CardContent className="p-6">
<h3 className="text-lg font-semibold mb-4 flex items-center">
<TrophyIcon className="mr-2 h-5 w-5 text-yellow-500" />
{contestDetails.name}
</h3>
<p className="text-sm text-gray-500 mb-4">{contestDetails.description}</p>
<div className="grid grid-cols-3 gap-4">
<div className="flex items-center">
<CalendarIcon className="mr-2 h-5 w-5 text-blue-500" />
<div>
<p className="text-sm font-medium">Start Date</p>
<p className="text-sm text-gray-500">{contestDetails.startDate}</p>
</div>
</div>
<div className="flex items-center">
<CalendarIcon className="mr-2 h-5 w-5 text-red-500" />
<div>
<p className="text-sm font-medium">End Date</p>
<p className="text-sm text-gray-500">{contestDetails.endDate}</p>
</div>
</div>
<div className="flex items-center">
<UsersIcon className="mr-2 h-5 w-5 text-green-500" />
<div>
<p className="text-sm font-medium">Member Limit</p>
<p className="text-sm text-gray-500">{contestDetails.memberLimit}</p>
</div>
</div>
</div>
</CardContent>
</Card>
<div className="flex justify-between mt-4">
<Button onClick={handleBack} variant="outline">Back</Button>
<Button onClick={() => setStep("team")}>Continue</Button>
</div>
</div>
)}
{step === "team" && (
<div className="grid gap-4 py-4">
<Select onValueChange={handleTeamSelect}>
<SelectTrigger className="w-full">
<SelectValue placeholder="Select a team" />
</SelectTrigger>
<SelectContent>
{userTeams.map(team => (
<SelectItem key={team.id} value={team.id}>{team.name}</SelectItem>
))}
</SelectContent>
</Select>
<div className="flex justify-start mt-4">
<Button onClick={handleBack} variant="outline">Back</Button>
</div>
</div>
)}
{step === "members" && (
<div className="grid gap-4 py-4">
<p>Select up to {contestDetails.memberLimit} members:</p>
{teamMembers.map(member => (
<div key={member.id} className="flex items-center space-x-2">
<Checkbox
id={`member-${member.id}`}
checked={selectedMembers.includes(member.id)}
onCheckedChange={() => handleMemberSelect(member.id)}
disabled={selectedMembers.length >= contestDetails.memberLimit && !selectedMembers.includes(member.id)}
/>
<label
htmlFor={`member-${member.id}`}
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
>
{member.name}
</label>
</div>
))}
<div className="flex justify-between mt-4">
<Button onClick={handleBack} variant="outline">Back</Button>
<Button onClick={handleJoinContest}>Join Contest</Button>
</div>
</div>
)}
</DialogContent>
</Dialog>
)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment