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

Add group activity page #36

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
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
258 changes: 258 additions & 0 deletions frontend/app/groups/[id]/activity/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,258 @@
'use client';

import { AnimatePresence, motion } from 'framer-motion';

Check failure on line 3 in frontend/app/groups/[id]/activity/page.tsx

View workflow job for this annotation

GitHub Actions / analysis (backend) / eslint-check

Run autofix to sort these imports!

Check failure on line 3 in frontend/app/groups/[id]/activity/page.tsx

View workflow job for this annotation

GitHub Actions / analysis (frontend) / eslint-check

Run autofix to sort these imports!
import { AwardIcon, ChevronDownIcon, StarIcon, UserIcon } from 'lucide-react';

Check failure on line 4 in frontend/app/groups/[id]/activity/page.tsx

View workflow job for this annotation

GitHub Actions / analysis (backend) / eslint-check

'ChevronDownIcon' is defined but never used

Check failure on line 4 in frontend/app/groups/[id]/activity/page.tsx

View workflow job for this annotation

GitHub Actions / analysis (frontend) / eslint-check

'ChevronDownIcon' is defined but never used
import Link from 'next/link';
import { useState } from 'react';

import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table';
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip';
import GroupInfoCard from '@/components/group-info-card';

// This would typically come from an API or props
const groupData = {
name: 'Corvin Innovation Hub',
semesters: ['2023/2024 spring', '2023/2024 ősz', '2022/2023 spring', '2022/2023 ősz'],
leaderPraise:
"Our group has shown exceptional dedication this semester. We've seen increased participation in campus events and significant contributions from many members. Special recognition goes to those who went above and beyond in organizing our major initiatives.",
members: [
{
id: 1,
name: 'Emma Johnson',
score: 9,
awardClass: 'AB',
comment:
"Outstanding leadership in organizing the fall festival. Emma's initiative brought the community together and showcased our group's talents.",
},
{ id: 2, name: 'Liam Williams', score: 47, awardClass: 'DO' },
{ id: 3, name: 'Olivia Brown', score: 12, awardClass: 'DO' },
{
id: 4,
name: 'Noah Davis',
score: 27,
awardClass: 'KB',
comment:
"Exceptional effort in coordinating the new student orientation program. Noah's innovative approach helped new students integrate seamlessly.",
},
{ id: 5, name: 'Ava Wilson', score: 5, awardClass: 'DO' },
{ id: 6, name: 'Ethan Taylor', score: 11, awardClass: 'DO' },
{ id: 7, name: 'Sophia Anderson', score: 5, awardClass: 'DO' },
{
id: 8,
name: 'Mason Thompson',
score: 50,
awardClass: 'AB',
comment:
"Innovative ideas for improving student engagement. Mason's creativity led to a significant increase in participation across all events.",
},
{
id: 9,
name: 'Isabella Martinez',
score: 26,
awardClass: 'KB',
comment:
"Exemplary work in developing the group's social media presence. Isabella's efforts greatly improved our outreach and community engagement.",
},
{ id: 10, name: 'William Clark', score: 5, awardClass: 'DO' },
{ id: 11, name: 'Mia Rodriguez', score: 5, awardClass: 'DO' },
{ id: 12, name: 'James Lee', score: 26, awardClass: 'DO' },
],
};

