From 6324c24803a22f170251e4b326aaae648a8b031d Mon Sep 17 00:00:00 2001 From: justnyx Date: Mon, 17 Mar 2025 20:11:44 +0100 Subject: [PATCH 01/27] created members page --- .gitignore | 1 + apps/frontend/src/app/members/page.tsx | 45 +++++++++++++ .../src/components/layout/sidebar.tsx | 9 ++- .../src/components/member/memberRow.tsx | 64 +++++++++++++++++++ apps/frontend/src/components/ui/badge.tsx | 32 ++++++++++ apps/frontend/src/components/ui/card.tsx | 49 ++++++++++++++ apps/frontend/src/mocks/users.ts | 49 ++++++++++++++ apps/frontend/src/types/user.ts | 15 +++++ 8 files changed, 263 insertions(+), 1 deletion(-) create mode 100644 apps/frontend/src/app/members/page.tsx create mode 100644 apps/frontend/src/components/member/memberRow.tsx create mode 100644 apps/frontend/src/components/ui/badge.tsx create mode 100644 apps/frontend/src/components/ui/card.tsx create mode 100644 apps/frontend/src/mocks/users.ts create mode 100644 apps/frontend/src/types/user.ts diff --git a/.gitignore b/.gitignore index f1175b1..22e7824 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ yarn-debug.log* yarn-error.log* .DS_Store .env +.env diff --git a/apps/frontend/src/app/members/page.tsx b/apps/frontend/src/app/members/page.tsx new file mode 100644 index 0000000..89af84e --- /dev/null +++ b/apps/frontend/src/app/members/page.tsx @@ -0,0 +1,45 @@ +'use client'; + +import MemberRow from '@components/member/memberRow'; +import { Input } from '@components/ui/input'; +import { Table, TableBody, TableCell, TableRow } from '@components/ui/table'; +import { useEffect, useState } from 'react'; + +import { mockUsers } from '@/mocks/users'; + +export default function Members() { + const data = mockUsers; + const [filteredData, setFilteredData] = useState(data); + const [searchTerm, setSearchTerm] = useState(''); + + useEffect(() => { + setFilteredData(data.filter((user) => user.name.toLowerCase().includes(searchTerm.toLowerCase()))); + }, [searchTerm]); + + return ( +
+
+

Felhasználók

+ setSearchTerm(event.target.value)} + className='max-w-sm target:ring-0' + /> +
+ + + {filteredData.length ? ( + filteredData.map((user) => ) + ) : ( + + + Nincs találat. + + + )} + +
+
+ ); +} diff --git a/apps/frontend/src/components/layout/sidebar.tsx b/apps/frontend/src/components/layout/sidebar.tsx index 333fbc0..3c1846f 100644 --- a/apps/frontend/src/components/layout/sidebar.tsx +++ b/apps/frontend/src/components/layout/sidebar.tsx @@ -8,6 +8,7 @@ import { MicVocal, Plus, Radio, + Users2, } from 'lucide-react'; import Link from 'next/link'; @@ -26,11 +27,17 @@ export function Sidebar() { +
diff --git a/apps/frontend/src/components/member/memberRow.tsx b/apps/frontend/src/components/member/memberRow.tsx new file mode 100644 index 0000000..e7fac1f --- /dev/null +++ b/apps/frontend/src/components/member/memberRow.tsx @@ -0,0 +1,64 @@ +import { Collapsible } from '@components/ui/collapsible'; +import { TableCell, TableRow } from '@components/ui/table'; + +import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'; +import { Badge } from '@/components/ui/badge'; +import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; +import { User } from '@/types/user'; + +export default function MemberRow({ user }: { user: User }) { + return ( + + <> + + + +
+
+ +
+
+ {user?.name} +
+

{user?.email}

+

{user?.phone}

+
+

{user?.roomNumber}

+
+
+
+ +
+
+ {user.role === 'ADMIN' && Admin} + + {user?.role === 'ADMIN' || user?.role === 'GATEKEEPER' ? 'Beengedő' : 'Felhasználó'} + + + {user?.isDormResident ? 'Kolis' : 'Nem kolis'} + +
+
+
+
+
+ + + + {user?.name + .split(' ') + .map((n) => n[0]) + .join('')} + + +
+
+
+
+
+ +
+ ); +} diff --git a/apps/frontend/src/components/ui/badge.tsx b/apps/frontend/src/components/ui/badge.tsx new file mode 100644 index 0000000..ddffd45 --- /dev/null +++ b/apps/frontend/src/components/ui/badge.tsx @@ -0,0 +1,32 @@ +import { cva, type VariantProps } from 'class-variance-authority'; +import * as React from 'react'; + +import { cn } from '@/lib/utils'; + +const badgeVariants = cva( + 'inline-flex items-center rounded-full border border-slate-200 px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-slate-950 focus:ring-offset-2 dark:border-slate-800 dark:focus:ring-slate-300', + { + variants: { + variant: { + default: + 'border-transparent bg-orange-500 text-slate-50 hover:bg-orange-400/80 dark:bg-orange-700 dark:text-slate-50 dark:hover:bg-orange-500/80', + secondary: + 'border-transparent bg-slate-100 text-slate-900 hover:bg-slate-400/80 dark:bg-zinc-700 dark:text-slate-50 dark:hover:bg-zinc-500/80', + destructive: + 'border-transparent bg-red-500 text-slate-50 hover:bg-red-500/80 dark:bg-red-900 dark:text-slate-50 dark:hover:bg-red-900/80', + outline: 'text-slate-950 dark:text-slate-50', + }, + }, + defaultVariants: { + variant: 'default', + }, + } +); + +export interface BadgeProps extends React.HTMLAttributes, VariantProps {} + +function Badge({ className, variant, ...props }: BadgeProps) { + return
; +} + +export { Badge, badgeVariants }; diff --git a/apps/frontend/src/components/ui/card.tsx b/apps/frontend/src/components/ui/card.tsx new file mode 100644 index 0000000..45f7a8d --- /dev/null +++ b/apps/frontend/src/components/ui/card.tsx @@ -0,0 +1,49 @@ +/* eslint-disable react/prop-types */ +import * as React from 'react'; + +import { cn } from '@/lib/utils'; + +const Card = React.forwardRef>(({ className, ...props }, ref) => ( +
+)); +Card.displayName = 'Card'; + +const CardHeader = React.forwardRef>( + ({ className, ...props }, ref) => ( +
+ ) +); +CardHeader.displayName = 'CardHeader'; + +const CardTitle = React.forwardRef>( + ({ className, ...props }, ref) => ( +
+ ) +); +CardTitle.displayName = 'CardTitle'; + +const CardDescription = React.forwardRef>( + ({ className, ...props }, ref) => ( +
+ ) +); +CardDescription.displayName = 'CardDescription'; + +const CardContent = React.forwardRef>( + ({ className, ...props }, ref) =>
+); +CardContent.displayName = 'CardContent'; + +const CardFooter = React.forwardRef>( + ({ className, ...props }, ref) =>
+); +CardFooter.displayName = 'CardFooter'; + +export { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle }; diff --git a/apps/frontend/src/mocks/users.ts b/apps/frontend/src/mocks/users.ts new file mode 100644 index 0000000..e5667c5 --- /dev/null +++ b/apps/frontend/src/mocks/users.ts @@ -0,0 +1,49 @@ +import { User } from '@/types/user'; + +export const mockUsers: User[] = [ + { + id: 1, + name: 'Alice Walker', + email: 'alice@email.com', + isDormResident: true, + roomNumber: '201', + role: 'USER', + profilePicture: '/placeholder.svg', + created_at: '2021-08-01T00:00:00.000Z', + updated_at: '2021-08-01T00:00:00.000Z', + }, + { + id: 2, + name: 'Bob Smith', + email: 'bob@email.com', + phone: '987654321', + isDormResident: false, + role: 'ADMIN', + profilePicture: '/placeholder.svg', + created_at: '2021-08-01T00:00:00.000Z', + updated_at: '2021-08-01T00:00:00.000Z', + }, + { + id: 3, + name: 'Charlie Brown', + email: 'charlie@email.com', + phone: '123456789', + isDormResident: true, + roomNumber: '202', + role: 'GATEKEEPER', + profilePicture: '/placeholder.svg', + created_at: '2021-08-01T00:00:00.000Z', + updated_at: '2021-08-01T00:00:00.000Z', + }, + { + id: 4, + name: 'David Johnson', + email: 'david@email.com', + phone: '1239874748', + isDormResident: false, + role: 'USER', + profilePicture: '/placeholder.svg', + created_at: '2021-08-01T00:00:00.000Z', + updated_at: '2021-08-01T00:00:00.000Z', + }, +]; diff --git a/apps/frontend/src/types/user.ts b/apps/frontend/src/types/user.ts new file mode 100644 index 0000000..068cef0 --- /dev/null +++ b/apps/frontend/src/types/user.ts @@ -0,0 +1,15 @@ +import { CardRight, ProfilePicture } from '.prisma/client'; + +export type User = { + id: number; + name: string; + email: string; + phone?: string; + isDormResident: boolean; + roomNumber?: string; + role: string; + cardRight?: CardRight; + profilePicture?: ProfilePicture | string; + created_at: string; + updated_at: string; +}; From ad549d41a87377d2c72699a0e0d9989f8cc9386e Mon Sep 17 00:00:00 2001 From: justnyx Date: Mon, 17 Mar 2025 20:12:25 +0100 Subject: [PATCH 02/27] fixed git ignore --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index 22e7824..f1175b1 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,3 @@ yarn-debug.log* yarn-error.log* .DS_Store .env -.env From f40677973b5cb15fdda4ed424643a349fbeb69cd Mon Sep 17 00:00:00 2001 From: justnyx Date: Mon, 17 Mar 2025 20:23:44 +0100 Subject: [PATCH 03/27] fixed eslint issue --- .../src/components/member/memberRow.tsx | 90 +++++++++---------- 1 file changed, 43 insertions(+), 47 deletions(-) diff --git a/apps/frontend/src/components/member/memberRow.tsx b/apps/frontend/src/components/member/memberRow.tsx index e7fac1f..5939c05 100644 --- a/apps/frontend/src/components/member/memberRow.tsx +++ b/apps/frontend/src/components/member/memberRow.tsx @@ -9,56 +9,52 @@ import { User } from '@/types/user'; export default function MemberRow({ user }: { user: User }) { return ( - <> - - - -
-
- -
-
- {user?.name} -
-

{user?.email}

-

{user?.phone}

-
-

{user?.roomNumber}

-
-
-
- -
-
- {user.role === 'ADMIN' && Admin} - - {user?.role === 'ADMIN' || user?.role === 'GATEKEEPER' ? 'Beengedő' : 'Felhasználó'} - - - {user?.isDormResident ? 'Kolis' : 'Nem kolis'} - + + + +
+
+ +
+
+ {user?.name} +
+

{user?.email}

+

{user?.phone}

+

{user?.roomNumber}

-
-
-
- - - - {user?.name - .split(' ') - .map((n) => n[0]) - .join('')} - - -
+
+ + +
+
+ {user.role === 'ADMIN' && Admin} + + {user?.role === 'ADMIN' || user?.role === 'GATEKEEPER' ? 'Beengedő' : 'Felhasználó'} + + + {user?.isDormResident ? 'Kolis' : 'Nem kolis'} + +
+
+
+
+
+ + + + {user?.name + .split(' ') + .map((n) => n[0]) + .join('')} + +
- - - - +
+ + + ); } From 7d8eabbfb78d01f4460d0e5f39b5936ed249008b Mon Sep 17 00:00:00 2001 From: justnyx Date: Tue, 17 Jun 2025 16:34:33 +0200 Subject: [PATCH 04/27] new tile design --- apps/frontend/src/app/members/page.tsx | 25 +++---- .../src/components/member/memberRow.tsx | 60 ----------------- .../src/components/member/memberTile.tsx | 67 +++++++++++++++++++ 3 files changed, 77 insertions(+), 75 deletions(-) delete mode 100644 apps/frontend/src/components/member/memberRow.tsx create mode 100644 apps/frontend/src/components/member/memberTile.tsx diff --git a/apps/frontend/src/app/members/page.tsx b/apps/frontend/src/app/members/page.tsx index 89af84e..1c51b1a 100644 --- a/apps/frontend/src/app/members/page.tsx +++ b/apps/frontend/src/app/members/page.tsx @@ -1,10 +1,9 @@ 'use client'; -import MemberRow from '@components/member/memberRow'; import { Input } from '@components/ui/input'; -import { Table, TableBody, TableCell, TableRow } from '@components/ui/table'; import { useEffect, useState } from 'react'; +import MemberTile from '@/components/member/memberTile'; import { mockUsers } from '@/mocks/users'; export default function Members() { @@ -27,19 +26,15 @@ export default function Members() { className='max-w-sm target:ring-0' />
- - - {filteredData.length ? ( - filteredData.map((user) => ) - ) : ( - - - Nincs találat. - - - )} - -
+ {filteredData.length ? ( +
+ {filteredData.map((user) => ( + + ))} +
+ ) : ( +
Nincs találat.
+ )}
); } diff --git a/apps/frontend/src/components/member/memberRow.tsx b/apps/frontend/src/components/member/memberRow.tsx deleted file mode 100644 index 5939c05..0000000 --- a/apps/frontend/src/components/member/memberRow.tsx +++ /dev/null @@ -1,60 +0,0 @@ -import { Collapsible } from '@components/ui/collapsible'; -import { TableCell, TableRow } from '@components/ui/table'; - -import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'; -import { Badge } from '@/components/ui/badge'; -import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; -import { User } from '@/types/user'; - -export default function MemberRow({ user }: { user: User }) { - return ( - - - - -
-
- -
-
- {user?.name} -
-

