diff --git a/package.json b/package.json index bb190c8b..9debc022 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-refresh": "^0.4.4", "prettier": "^3.1.1", - "typescript": "^5.2.2", + "typescript": "^5.5.2", "vite": "^5.0.0", "vite-plugin-node-polyfills": "^0.17.0" } diff --git a/packages/api/src/fetchEventGroupCategories.ts b/packages/api/src/fetchEventGroupCategories.ts new file mode 100644 index 00000000..5bd3f82e --- /dev/null +++ b/packages/api/src/fetchEventGroupCategories.ts @@ -0,0 +1,29 @@ +import { GetGroupCategoriesResponse } from './types'; + +async function fetchEventGroupCategories( + eventId: string, +): Promise { + try { + const response = await fetch( + `${import.meta.env.VITE_SERVER_URL}/api/events/${eventId}/group-categories`, + { + credentials: 'include', + headers: { + 'Content-Type': 'application/json', + }, + }, + ); + + if (!response.ok) { + throw new Error(`HTTP Error! Status: ${response.status}`); + } + + const groupCategories = (await response.json()) as { data: GetGroupCategoriesResponse }; + return groupCategories.data; + } catch (error) { + console.error('Error fetching cycles:', error); + return null; + } +} + +export default fetchEventGroupCategories; diff --git a/packages/api/src/fetchGroupCategories.ts b/packages/api/src/fetchGroupCategories.ts index 9fad1de5..f9c4d49d 100644 --- a/packages/api/src/fetchGroupCategories.ts +++ b/packages/api/src/fetchGroupCategories.ts @@ -2,7 +2,7 @@ import { GetGroupCategoriesResponse } from './types'; async function fetchGroupCategories(): Promise { try { - const response = await fetch(`${import.meta.env.VITE_SERVER_URL}/api//group-categories`, { + const response = await fetch(`${import.meta.env.VITE_SERVER_URL}/api/group-categories`, { credentials: 'include', headers: { 'Content-type': 'application/json', diff --git a/packages/api/src/fetchGroups.ts b/packages/api/src/fetchGroups.ts index 8ccc94d6..bda24450 100644 --- a/packages/api/src/fetchGroups.ts +++ b/packages/api/src/fetchGroups.ts @@ -1,13 +1,13 @@ import { GetGroupsResponse } from './types'; async function fetchGroups({ - groupCategoryName, + groupCategoryId, }: { - groupCategoryName: string; + groupCategoryId: string; }): Promise { try { const response = await fetch( - `${import.meta.env.VITE_SERVER_URL}/api/group-categories/${groupCategoryName}/groups`, + `${import.meta.env.VITE_SERVER_URL}/api/group-categories/${groupCategoryId}/groups`, { credentials: 'include', headers: { diff --git a/packages/api/src/index.ts b/packages/api/src/index.ts index bfe38a75..5fd17c38 100644 --- a/packages/api/src/index.ts +++ b/packages/api/src/index.ts @@ -36,4 +36,5 @@ export { default as postVotes } from './postVotes'; export { default as putRegistration } from './putRegistration'; export { default as putUser } from './putUser'; export { default as putUsersToGroups } from './putUsersToGroups'; +export { default as fetchEventGroupCategories } from './fetchEventGroupCategories'; export * from './types'; diff --git a/packages/api/src/types/CycleType.ts b/packages/api/src/types/CycleType.ts index b1bdad5d..b95e5612 100644 --- a/packages/api/src/types/CycleType.ts +++ b/packages/api/src/types/CycleType.ts @@ -7,6 +7,7 @@ export type GetCycleResponse = { endAt: string; forumQuestions: { id: string; + showScore: boolean; createdAt: string; updatedAt: string; questionSubTitle: string | null; @@ -20,12 +21,23 @@ export type GetCycleResponse = { optionTitle: string; optionSubTitle?: string; accepted: boolean; + voteScore?: number; fundingRequest: string; - user: { - group: { + user?: { + groups?: { id: string; name: string; - }; + groupCategory?: { + id: string; + name: string | null; + createdAt: Date; + updatedAt: Date; + eventId: string | null; + userCanCreate: boolean; + userCanView: boolean; + required: boolean; + }; + }[]; username: string; firstName: string; lastName: string; diff --git a/packages/api/src/types/GroupCategoryType.ts b/packages/api/src/types/GroupCategoryType.ts index 275e2b90..aa88128f 100644 --- a/packages/api/src/types/GroupCategoryType.ts +++ b/packages/api/src/types/GroupCategoryType.ts @@ -6,6 +6,7 @@ export type GetGroupCategoryResponse = { eventId: string | null; userCanCreate: boolean; userCanView: boolean; + required: boolean; }; export type GetGroupCategoriesResponse = GetGroupCategoryResponse[]; diff --git a/packages/api/src/types/GroupType.ts b/packages/api/src/types/GroupType.ts index 18bb538c..e2964ff5 100644 --- a/packages/api/src/types/GroupType.ts +++ b/packages/api/src/types/GroupType.ts @@ -12,6 +12,7 @@ export type GetGroupsResponse = { eventId: string; userCanCreate: boolean; userCanView: boolean; + required: boolean; createdAt: string; updatedAt: string; }; @@ -27,6 +28,7 @@ export type PostGroupResponse = { groupCategoryId: string | null; name: string; secret: string | null; + required: boolean; description: string; createdAt: string; updatedAt: string; diff --git a/packages/api/src/types/UserType.ts b/packages/api/src/types/UserType.ts index 657353a3..3380a096 100644 --- a/packages/api/src/types/UserType.ts +++ b/packages/api/src/types/UserType.ts @@ -16,5 +16,4 @@ export type PutUserRequest = { lastName: string; email?: string; telegram?: string | null; - userAttributes: Record; }; diff --git a/packages/berlin/public/logos/lexicon-light.svg b/packages/berlin/public/logos/lexicon-light.svg index 53a5bf02..f0109986 100644 --- a/packages/berlin/public/logos/lexicon-light.svg +++ b/packages/berlin/public/logos/lexicon-light.svg @@ -1,19 +1,24 @@ - - - - + + + + + + + + + - + - + - + diff --git a/packages/berlin/src/App.tsx b/packages/berlin/src/App.tsx index 8477dd86..a7a349db 100644 --- a/packages/berlin/src/App.tsx +++ b/packages/berlin/src/App.tsx @@ -1,16 +1,17 @@ // React and third-party libraries -import { RouterProvider, createBrowserRouter, redirect } from 'react-router-dom'; import { QueryClient } from '@tanstack/react-query'; +import { RouterProvider, createBrowserRouter, redirect } from 'react-router-dom'; // Store import { useAppStore } from './store'; // API -import { fetchEvents, fetchUser, fetchCycle, fetchRegistrations } from 'api'; +import { fetchCycle, fetchEvents, fetchRegistrations, fetchUser } from 'api'; // Pages import { default as BerlinLayout } from './layout/index.ts'; import Account from './pages/Account'; +import Comments from './pages/Comments.tsx'; import Cycle from './pages/Cycle.tsx'; import DataPolicy from './pages/DataPolicy.tsx'; import Event from './pages/Event.tsx'; @@ -18,7 +19,6 @@ import Events from './pages/Events.tsx'; import Holding from './pages/Holding'; import Landing from './pages/Landing'; import Onboarding from './pages/Onboarding'; -import Comments from './pages/Comments.tsx'; import PassportPopupRedirect from './pages/Popup'; import PublicGroupRegistration from './pages/PublicGroupRegistration.tsx'; import Register from './pages/Register'; diff --git a/packages/berlin/src/components/columns/cycle-columns/CycleColumns.styled.tsx b/packages/berlin/src/components/columns/cycle-columns/CycleColumns.styled.tsx index eac82e67..9ddf80a7 100644 --- a/packages/berlin/src/components/columns/cycle-columns/CycleColumns.styled.tsx +++ b/packages/berlin/src/components/columns/cycle-columns/CycleColumns.styled.tsx @@ -2,9 +2,13 @@ import styled from 'styled-components'; import { FlexRow } from '../../containers/FlexRow.styled'; export const Card = styled(FlexRow)` - border-bottom: 2px solid var(--color-black); - gap: 0; - width: 100%; + display: none; + @media (min-width: 600px) { + display: flex; + border-bottom: 2px solid var(--color-black); + gap: 0; + width: 100%; + } `; export const Proposal = styled(FlexRow)` @@ -53,7 +57,7 @@ export const Hearts = styled(FlexRow)` padding: 1.5rem; `; -// export const Plurality = styled(FlexRow)` -// max-width: 5.5rem; -// padding: 1.5rem; -// `; +export const Plurality = styled(FlexRow)` + max-width: 5rem; + padding: 1.5rem; +`; diff --git a/packages/berlin/src/components/columns/cycle-columns/CycleColumns.tsx b/packages/berlin/src/components/columns/cycle-columns/CycleColumns.tsx index 8fd8221b..f939be67 100644 --- a/packages/berlin/src/components/columns/cycle-columns/CycleColumns.tsx +++ b/packages/berlin/src/components/columns/cycle-columns/CycleColumns.tsx @@ -1,12 +1,13 @@ import IconButton from '../../icon-button'; import { Body } from '../../typography/Body.styled'; -import { Affiliation, Lead, Card, Hearts, Proposal } from './CycleColumns.styled'; +import { Affiliation, Lead, Card, Hearts, Proposal, Plurality } from './CycleColumns.styled'; type CycleColumnsProps = { onColumnClick: (column: string) => void; + showScore?: boolean; }; -function CycleColumns({ onColumnClick }: CycleColumnsProps) { +function CycleColumns({ onColumnClick, showScore }: CycleColumnsProps) { return ( @@ -25,13 +26,15 @@ function CycleColumns({ onColumnClick }: CycleColumnsProps) { icon={{ src: `/icons/heart-full.svg`, alt: 'Full heart' }} /> - {/* onColumnClick('voteScore')}> - - */} + {showScore && ( + onColumnClick('voteScore')}> + + + )} ); } diff --git a/packages/berlin/src/components/columns/results-columns/ResultsColumns.styled.tsx b/packages/berlin/src/components/columns/results-columns/ResultsColumns.styled.tsx index 331a2142..63314245 100644 --- a/packages/berlin/src/components/columns/results-columns/ResultsColumns.styled.tsx +++ b/packages/berlin/src/components/columns/results-columns/ResultsColumns.styled.tsx @@ -2,8 +2,12 @@ import styled from 'styled-components'; import { Grid } from '../../containers/Grid.styled'; export const Card = styled(Grid)<{ $showFunding: boolean }>` - border-bottom: 2px solid var(--color-black); - grid-template-columns: ${(props) => - props.$showFunding ? 'auto repeat(3, 48px) 100px' : 'auto repeat(3, 48px)'}; - padding: 1.5rem; + display: none; + @media (min-width: 600px) { + border-bottom: 2px solid var(--color-black); + display: grid; + grid-template-columns: ${(props) => + props.$showFunding ? 'auto repeat(3, 48px) 100px' : 'auto repeat(3, 48px)'}; + padding: 1.5rem; + } `; diff --git a/packages/berlin/src/components/dots/Dots.tsx b/packages/berlin/src/components/dots/Dots.tsx index d5bef910..fd3ede01 100644 --- a/packages/berlin/src/components/dots/Dots.tsx +++ b/packages/berlin/src/components/dots/Dots.tsx @@ -4,14 +4,14 @@ import { Dot } from './Dots.styled'; type DotsProps = { dots: number; activeDotIndex: number; - setStep: React.Dispatch>; + handleClick: (index: number) => void; }; -function Dots({ dots, activeDotIndex, setStep }: DotsProps) { +function Dots({ dots, activeDotIndex, handleClick }: DotsProps) { return ( {Array.from({ length: dots }).map((_, index) => ( - setStep(index)} /> + handleClick(index)} /> ))} ); diff --git a/packages/berlin/src/components/event-card/EventCard.styled.tsx b/packages/berlin/src/components/event-card/EventCard.styled.tsx index ec9898cb..a3742b19 100644 --- a/packages/berlin/src/components/event-card/EventCard.styled.tsx +++ b/packages/berlin/src/components/event-card/EventCard.styled.tsx @@ -1,18 +1,12 @@ -import styled, { css } from 'styled-components'; +import styled from 'styled-components'; import { FlexColumn } from '../containers/FlexColumn.styled'; +import { FlexRowToColumn } from '../containers/FlexRowToColumn.styled'; -export const Card = styled(FlexColumn)<{ $direction?: 'row' | 'column' }>` +export const Card = styled(FlexRowToColumn)` border-radius: 1rem; border: 1px solid var(--color-black); - flex-direction: column; overflow: hidden; width: 100%; - - ${(props) => - props.$direction === 'row' && - css` - flex-direction: row; - `} `; export const ImageContainer = styled.div` diff --git a/packages/berlin/src/components/event-card/EventCard.tsx b/packages/berlin/src/components/event-card/EventCard.tsx index cec0a4ec..5c6d1878 100644 --- a/packages/berlin/src/components/event-card/EventCard.tsx +++ b/packages/berlin/src/components/event-card/EventCard.tsx @@ -10,13 +10,12 @@ import Markdown from 'react-markdown'; type EventCardProps = { event: GetEventResponse; - $direction?: 'row' | 'column'; onClick?: () => void; }; -function EventCard({ event, $direction = 'column', onClick }: EventCardProps) { +function EventCard({ event, onClick }: EventCardProps) { return ( - + {`${event.name} diff --git a/packages/berlin/src/components/form/FormInput.tsx b/packages/berlin/src/components/form/FormInput.tsx new file mode 100644 index 00000000..2f5bc69f --- /dev/null +++ b/packages/berlin/src/components/form/FormInput.tsx @@ -0,0 +1,56 @@ +import { FieldValues, Path, UseFormReturn } from 'react-hook-form'; +import { SelectInput } from './SelectInput'; +import { TextAreaInput } from './TextAreaInput'; +import { TextInput } from './TextInput'; +import { NumberInput } from './NumberInput'; + +export function FormInput(props: { + form: UseFormReturn; + name: Path; + label: string; + options?: { name: string; value: string }[]; + required: boolean | null; + type: string; +}) { + switch (props.type) { + case 'TEXT': + return ( + + ); + case 'TEXTAREA': + return ( + + ); + case 'SELECT': + return ( + + ); + case 'NUMBER': + return ( + + ); + default: + return <>; + } +} diff --git a/packages/berlin/src/components/form/NumberInput.tsx b/packages/berlin/src/components/form/NumberInput.tsx new file mode 100644 index 00000000..262524a7 --- /dev/null +++ b/packages/berlin/src/components/form/NumberInput.tsx @@ -0,0 +1,37 @@ +import { Controller, FieldValues, Path, UseFormReturn } from 'react-hook-form'; +import Input from '../input'; + +export function NumberInput(props: { + form: UseFormReturn; + name: Path; + label: string; + required: boolean | null; + customValidation?: (value: number) => string | undefined; +}) { + return ( + ( + + )} + /> + ); +} diff --git a/packages/berlin/src/components/form/SelectInput.tsx b/packages/berlin/src/components/form/SelectInput.tsx new file mode 100644 index 00000000..102beaed --- /dev/null +++ b/packages/berlin/src/components/form/SelectInput.tsx @@ -0,0 +1,34 @@ +import { Controller, FieldValues, Path, UseFormReturn } from 'react-hook-form'; +import Select from '../select'; + +export function SelectInput(props: { + form: UseFormReturn; + name: Path; + label: string; + required: boolean | null; + options: { name: string; value: string }[]; +}) { + return ( + ( +