export default function GroupSemesterScores() {
const [selectedSemester, setSelectedSemester] = useState(groupData.semesters[0]);
const totalMembers = groupData.members.length;
const entryCards = groupData.members.filter((member) => member.awardClass !== 'DO').length;

return (
<div className='min-h-screen bg-gradient-to-br from-blue-50 to-purple-50 text-gray-900 p-4 sm:p-8'>
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5 }}
className='max-w-5xl mx-auto space-y-8'
>
<Card className='overflow-hidden shadow-lg'>
<CardHeader className='p-6 sm:p-8 bg-gradient-to-r from-blue-500 to-purple-500'>
<div className='flex flex-col sm:flex-row items-center sm:items-start gap-6'>
<Avatar className='h-32 w-32 border-4 border-white shadow-lg'>
<AvatarImage src='/placeholder.svg?height=128&width=128' alt={groupData.name} />
<AvatarFallback className='text-4xl bg-white text-blue-500'>
{groupData.name
.split(' ')
.map((n) => n[0])
.join('')}
</AvatarFallback>
</Avatar>
<div className='text-center sm:text-left'>
<CardTitle className='text-3xl sm:text-4xl font-bold text-white mb-2'>{groupData.name}</CardTitle>
<CardDescription className='text-lg text-blue-100'>
<Select value={selectedSemester} onValueChange={setSelectedSemester}>
<SelectTrigger className='border-none bg-white/20 text-white hover:bg-white/30 transition-colors'>
<SelectValue placeholder='Select semester' />
</SelectTrigger>
<SelectContent>
{groupData.semesters.map((semester) => (
<SelectItem key={semester} value={semester}>
{semester}
</SelectItem>
))}
</SelectContent>
</Select>
</CardDescription>
</div>
<div className='sm:ml-auto flex gap-2'>
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button variant='ghost' size='icon' className='text-white hover:bg-white/20'>
<UserIcon className='h-5 w-5' />
</Button>
</TooltipTrigger>
<TooltipContent>
<p>Group Members</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button variant='ghost' size='icon' className='text-white hover:bg-white/20'>
<StarIcon className='h-5 w-5' />
</Button>
</TooltipTrigger>
<TooltipContent>
<p>Group Achievements</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
</div>
</div>
</CardHeader>
<CardContent className='p-6'>
<div className='grid gap-4 sm:grid-cols-2'>
<GroupInfoCard
Title='Félévben aktív tagok'
Icon={UserIcon}
content={totalMembers.toString()}
color='blue'
/>
<GroupInfoCard Title='Kiosztott belépők' Icon={UserIcon} content={entryCards.toString()} color='purple' />
</div>
</CardContent>
</Card>

<AnimatePresence>
<motion.div
key='leader-praise'
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -20 }}
transition={{ duration: 0.5 }}
>
<Card className='overflow-hidden shadow-lg'>
<CardHeader className='bg-gradient-to-r from-yellow-400 to-orange-500 p-6'>
<CardTitle className='text-2xl font-bold flex items-center text-white'>
<AwardIcon className='mr-2 h-8 w-8' />
Körvezetői beszámoló
</CardTitle>
</CardHeader>
<CardContent className='p-6'>
<p className='text-gray-700 italic'>&ldquo;{groupData.leaderPraise}&rdquo;</p>
</CardContent>
</Card>
</motion.div>
</AnimatePresence>

