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

Event feed initialisation #44

Open
wants to merge 10 commits into
base: main
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
4 changes: 3 additions & 1 deletion apps/frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"lint": "next lint"
},
"dependencies": {
"@lucide/lab": "^0.1.2",
"@radix-ui/react-avatar": "^1.1.0",
"@tanstack/react-query": "^5.52.0",
"axios": "^1.7.4",
Expand All @@ -23,7 +24,8 @@
"react": "^18.2.0",
"react-dom": "^18.2.0",
"tailwind-merge": "^2.3.0",
"tailwindcss-animate": "^1.0.7"
"tailwindcss-animate": "^1.0.7",
"vaul": "^0.9.1"
},
"devDependencies": {
"@tanstack/eslint-plugin-query": "^5.52.0",
Expand Down
93 changes: 87 additions & 6 deletions apps/frontend/src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,96 @@
'use client';
import { Plus } from 'lucide-react';
import Link from 'next/link';

import { CommentSection } from '@/components/comment-section';
import { DrinkList } from '@/components/drinkAction-drink-list';
import { EventDiscription } from '@/components/event-discription';
import { ShareLink } from '@/components/share-link';
import { Button } from '@/components/ui/button';
import {
Pagination,
PaginationContent,
PaginationEllipsis,
PaginationItem,
PaginationLink,
PaginationNext,
PaginationPrevious,
} from '@/components/ui/pagination';
import { UserAvatar } from '@/components/user-avatar';
import { UserHoverCard } from '@/components/user-hovercard';
import { events } from '@/models/mockData';

export default function Home() {
import { LikeButton } from '../../src/components/like-button';

export default function EventFeedPage() {
return (
<main className='flex items-center justify-center'>
{events.map((e) => (
<Link key={e.id} href={`/events/${e.id}`}>
<h2>{e.name}</h2>
<main>
<div className='flex flex-col items-center justify-center bg-green-300'>
<Link href='http://bealcoholic.com'>
Copy link
Member

Choose a reason for hiding this comment

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

don't hardcode any URLs, you can just use '/' here, that will redirect to the main page

<h1 className='text-4xl font-bold m-3'>BeAlcoholic</h1>
</Link>
))}
</div>
<div className='flex flex-col items-end justify-end mr-20 mt-10'>
<Button variant='default' asChild>
<Link href='/events/new'>
<Plus className='size-5 -ml-1' /> Új Esemény
</Link>
</Button>
</div>

<div className='flex flex-col items-center justify-center'>
<div className='w-[61rem]'>
{events.map((event) => (
<div key={event.id} className='my-4'>
{/* <Link href={`/events/${event.id}`}> */}
Copy link
Member

Choose a reason for hiding this comment

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

why is this commented out?

Copy link
Member

Choose a reason for hiding this comment

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

ohh I see, the other buttons don't work. I'll show you how it can be fixed
spoiler: https://developer.mozilla.org/en-US/docs/Web/API/Event/stopPropagation

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thank you SO MUCH! I spent hours trying to find the answer without any success.

<div className='bg-white rounded-lg shadow-md p-4 flex items-start'>
<div className='flex-shrink-0 mr-4'>
<UserAvatar user={event.owner} />
</div>
<div>
<h2 className='text-2xl font-bold'>{event.name}</h2>
<p className='text-sm'>
Létrehozta: <UserHoverCard user={event.owner} />
</p>
<div>
<DrinkList event={event} />
</div>
<div>
<EventDiscription event={event} />
</div>
<p className='text-gray-600 text-xs mt-2'>
{event.startDate.toLocaleString('hu')} - {event.endDate.toLocaleString('hu')}
Copy link
Member

Choose a reason for hiding this comment

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

this should be further refined, really no need to display the seconds. Would be even better if the common parts of the two dates (year, month and possibly day) would only be shown once

</p>
<div className='flex flex-row mt-3'>
<LikeButton />
<CommentSection />
<ShareLink event={event} />
</div>
</div>
</div>
{/* </Link> */}
</div>
))}
</div>
</div>
<footer>
<Pagination>
<PaginationContent>
<PaginationItem>
<PaginationPrevious href='#' />
</PaginationItem>
<PaginationItem>
<PaginationLink href='#'>1</PaginationLink>
</PaginationItem>
<PaginationItem>
<PaginationEllipsis />
</PaginationItem>
<PaginationItem>
<PaginationNext href='#' />
</PaginationItem>
</PaginationContent>
</Pagination>
</footer>
</main>
);
}
48 changes: 48 additions & 0 deletions apps/frontend/src/components/comment-section.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { MessageCircleMore, SendHorizonal } from 'lucide-react';

import {
Drawer,
DrawerClose,
DrawerContent,
DrawerDescription,
DrawerFooter,
DrawerHeader,
DrawerTitle,
DrawerTrigger,
} from '@/components/ui/drawer';

import { Button } from './ui/button';
import { Input } from './ui/input';

export function CommentSection() {
return (
<Drawer>
<DrawerTrigger asChild>
<Button variant='ghost'>
<MessageCircleMore className='mr-2 ml-6' /> Comment
</Button>
</DrawerTrigger>
<DrawerContent>
<div className='mx-auto w-full max-w-sm'>
<DrawerHeader>
<DrawerTitle>Comment Section</DrawerTitle>
<DrawerDescription>You can leave comments or talk to other users.</DrawerDescription>
</DrawerHeader>
<div className='flex w-full max-w-sm items-center space-x-2'>
<Input type='text' placeholder='Comment' />
<Button type='submit'>
<SendHorizonal className='-mx-3 -my-1' />
</Button>
</div>
<DrawerFooter>
<DrawerClose asChild>
<Button variant='outline' className='-mx-4'>
Close
</Button>
</DrawerClose>
</DrawerFooter>
</div>
</DrawerContent>
</Drawer>
);
}
7 changes: 4 additions & 3 deletions apps/frontend/src/components/drink-type-badge.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Beer, Skull, Wine } from 'lucide-react';
import { cocktail, wineGlassBottle } from '@lucide/lab';
import { Beer, Icon, Skull } from 'lucide-react';

import { DrinkType } from '@/models/drink';

Expand All @@ -19,13 +20,13 @@ export function DrinkTypeBadge({ type }: Props) {
case DrinkType.WINE:
return (
<Badge variant='outline' className='bg-red-900 text-white'>
<Wine />
<Icon iconNode={wineGlassBottle} />
</Badge>
);
case DrinkType.COCKTAIL:
return (
<Badge variant='outline' className='bg-teal-500'>
<Wine />
<Icon iconNode={cocktail} />
</Badge>
);
case DrinkType.SPIRIT:
Expand Down
29 changes: 29 additions & 0 deletions apps/frontend/src/components/drinkAction-drink-list.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { Card, CardContent } from '@/components/ui/card';
import { Carousel, CarouselContent, CarouselItem } from '@/components/ui/carousel';
import { EventDetails } from '@/models/event';

interface Props {
event: EventDetails;
}

export function DrinkList({ event }: Props) {
return (
<Carousel className='w-[51rem]'>
<CarouselContent className='-ml-1'>
{event.drinkActions.map((drinkAction) => (
Copy link
Member

Choose a reason for hiding this comment

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

I think we shouldn't show every drink action here (though it might work with the carousel), would be better to show some stats, like most consumed drinks

// eslint-disable-next-line react/no-array-index-key
<CarouselItem key={drinkAction.id} className='pl-1 md:basis-1/2 lg:basis-auto'>
<div className='p-1'>
<Card className='w-48 h-48'>
<CardContent className='flex flex-col aspect-square items-center justify-center p-6 w-auto'>
<span className='text-xl font-semibold no-'>{drinkAction.drink.name}</span>
<span className='text-xs mt-5'>Alcohol Content: {drinkAction.drink.alcoholContent}%</span>
</CardContent>
</Card>
Comment on lines +17 to +22
Copy link
Member

Choose a reason for hiding this comment

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

I'd make this smaller

</div>
</CarouselItem>
))}
</CarouselContent>
</Carousel>
);
}
48 changes: 48 additions & 0 deletions apps/frontend/src/components/event-discription.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { useEffect, useRef, useState } from 'react';

import { EventDetails } from '@/models/event';

interface Props {
event: EventDetails;
}
export function EventDiscription({ event }: Props) {
const [showFullText, setShowFullText] = useState(false);
const descriptionRef = useRef<HTMLParagraphElement>(null);

const handleShowMoreClick = () => {
setShowFullText(true);
};

const handleShowLessClick = () => {
setShowFullText(false);
};

useEffect(() => {
if (descriptionRef.current) {
descriptionRef.current.style.maxHeight = showFullText ? `${descriptionRef.current.scrollHeight}px` : '1.5rem';
}
}, [showFullText]);

if (!event?.description || event?.description.trim() === '') {
return null;
}

return (
<div className='w-[53rem]'>
<p ref={descriptionRef} className='overflow-hidden transition-max-h duration-500'>
{event.description}
</p>

{!showFullText && event?.description.length > 100 && (
<button onClick={handleShowMoreClick} className='underline'>
Show more
</button>
)}
{showFullText && (
<button onClick={handleShowLessClick} className='underline'>
Show less
</button>
)}
</div>
);
}
12 changes: 0 additions & 12 deletions apps/frontend/src/components/hello-world.tsx

This file was deleted.

27 changes: 27 additions & 0 deletions apps/frontend/src/components/like-button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { ThumbsUp } from 'lucide-react';
import { useState } from 'react';

import { Button } from './ui/button';

export function LikeButton() {
const [liked, setLiked] = useState(false);
const [likeCount, setLikeCount] = useState(0);
const [isAnimating, setIsAnimating] = useState(false);

const handleLikeClick = () => {
setLiked(!liked);
setLikeCount(liked ? likeCount - 1 : likeCount + 1);
setIsAnimating(true);
setTimeout(() => setIsAnimating(false), 300);
};

return (
<Button variant='ghost' onClick={handleLikeClick}>
<ThumbsUp
className={`-ml-6 mr-2 -mt-1 transition-transform duration-300 ${isAnimating ? 'scale-125 rotate-12' : ''}`}
color={liked ? '#22c55e' : 'black'}
/>
{liked ? likeCount : 'Like'}
</Button>
);
}
75 changes: 75 additions & 0 deletions apps/frontend/src/components/share-link.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { DialogClose } from '@radix-ui/react-dialog';
import { Copy, Share2 } from 'lucide-react';
import { useState } from 'react';

import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from '@/components/ui/dialog';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { EventDetails } from '@/models/event';

import { Button } from './ui/button';

type Props = {
event: EventDetails;
};

export function ShareLink({ event }: Props) {
const [copied, setCopied] = useState(false);

const handleCopyClick = (id: string) => {
const linkToCopy = `https://bealcoholic.com/events/${id}`;
Copy link
Member

Choose a reason for hiding this comment

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

we'll store the actual url in an environment variable, but it's fine for now

navigator.clipboard
.writeText(linkToCopy)
.then(() => {
setCopied(true);
setTimeout(() => setCopied(false), 1500);
})
.catch((err) => {
console.error('Hiba történt a másolás során:', err);
});
};

return (
<Dialog>
<DialogTrigger asChild>
<Button variant='ghost'>
<Share2 className='mr-2 ml-6' /> Share
</Button>
</DialogTrigger>
<DialogContent className='sm:max-w-md'>
<DialogHeader>
<DialogTitle>Share link</DialogTitle>
<DialogDescription>Anyone who has this link will be able to view this Event.</DialogDescription>
</DialogHeader>
<div className='flex items-center space-x-2'>
<div className='grid flex-1 gap-2'>
<Label htmlFor='link' className='sr-only'>
Link
</Label>
<Input id='link' defaultValue={`https://bealcoholic.com/events/${event.id}`} readOnly />
</div>
<Button type='submit' size='sm' className='px-3' onClick={() => handleCopyClick(event.id)}>
<span className='sr-only'>Copy</span>
<Copy className='h-4 w-4' />
{copied && <span>Copied!</span>}
Comment on lines +61 to +62
Copy link
Member

Choose a reason for hiding this comment

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

some spacing would be nice here

</Button>
</div>
<DialogFooter className='sm:justify-start'>
<DialogClose asChild>
<Button type='button' variant='secondary'>
Close
</Button>
</DialogClose>
</DialogFooter>
</DialogContent>
</Dialog>
);
}
Loading