Skip to content
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
49 changes: 49 additions & 0 deletions src/components/events/event-card.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import { cn } from "@/lib/utils"
import type { EventCardProps } from "@/types/events"

export function EventCard({
event,
className,
isActive = false,
}: EventCardProps) {
return (
<Card
className={cn(
// Base glass effect
"w-full overflow-hidden rounded-2xl border border-white/10",
"backdrop-blur-xl",
// Soft inner highlight
"shadow-[inset_0_1px_1px_rgba(255,255,255,0.1)]",
// Grey outer glow
"shadow-[0_0_30px_rgba(200,200,200,0.1)]",
// Smooth transitions
"transition-all duration-300 ease-out",
// Hover/Active states
isActive
? "shadow-[0_0_40px_rgba(234,179,8,0.4),inset_0_1px_1px_rgba(255,255,255,0.2)] border-amber-400/30"
: "hover:shadow-[0_0_40px_rgba(200,200,200,0.2),inset_0_1px_1px_rgba(255,255,255,0.15)] hover:border-white/20 hover:-translate-y-1",
className
)}
style={{
backgroundColor: "var(--navy-card)",
}}
>
<CardHeader className="pb-1">
<CardTitle className="text-xl font-bold text-white/90">
{event.name}
</CardTitle>
</CardHeader>
<CardContent className="pt-2">
<div
className={cn(
"inline-block rounded-lg px-3 py-1 text-sm font-semibold",
"bg-amber-500/10 text-amber-300/80 border border-amber-400/10"
)}
>
{event.day}
</div>
</CardContent>
</Card>
)
}
53 changes: 53 additions & 0 deletions src/components/events/events-filter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { Input } from "@/components/ui/input"
import { cn } from "@/lib/utils"
import { Search } from "lucide-react"
import type { EventsFilterProps } from "@/types/events"

export function EventsFilter({
searchQuery,
setSearchQuery,
selectedDay,
setSelectedDay,
}: EventsFilterProps) {
return (
<div className="flex flex-col gap-4">
{/* Search */}
<div className="relative">
<Search
className="absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground"
size={16}
/>
<Input
id="search"
placeholder="Search by name, organization..."
className="pl-9 border-input text-foreground focus-visible:ring-ring"
style={{ backgroundColor: "var(--navy-dark)" }}
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
/>
</div>

{/* Day toggle */}
<div
className="flex items-center gap-0.5 px-1 rounded-md border border-zinc-700/50 h-9"
style={{ backgroundColor: "var(--navy-dark)" }}
>
{(["All", "20 Feb", "21 Feb"] as const).map((day) => (
<button
key={day}
onClick={() => setSelectedDay(day)}
className={cn(
"flex-1 rounded px-2 py-1 text-sm font-medium whitespace-nowrap",
"transition-all duration-200",
selectedDay === day
? "border border-amber-500/80 text-amber-400 bg-transparent"
: "border border-transparent text-zinc-400 hover:text-zinc-200"
)}
>
{day}
</button>
))}
</div>
</div>
)
}
44 changes: 44 additions & 0 deletions src/components/events/mock-data.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import type { Event } from "@/types/events"

export const MOOCK_EVENTS: Event[] = [
{
id: "1",
name: "Tech Talk 2024",
organizer: "Computer Science Dept",
day: "20 Feb",
},
{
id: "2",
name: "Cultural Fest",
organizer: "Arts Club",
day: "21 Feb",
},
{
id: "4",
name: "Coding Marathon",
organizer: "Computer Science Dept",
day: "20 Feb",
},
{
id: "5",
name: "Music Concert",
organizer: "Music Club",
day: "21 Feb",
},
{
id: "7",
name: "AI Seminar",
organizer: "AI Research Group",
day: "20 Feb",
},
]

export const ORGANIZERS = [
"All organizers",
"Computer Science Dept",
"Arts Club",
"Robotics Club",
"Music Club",
"Gaming Club",
"AI Research Group",
]
131 changes: 131 additions & 0 deletions src/components/login-form.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import { useNavigate } from "@tanstack/react-router"
import { cn } from "@/lib/utils"
import { useMutation } from "@tanstack/react-query"
import { Eye, EyeOff } from "lucide-react"
import { useState } from "react"
import axiosClient from "@/lib/axios"
import { apiEndpoints } from "@/lib/api-endpoints"

import { Button } from "@/components/ui/button"
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card"
import { Field, FieldGroup, FieldLabel } from "@/components/ui/field"
import { Input } from "@/components/ui/input"

export function LoginForm({
className,
...props
}: React.ComponentProps<"div">) {
const navigate = useNavigate()
const [username, setUsername] = useState("")
const [password, setPassword] = useState("")
const [error, setError] = useState("")
const [showPassword, setShowPassword] = useState(false)

const loginMutation = useMutation({
mutationFn: async (data: { email: string; password: string }) => {
const response = await axiosClient.post(apiEndpoints.LOGIN, data)
return response.data
},
onSuccess: () => {
navigate({ to: "/events" })
},
onError: (error: any) => {
console.error("Login failed:", error)
setError(
error.response?.data?.message || "Login failed. Please try again."
)
},
})

const handleSubmit = (e: React.FormEvent) => {
e.preventDefault()
setError("")

if (!username || !password) {
setError("Please enter both email and password")
return
}

loginMutation.mutate({ email: username, password })
}
Comment thread
KiranRajeev-KV marked this conversation as resolved.

return (
<div className={cn("flex flex-col gap-6", className)} {...props}>
<Card className="bg-background/60 backdrop-blur-xl border-accent/20 shadow-xl">
<CardHeader className="text-center">
<CardTitle className="text-2xl">Welcome back</CardTitle>
<CardDescription>
Login with your organizer credentials
</CardDescription>
</CardHeader>
<CardContent>
<form onSubmit={handleSubmit}>
<FieldGroup>
<Field>
<FieldLabel htmlFor="username">Email</FieldLabel>
<Input
id="username"
type="text"
placeholder="email@example.com"
value={username}
onChange={(e) => setUsername(e.target.value)}
/>
</Field>

<Field>
<FieldLabel htmlFor="password">Password</FieldLabel>
<div className="relative">
<Input
id="password"
type={showPassword ? "text" : "password"}
placeholder="Enter your password"
value={password}
onChange={(e) => setPassword(e.target.value)}
className="pr-10"
/>
<Button
type="button"
variant="ghost"
size="sm"
className="absolute right-0 top-0 h-full px-3 py-2 hover:bg-transparent"
onClick={() => setShowPassword((prev) => !prev)}
aria-label={
showPassword ? "Hide password" : "Show password"
}
>
{showPassword ? (
<EyeOff className="h-4 w-4 text-muted-foreground" />
) : (
<Eye className="h-4 w-4 text-muted-foreground" />
)}
</Button>
</div>
</Field>

{/* Error message */}
{error && (
<div className="text-sm text-red-500 text-center">{error}</div>
)}

<Field>
<Button
type="submit"
className="w-full"
disabled={loginMutation.isPending}
>
{loginMutation.isPending ? "Logging in..." : "Login"}
</Button>
</Field>
</FieldGroup>
</form>
</CardContent>
</Card>
</div>
)
}
Loading