<AnimatePresence>
<motion.div
key='member-contributions'
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -20 }}
transition={{ duration: 0.5, delay: 0.2 }}
>
<Card className='overflow-hidden shadow-lg'>
<CardHeader className='bg-gradient-to-r from-green-400 to-blue-500 p-6'>
<CardTitle className='text-2xl font-bold flex items-center text-white'>
<UserIcon className='mr-2 h-8 w-8' />
Member Contributions
</CardTitle>
</CardHeader>
<CardContent className='p-6'>
<div className='overflow-x-auto'>
<Table>
<TableHeader>
<TableRow>
<TableHead className='flex-1'>Name</TableHead>
<TableHead>Score</TableHead>
<TableHead className='w-32 text-center'>Award Class</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{groupData.members.map((member, index) => (
<motion.tr
key={member.id}
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.3, delay: index * 0.05 }}
className='group hover:bg-gray-50'
>
<TableCell className='font-medium'>
<Link
href={`/profile/${member.id}`}
className='text-blue-600 hover:text-blue-800 transition-colors duration-200'
>
{member.name}
</Link>
{(member.awardClass === 'AB' || member.awardClass === 'KB') && (
<motion.div
initial={{ opacity: 0, height: 0 }}
animate={{ opacity: 1, height: 'auto' }}
transition={{ duration: 0.3 }}
className='text-sm text-gray-600 mt-1'
>
{member.comment}
</motion.div>
)}
</TableCell>
<TableCell>
<span className='font-semibold text-gray-700 text-center'>{member.score}</span>
</TableCell>
<TableCell className='text-center'>
<Badge
variant={
member.awardClass === 'AB'

Check failure on line 230 in frontend/app/groups/[id]/activity/page.tsx

View workflow job for this annotation

GitHub Actions / analysis (backend) / eslint-check

Do not nest ternary expressions

Check failure on line 230 in frontend/app/groups/[id]/activity/page.tsx

View workflow job for this annotation

GitHub Actions / analysis (frontend) / eslint-check

Do not nest ternary expressions
? 'default'
: member.awardClass === 'KB'
? 'secondary'
: 'outline'
}
className={`
${member.awardClass === 'AB' ? 'bg-amber-500 hover:bg-amber-600 text-white' : ''}
${member.awardClass === 'KB' ? 'bg-blue-500 hover:bg-blue-600 text-white' : ''}
${member.awardClass === 'DO' ? 'bg-gray-500 hover:bg-gray-600 text-white' : ''}
transition-all duration-300 ease-in-out transform hover:scale-105
`}
>
{member.awardClass}
</Badge>
</TableCell>
</motion.tr>
))}
</TableBody>
</Table>
</div>
</CardContent>
</Card>
</motion.div>
</AnimatePresence>
</motion.div>
</div>
);
}
2 changes: 1 addition & 1 deletion frontend/components/client-side-profile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export function ClientSideProfile() {
const { data: me, status, error } = useAuthMe({ query: { retry: false } });
if (status === 'pending') return <h1>Loading...</h1>;
if (status === 'error' && error.status === 401) return <h1>Client: Anonymous</h1>;
if (status === 'error') return <h1>Something went wrong {error.response.data.message}</h1>;
if (status === 'error') return <h1>Something went wrong {error?.response?.data?.message}</h1>;

return <h1>Client: {me.name}</h1>;
}
22 changes: 22 additions & 0 deletions frontend/components/group-info-card.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { TooltipProvider, Tooltip, TooltipTrigger, TooltipContent } from '@radix-ui/react-tooltip';

Check failure on line 1 in frontend/components/group-info-card.tsx

View workflow job for this annotation

GitHub Actions / analysis (backend) / eslint-check

Run autofix to sort these imports!

Check failure on line 1 in frontend/components/group-info-card.tsx

View workflow job for this annotation

GitHub Actions / analysis (backend) / eslint-check

'TooltipProvider' is defined but never used

Check failure on line 1 in frontend/components/group-info-card.tsx

View workflow job for this annotation

GitHub Actions / analysis (backend) / eslint-check

'Tooltip' is defined but never used

Check failure on line 1 in frontend/components/group-info-card.tsx

View workflow job for this annotation

GitHub Actions / analysis (backend) / eslint-check

'TooltipTrigger' is defined but never used

Check failure on line 1 in frontend/components/group-info-card.tsx

View workflow job for this annotation

GitHub Actions / analysis (backend) / eslint-check

'TooltipContent' is defined but never used

Check failure on line 1 in frontend/components/group-info-card.tsx

View workflow job for this annotation

GitHub Actions / analysis (frontend) / eslint-check

Run autofix to sort these imports!

Check failure on line 1 in frontend/components/group-info-card.tsx

View workflow job for this annotation

GitHub Actions / analysis (frontend) / eslint-check

'TooltipProvider' is defined but never used

Check failure on line 1 in frontend/components/group-info-card.tsx

View workflow job for this annotation

GitHub Actions / analysis (frontend) / eslint-check

'Tooltip' is defined but never used

Check failure on line 1 in frontend/components/group-info-card.tsx

View workflow job for this annotation

GitHub Actions / analysis (frontend) / eslint-check

'TooltipTrigger' is defined but never used

Check failure on line 1 in frontend/components/group-info-card.tsx

