Skip to content

Commit

Permalink
599 update agenda page (#600)
Browse files Browse the repository at this point in the history
* Create TabsHeader and TabsManager

* Create cycle component

* Update Event

* Remove gap

* Update tabs header

* Add groups to event page

* Fixes

* join tabs components

---------

Co-authored-by: Diego Alzate <[email protected]>
  • Loading branch information
camilovegag and diegoalzate authored Jun 20, 2024
1 parent f74069e commit 85c263a
Show file tree
Hide file tree
Showing 12 changed files with 189 additions and 71 deletions.
9 changes: 9 additions & 0 deletions packages/berlin/src/components/cycles/Cycles.styled.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import styled from 'styled-components';
import { FlexRowToColumn } from '../containers/FlexRowToColumn.styled';

export const CycleContainer = styled(FlexRowToColumn)`
border: 1px solid var(--color-black);
padding: 2rem;
justify-content: space-between;
border-radius: 0.5rem;
`;
32 changes: 32 additions & 0 deletions packages/berlin/src/components/cycles/Cycles.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { GetCycleResponse } from 'api';
import { Body } from '../typography/Body.styled';
import { CycleContainer } from './Cycles.styled';

type CyclesProps = {
cycles: GetCycleResponse[] | undefined;
errorMessage: string;
};

function Cycles({ cycles, errorMessage }: CyclesProps) {
const formatDate = (date: string) => {
const eventEndDate = new Date(date);
return eventEndDate.toLocaleDateString();
};

return (
<>
{cycles?.length ? (
cycles.map((cycle) => (
<CycleContainer key={cycle.id}>
<Body>{cycle.forumQuestions[0]?.questionTitle}</Body>
<Body>{formatDate(cycle.endAt)}</Body>
</CycleContainer>
))
) : (
<Body>{errorMessage}</Body>
)}
</>
);
}

export default Cycles;
1 change: 1 addition & 0 deletions packages/berlin/src/components/cycles/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './Cycles';
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { FlexColumn } from '../containers/FlexColumn.styled';
import { FlexRowToColumn } from '../containers/FlexRowToColumn.styled';

export const Card = styled(FlexRowToColumn)`
border-radius: 1rem;
border-radius: 0.5rem;
border: 1px solid var(--color-black);
overflow: hidden;
width: 100%;
Expand Down
2 changes: 1 addition & 1 deletion packages/berlin/src/components/event-card/EventCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ type EventCardProps = {

function EventCard({ event, onClick }: EventCardProps) {
return (
<Card>
<Card $gap="0">
<ImageContainer>
<img src={event.imageUrl} alt={`${event.name} image`} />
</ImageContainer>
Expand Down
1 change: 0 additions & 1 deletion packages/berlin/src/components/tab-manager/index.ts

This file was deleted.

21 changes: 21 additions & 0 deletions packages/berlin/src/components/tabs/TabsHeader.styled.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import styled from 'styled-components';
import { Body } from '../typography/Body.styled';
import { FlexRow } from '../containers/FlexRow.styled';

export const Tabs = styled(FlexRow)`
justify-content: flex-start;
@media (min-width: 600px) {
justify-content: flex-end;
}
`;

export const Tab = styled(Body)`
cursor: pointer;
text-transform: capitalize;
&.active {
font-weight: 600;
text-decoration: underline;
}
`;
36 changes: 36 additions & 0 deletions packages/berlin/src/components/tabs/TabsHeader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { Fragment, useState } from 'react';
import { Body } from '../typography/Body.styled';
import { Tab, Tabs } from './TabsHeader.styled';

type TabsHeaderProps = {
tabNames: string[];
initialTab?: string;
onTabChange?: (tab: string) => void;
};

export function TabsHeader({ tabNames, initialTab, onTabChange }: TabsHeaderProps) {
const [activeTab, setActiveTab] = useState<string>(initialTab || tabNames[0]);

const handleTabClick = (tab: string) => {
setActiveTab(tab);
if (onTabChange) {
onTabChange(tab);
}
};

return (
<Tabs $gap="0.5rem">
{tabNames.map((tabName, index) => (
<Fragment key={tabName}>
<Tab
className={activeTab === tabName ? 'active' : ''}
onClick={() => handleTabClick(tabName)}
>
{tabName}
</Tab>
{index < tabNames.length - 1 && <Body>/</Body>}
</Fragment>
))}
</Tabs>
);
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export function TabManager<T extends string>({
export function TabsManager<T extends string>({
tabs,
tab,
fallback,
Expand Down
2 changes: 2 additions & 0 deletions packages/berlin/src/components/tabs/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './TabsHeader';
export * from './TabsManager';
4 changes: 2 additions & 2 deletions packages/berlin/src/pages/Account.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Title } from '../components/typography/Title.styled';
import useUser from '../hooks/useUser';
import { FlexColumn } from '../components/containers/FlexColumn.styled';
import { FlexRow } from '../components/containers/FlexRow.styled';
import { TabManager } from '../components/tab-manager';
import { TabsManager } from '../components/tabs';
import { Edit, X } from 'lucide-react';
import {
GetUserResponse,
Expand Down Expand Up @@ -64,7 +64,7 @@ function Account() {
/>
)}
</FlexRow>
<TabManager tabs={tabs} tab={tab} fallback={<Title>Tab not found</Title>} />
<TabsManager tabs={tabs} tab={tab} fallback={<Title>Tab not found</Title>} />
</FlexColumn>
);
}
Expand Down
148 changes: 83 additions & 65 deletions packages/berlin/src/pages/Event.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,28 @@
// React and third-party libraries
import { useMemo } from 'react';
import { useState, useMemo } from 'react';
import { useQuery } from '@tanstack/react-query';
import { useNavigate, useParams } from 'react-router-dom';

// API
import { GetCycleResponse, fetchEvent, fetchEventCycles } from 'api';
import {
fetchEvent,
fetchEventCycles,
fetchEventGroupCategories,
GetGroupCategoriesResponse,
} from 'api';

// Components
import { Body } from '../components/typography/Body.styled';
import { FlexColumn } from '../components/containers/FlexColumn.styled';
import { Table } from '../components/table';
import { FlexRow } from '../components/containers/FlexRow.styled';
import { Subtitle } from '../components/typography/Subtitle.styled';
import Button from '../components/button';
import Cycles from '../components/cycles';
import EventCard from '../components/event-card';
import Link from '../components/link';
import * as Tabs from '../components/tabs';

function Event() {
const navigate = useNavigate();
const { eventId } = useParams();
const { data: event } = useQuery({
queryKey: ['event', eventId],
Expand All @@ -30,6 +37,12 @@ function Event() {
refetchInterval: 5000, // Poll every 5 seconds
});

const { data: groupCategories } = useQuery({
queryKey: ['event', eventId, 'group-categories'],
queryFn: () => fetchEventGroupCategories(eventId || ''),
enabled: !!eventId,
});

const openCycles = useMemo(
() => eventCycles?.filter((cycle) => cycle.status === 'OPEN'),
[eventCycles],
Expand All @@ -39,83 +52,88 @@ function Event() {
[eventCycles],
);

const handleDataPolicyClick = () => {
navigate(`/data-policy`);
};

// TODO: Create functions to navigate to onboarding slides
const tabNames = ['upcoming', 'past'];
const [activeTab, setActiveTab] = useState<string>('upcoming');

const handleOnboardingClick = () => {
navigate(`/onboarding`);
const tabs = {
upcoming: <Cycles cycles={openCycles} errorMessage="No upcoming events" />,
past: <Cycles cycles={closedCycles} errorMessage="No past events" />,
};

// TODO: flag for showing groups.
const showGroups = true;

return (
<FlexColumn $gap="2rem">
{/* <BackButton /> */}
{!!openCycles?.length && <CycleTable cycles={openCycles} status="open" />}
{!!closedCycles?.length && <CycleTable cycles={closedCycles} status="closed" />}
{event && <EventCard event={event} />}
<Body>
Click to revisit the{' '}
<Link
to="#"
onClick={handleOnboardingClick}
state={{ onboardingStep: 2, previousPath: location.pathname }}
>
event rules
</Link>
,{' '}
<Link
to="#"
onClick={handleOnboardingClick}
state={{ onboardingStep: 0, previousPath: location.pathname }}
>
trust assumptions
</Link>
, and the community’s{' '}
<Link to="#" onClick={handleDataPolicyClick}>
data policy
</Link>
.
</Body>
<Subtitle>Questions</Subtitle>
<Tabs.TabsHeader tabNames={tabNames} onTabChange={setActiveTab} />
<FlexColumn>
<Tabs.TabsManager tabs={tabs} tab={activeTab} fallback={'Tab not found'} />
</FlexColumn>
{showGroups && <Groups groups={groupCategories} />}
<RunningText />
</FlexColumn>
);
}

function CycleTable({ cycles, status }: { cycles: GetCycleResponse[]; status: 'open' | 'closed' }) {
const { eventId } = useParams();
function RunningText() {
const navigate = useNavigate();
const formatDate = (date: string) => {
const eventEndDate = new Date(date);
return eventEndDate.toLocaleDateString();
};
const handleClick = (cycleId: string) => {
navigate(`/events/${eventId}/cycles/${cycleId}`);

const handleDataPolicyClick = () => {
navigate(`/data-policy`);
};

const formattedColumnText = () => {
if (status === 'open') {
return 'Closes on';
} else {
return 'Closed on';
}
const handleOnboardingClick = () => {
navigate(`/onboarding`);
};

return (
<Table
columns={[
`${status.charAt(0).toUpperCase() + status.slice(1)} Agendas`,
formattedColumnText(),
'',
]}
rows={cycles.map((cycle) => [
cycle.forumQuestions?.[0]?.questionTitle,
formatDate(cycle.endAt),
<Button onClick={() => handleClick(cycle.id)}>
{status === 'open' ? 'Vote' : 'Results'}
</Button>,
])}
/>
<Body>
Click to revisit the{' '}
<Link
to="#"
onClick={handleOnboardingClick}
state={{ onboardingStep: 2, previousPath: location.pathname }}
>
event rules
</Link>
,{' '}
<Link
to="#"
onClick={handleOnboardingClick}
state={{ onboardingStep: 0, previousPath: location.pathname }}
>
trust assumptions
</Link>
, and the community’s{' '}
<Link to="#" onClick={handleDataPolicyClick}>
data policy
</Link>
.
</Body>
);
}

function Groups({ groups }: { groups: GetGroupCategoriesResponse | null | undefined }) {
const navigate = useNavigate();

return groups ? (
<>
<Subtitle>Groups</Subtitle>
<FlexRow $wrap>
{groups.map((group) => (
<Button
key={group.id}
onClick={() => navigate(`/secret-groups?groupcategory=${group.name}`)}
>
{group.name}
</Button>
))}
</FlexRow>
</>
) : (
<Body>No groups</Body>
);
}

Expand Down

0 comments on commit 85c263a

Please sign in to comment.