{user?.email}

-

{user?.phone}

-
-

{user?.roomNumber}

-
-
-
- -
-
- {user.role === 'ADMIN' && Admin} - - {user?.role === 'ADMIN' || user?.role === 'GATEKEEPER' ? 'Beengedő' : 'Felhasználó'} - - - {user?.isDormResident ? 'Kolis' : 'Nem kolis'} - -
-
-
-
-
- - - - {user?.name - .split(' ') - .map((n) => n[0]) - .join('')} - - -
-
-
-
-
-
- ); -} diff --git a/apps/frontend/src/components/member/memberTile.tsx b/apps/frontend/src/components/member/memberTile.tsx new file mode 100644 index 0000000..7d4b6c7 --- /dev/null +++ b/apps/frontend/src/components/member/memberTile.tsx @@ -0,0 +1,67 @@ +import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'; +import { Badge } from '@/components/ui/badge'; +import { Card } from '@/components/ui/card'; +import { User } from '@/types/user'; + +function getRoleLabel(role: string) { + switch (role) { + case 'ADMIN': + return 'Admin'; + case 'GATEKEEPER': + return 'Beengedő'; + default: + return 'Felhasználó'; + } +} + +function getRoleVariant(role: string) { + switch (role) { + case 'ADMIN': + return 'destructive'; + case 'GATEKEEPER': + return 'default'; + default: + return 'secondary'; + } +} + +export default function MemberTile({ user }: { user: User }) { + return ( +
+ + {/* Role badge at the top */} +
+ + {getRoleLabel(user.role)} + +
+ {/* Profile picture */} +
+ + + + {user.name + .split(' ') + .map((n) => n[0]) + .join('')} + + +
+ {/* Name */} +
{user.name}
+
+ {/* Details below the tile */} +
+
+ {user.email} + {user.phone && {user.phone}} +
+ {user.roomNumber && ( +
+ {user.roomNumber} +
+ )} +
+
+ ); +} From 6fe6079acea2412fe45effc4430d2621ac19061f Mon Sep 17 00:00:00 2001 From: justnyx Date: Tue, 17 Jun 2025 17:22:51 +0200 Subject: [PATCH 05/27] created stats page --- apps/frontend/src/app/members/page.tsx | 2 +- apps/frontend/src/app/stats/page.tsx | 61 +++++++++++++++++++ .../src/components/layout/sidebar.tsx | 2 +- apps/frontend/src/mocks/gatekeepings.ts | 10 +++ apps/frontend/src/types/gatekeeping.ts | 5 ++ 5 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 apps/frontend/src/app/stats/page.tsx create mode 100644 apps/frontend/src/mocks/gatekeepings.ts create mode 100644 apps/frontend/src/types/gatekeeping.ts diff --git a/apps/frontend/src/app/members/page.tsx b/apps/frontend/src/app/members/page.tsx index 1c51b1a..e78a654 100644 --- a/apps/frontend/src/app/members/page.tsx +++ b/apps/frontend/src/app/members/page.tsx @@ -7,7 +7,7 @@ import MemberTile from '@/components/member/memberTile'; import { mockUsers } from '@/mocks/users'; export default function Members() { - const data = mockUsers; + const data = mockUsers; //TODO: replace with real data const [filteredData, setFilteredData] = useState(data); const [searchTerm, setSearchTerm] = useState(''); diff --git a/apps/frontend/src/app/stats/page.tsx b/apps/frontend/src/app/stats/page.tsx new file mode 100644 index 0000000..64a6054 --- /dev/null +++ b/apps/frontend/src/app/stats/page.tsx @@ -0,0 +1,61 @@ +import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'; +import { mockGatekeepings } from '@/mocks/gatekeepings'; +import { mockUsers } from '@/mocks/users'; +import { User } from '@/types/user'; + +const currentUser: User = mockUsers[1]; //TODO: replace with real user +const data = mockGatekeepings; //TODO: replace with real data + +function isAuthorized(user: User) { + return user.role === 'ADMIN' || user.role === 'GATEKEEPER'; +} + +function getCurrentPeriodStart() { + //TODO: replace with real period + const now = new Date(); + return new Date(now.getFullYear(), now.getMonth(), 1); +} + +export default function Stats() { + if (!isAuthorized(currentUser)) { + return ( +
+
+ Access denied. You do not have permission to view this page. +
+
+ ); + } + + const periodStart = getCurrentPeriodStart(); + const gatekeepers = mockUsers.filter((u) => u.role === 'GATEKEEPER' || u.role === 'ADMIN'); + + const gatekeepingCounts = gatekeepers.map((gk) => { + const count = data.filter((gkEvent) => gkEvent.userId === gk.id && new Date(gkEvent.date) >= periodStart).length; + return { ...gk, count }; + }); + + return ( +
+
+

Beengedési statisztika

+
+ + + + Név + Beengedések + + + + {gatekeepingCounts.map((gk) => ( + + {gk.name} + {gk.count} + + ))} + +
+
+ ); +} diff --git a/apps/frontend/src/components/layout/sidebar.tsx b/apps/frontend/src/components/layout/sidebar.tsx index 3c1846f..22ed5d5 100644 --- a/apps/frontend/src/components/layout/sidebar.tsx +++ b/apps/frontend/src/components/layout/sidebar.tsx @@ -74,7 +74,7 @@ export function Sidebar() { - - - - -