View workflow job for this annotation

GitHub Actions / analysis (frontend) / eslint-check

'TooltipContent' is defined but never used
import { UserIcon } from 'lucide-react';
import { Button } from './ui/button';

Check failure on line 3 in frontend/components/group-info-card.tsx

View workflow job for this annotation

GitHub Actions / analysis (backend) / eslint-check

'Button' is defined but never used

Check failure on line 3 in frontend/components/group-info-card.tsx

View workflow job for this annotation

GitHub Actions / analysis (frontend) / eslint-check

'Button' is defined but never used

type GroupInfoCardProps = {
Title: string;
Icon: React.FC<React.SVGProps<SVGSVGElement>>;
content: string;
color: string;
};

export default function GroupInfoCard(props: GroupInfoCardProps) {
return (
<div className={`flex items-center justify-between bg-${props.color}-100 rounded-lg p-4`}>
<div className='flex items-center space-x-2'>
<UserIcon className={`h-6 w-6 text-${props.color}-600`} />
Copy link
Collaborator

@tomitheninja tomitheninja Nov 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A tailwind css néha nem kezeli le azt, ha futási időben adsz class-okat. Majd merge előtt checkold le légyszi.

<span className={`text-sm font-medium text-${props.color}-800`}>{props.Title}</span>
</div>
<span className={`text-2xl font-bold text-${props.color}-600`}>{props.content}</span>
</div>
);
}
50 changes: 50 additions & 0 deletions frontend/components/ui/avatar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
"use client"

Check failure on line 1 in frontend/components/ui/avatar.tsx

View workflow job for this annotation

GitHub Actions / analysis (backend) / eslint-check

Replace `"use·client"` with `'use·client';`

Check failure on line 1 in frontend/components/ui/avatar.tsx

View workflow job for this annotation

GitHub Actions / analysis (frontend) / eslint-check

Replace `"use·client"` with `'use·client';`

import * as React from "react"
import * as AvatarPrimitive from "@radix-ui/react-avatar"

import { cn } from "@/lib/utils"

const Avatar = React.forwardRef<
React.ElementRef<typeof AvatarPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Root>
>(({ className, ...props }, ref) => (
<AvatarPrimitive.Root
ref={ref}
className={cn(
"relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full",
className
)}
{...props}
/>
))
Avatar.displayName = AvatarPrimitive.Root.displayName

const AvatarImage = React.forwardRef<
React.ElementRef<typeof AvatarPrimitive.Image>,
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Image>
>(({ className, ...props }, ref) => (
<AvatarPrimitive.Image
ref={ref}
className={cn("aspect-square h-full w-full", className)}
{...props}
/>
))
AvatarImage.displayName = AvatarPrimitive.Image.displayName

const AvatarFallback = React.forwardRef<
React.ElementRef<typeof AvatarPrimitive.Fallback>,
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Fallback>
>(({ className, ...props }, ref) => (
<AvatarPrimitive.Fallback
ref={ref}
className={cn(
"flex h-full w-full items-center justify-center rounded-full bg-muted",
className
)}
{...props}
/>
))
AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName

export { Avatar, AvatarImage, AvatarFallback }
36 changes: 36 additions & 0 deletions frontend/components/ui/badge.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import * as React from "react"
import { cva, type VariantProps } from "class-variance-authority"

import { cn } from "@/lib/utils"

const badgeVariants = cva(
"inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
{
variants: {
variant: {
default:
"border-transparent bg-primary text-primary-foreground hover:bg-primary/80",
secondary:
"border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
destructive:
"border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
outline: "text-foreground",
},
},
defaultVariants: {
variant: "default",
},
}
)

export interface BadgeProps
extends React.HTMLAttributes<HTMLDivElement>,
VariantProps<typeof badgeVariants> {}

function Badge({ className, variant, ...props }: BadgeProps) {
return (
<div className={cn(badgeVariants({ variant }), className)} {...props} />
)
}

export { Badge, badgeVariants }
Loading
Loading