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

704 add events page #705

Merged
merged 13 commits into from
Jul 30, 2024
1 change: 1 addition & 0 deletions packages/api/src/types/Events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export type GetEventResponse = {
updatedAt: string;
description: string | null;
fields: unknown;
status: 'OPEN' | 'CLOSED' | 'UPCOMING' | null;
};

export type GetEventsResponse = GetEventResponse[];
4 changes: 2 additions & 2 deletions packages/berlin/src/components/cycles/Cycles.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,14 @@ function Cycles({ cycles, errorMessage, eventId }: CyclesProps) {
<>
{cycles?.length ? (
cycles.map((cycle) => (
<div
<article
className="border-secondary flex w-full flex-col gap-4 border p-4"
key={cycle.id}
onClick={() => handleCycleClick(cycle.id)}
>
<Body>{cycle?.questions[0]?.title}</Body>
<Body>{formatDate(cycle.endAt)}</Body>
</div>
</article>
))
) : (
<Body>{errorMessage}</Body>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import styled from 'styled-components';
import { FlexColumn } from '../containers/FlexColumn.styled';
import { FlexRowToColumn } from '../containers/FlexRowToColumn.styled';

export const Card = styled(FlexRowToColumn)`
border-radius: 0.5rem;
export const Card = styled(FlexColumn)`
border: 1px solid var(--color-black);
overflow: hidden;
width: 100%;
Expand All @@ -12,7 +10,7 @@ export const Card = styled(FlexRowToColumn)`
export const ImageContainer = styled.div`
background-color: var(--color-gray);
width: 100%;
height: 300px;
height: 160px;

img {
height: 100%;
Expand All @@ -24,4 +22,5 @@ export const ImageContainer = styled.div`

export const CardContent = styled(FlexColumn)`
padding: 2rem;
max-height: 170px;
`;
11 changes: 5 additions & 6 deletions packages/berlin/src/components/event-card/EventCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { GetEventResponse } from 'api';
import { Subtitle } from '../typography/Subtitle.styled';
import { Body } from '../typography/Body.styled';
import { Card, CardContent, ImageContainer } from './EventCard.styled';
import Button from '../button';
import Link from '../link';

// Third-party libraries
Expand All @@ -15,14 +14,12 @@ type EventCardProps = {

function EventCard({ event, onClick }: EventCardProps) {
return (
<Card $gap="0">
<ImageContainer>
<img src={event.imageUrl} alt={`${event.name} image`} />
</ImageContainer>
<Card className="cursor-pointer" $gap="0" onClick={onClick}>
<CardContent $gap="1.25rem">
<Subtitle>{event.name}</Subtitle>
{event.description && (
<Markdown
className="max-w-[100ch] truncate"
components={{
a: ({ node, ...props }) => <Link to={props.href ?? ''}>{props.children}</Link>,
p: ({ node, ...props }) => <Body>{props.children}</Body>,
Expand All @@ -31,8 +28,10 @@ function EventCard({ event, onClick }: EventCardProps) {
{event.description}
</Markdown>
)}
{onClick && <Button onClick={onClick}>Go</Button>}
</CardContent>
<ImageContainer>
<img src={event.imageUrl} alt={`${event.name} image`} />
</ImageContainer>
</Card>
);
}
Expand Down
60 changes: 60 additions & 0 deletions packages/berlin/src/components/events/Events.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import Markdown from 'react-markdown';

import { GetEventResponse } from 'api';

import { Body } from '../typography/Body.styled';
import { Subtitle } from '../typography/Subtitle.styled';
import Link from '../link';
import { useNavigate } from 'react-router-dom';

type EventsProps = {
events: GetEventResponse[] | undefined;
errorMessage: string;
};

export default function Events({ events, errorMessage }: EventsProps) {
const navigate = useNavigate();

const handleClick = (eventId: string) => {
navigate(`/events/${eventId}/cycles`);
};

return events?.length ? (
events.map((event) => {
return (
<article
key={event.id}
className="border-secondary flex w-full cursor-pointer flex-col border"
onClick={() => handleClick(event.id)}
>
<section className="flex flex-col gap-4 p-4">
<Subtitle>{event.name}</Subtitle>
{event.description && (
<Markdown
components={{
a: ({ node, ...props }) => <Link to={props.href ?? ''}>{props.children}</Link>,
p: ({ node, ...props }) => (
<Body className="truncate" style={{ whiteSpace: 'nowrap' }}>
{props.children}
</Body>
),
}}
>
{event.description}
</Markdown>
)}
</section>
<section className="h-40 w-full">
<img
className="h-full w-full object-cover object-center"
src={event.imageUrl}
alt={`${event.name} image`}
/>
</section>
</article>
);
})
) : (
<Body>{errorMessage}</Body>
);
}
1 change: 1 addition & 0 deletions packages/berlin/src/components/events/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './Events';
30 changes: 21 additions & 9 deletions packages/berlin/src/pages/Events.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// React and third-party libraries
import { useNavigate } from 'react-router-dom';
import { useMemo, useState } from 'react';
import { useQuery } from '@tanstack/react-query';

// API
Expand All @@ -11,27 +11,39 @@ import useUser from '../hooks/useUser';
// Components
import { FlexColumn } from '../components/containers/FlexColumn.styled';
import { Title } from '../components/typography/Title.styled';
import EventCard from '../components/event-card';
import * as Tabs from '../components/tabs';
import EventsCards from '../components/events';

function Events() {
const navigate = useNavigate();
const [activeTab, setActiveTab] = useState<string>('upcoming');
const { user } = useUser();
const { data: events } = useQuery({
queryKey: ['events'],
queryFn: () => fetchEvents({ serverUrl: import.meta.env.VITE_SERVER_URL }),
enabled: !!user?.id,
});

const handleClick = (eventId: string) => {
navigate(`/events/${eventId}/cycles`);
const openEvents = useMemo(() => events?.filter((event) => event.status === 'OPEN'), [events]);
const closedEvents = useMemo(
() => events?.filter((events) => events.status === 'CLOSED'),
[events],
);

const tabNames = ['upcoming', 'past'];
const tabs = {
upcoming: <EventsCards events={openEvents} errorMessage="No upcoming events..." />,
past: <EventsCards events={closedEvents} errorMessage="No past events..." />,
};

return (
<FlexColumn $gap="2rem">
<Title>Welcome, {user?.username ?? 'User'}</Title>
{events?.map((event) => {
return <EventCard key={event.id} event={event} onClick={() => handleClick(event.id)} />;
})}
<section className="flex w-full flex-col justify-between gap-2 md:flex-row md:items-center">
<Title>Events</Title>
<Tabs.TabsHeader className="tabs" tabNames={tabNames} onTabChange={setActiveTab} />
</section>
<section className="grid grid-cols-2 gap-4">
<Tabs.TabsManager tabs={tabs} tab={activeTab} fallback={'Tab not found'} />
</section>
</FlexColumn>
);
}
Expand Down
Loading