diff --git a/src/Components/IconButton/IconButton.tsx b/src/Components/IconButton/IconButton.tsx index 407052e..7a3ea33 100644 --- a/src/Components/IconButton/IconButton.tsx +++ b/src/Components/IconButton/IconButton.tsx @@ -9,6 +9,7 @@ interface Props { className?: string size?: "sm" | 'md' | 'lg' variant?: 'blank' | 'fill' + isDisabled?: boolean } @@ -32,7 +33,8 @@ const IconButton = React.forwardRef>(({ children, onClick = () => { }, onKeyDown, - variant = 'blank' + variant = 'blank', + isDisabled, }, ref) => { if (href) @@ -57,12 +59,16 @@ const IconButton = React.forwardRef>(({ ref={ref} type='button' className={` + ${className} ${sizeToPadding[size]} ${baseBtnStyles[variant]} - active:scale-95 rounded-full ${className}`} + active:scale-95 rounded-full + ${isDisabled && "opacity-60"} + `} style={{ lineHeight: 0 }} onClick={onClick} onKeyDown={onKeyDown} + disabled={isDisabled} > {children} diff --git a/src/Components/Inputs/Selects/BasicSelectInput/BasicSelectInput.tsx b/src/Components/Inputs/Selects/BasicSelectInput/BasicSelectInput.tsx index 10850cb..00d3d0a 100644 --- a/src/Components/Inputs/Selects/BasicSelectInput/BasicSelectInput.tsx +++ b/src/Components/Inputs/Selects/BasicSelectInput/BasicSelectInput.tsx @@ -122,7 +122,15 @@ export default function BasicSelectInput, IsMulti } function getOptionComponent>(renderOption: Props['renderOption'], labelField: Props['labelField']) { - const _render = renderOption ?? ((option) =>
+ const _render = renderOption ?? ((option) =>
{option.data[labelField]}
) diff --git a/src/features/Projects/pages/ExplorePage/Header/Header.tsx b/src/features/Projects/pages/ExplorePage/Header/Header.tsx index 0c2891c..9f67dec 100644 --- a/src/features/Projects/pages/ExplorePage/Header/Header.tsx +++ b/src/features/Projects/pages/ExplorePage/Header/Header.tsx @@ -7,6 +7,18 @@ import useEmblaCarousel from 'embla-carousel-react' import { useCallback, useEffect, useState } from "react"; const headerLinks = [ + { + title: + <> +

The Long Night tournament is coming!!!

+

1st Oct - 31st Nov, 2022

+ , + img: "https://imagedelivery.net/wyrwp3c-j0gDDUWgnE7lig/1d5d2c86-fe46-4478-6909-bb3c425c0d00/public", + link: { + content: "Register Now", + url: "/tournaments/12", + }, + }, { title:

Explore a fun directory of lightning web apps

, img: Assets.Images_ExploreHeader1, @@ -15,18 +27,6 @@ const headerLinks = [ url: "https://form.jotform.com/220301236112030", }, }, - { - title: - <> -

Take part in BOLT🔩FUN’s Shock the Web 2 ⚡️

-

16th - 19th June, 2022

- , - img: Assets.Images_ExploreHeader2, - link: { - content: "Register Now", - url: "https://bolt.fun/hackathons/shock-the-web-2/", - }, - }, ]; @@ -72,7 +72,7 @@ export default function Header() { {headerLinks[0].title}
- diff --git a/src/features/Tournaments/pages/MakersPage/MakerCard/MakerCard.Skeleton.tsx b/src/features/Tournaments/pages/MakersPage/MakerCard/MakerCard.Skeleton.tsx new file mode 100644 index 0000000..935d929 --- /dev/null +++ b/src/features/Tournaments/pages/MakersPage/MakerCard/MakerCard.Skeleton.tsx @@ -0,0 +1,39 @@ +import Card from 'src/Components/Card/Card'; +import Badge from 'src/Components/Badge/Badge'; +import Skeleton from 'react-loading-skeleton'; + + +export default function MakerCardSkeleton() { + + + return ( + +
+
+ +
+
+

+

+
    + {Array(3).fill(0).map((_, idx) =>
  • Loading role
  • )} +
+
+
+
+ +
+

+
    + {Array(3).fill(0).map((_, idx) =>
  • Loading role
  • )} +
+
+ +
+

+
    + {Array(3).fill(0).map((_, idx) =>
  • Loading role
  • )}
+
+
+ ) +} diff --git a/src/features/Tournaments/pages/MakersPage/MakerCard/MakerCard.tsx b/src/features/Tournaments/pages/MakersPage/MakerCard/MakerCard.tsx index 78c40c3..1f21365 100644 --- a/src/features/Tournaments/pages/MakersPage/MakerCard/MakerCard.tsx +++ b/src/features/Tournaments/pages/MakersPage/MakerCard/MakerCard.tsx @@ -11,7 +11,7 @@ import { openModal } from "src/redux/features/modals.slice"; import Card from 'src/Components/Card/Card'; import Avatar from 'src/features/Profiles/Components/Avatar/Avatar'; import Badge from 'src/Components/Badge/Badge'; -import { PAGES_ROUTES } from 'src/utils/routing'; +import { createRoute, PAGES_ROUTES } from 'src/utils/routing'; type MakerType = GetMakersInTournamentQuery['getMakersInTournament'][number] @@ -20,7 +20,7 @@ interface Props { isMe?: boolean; } -export default function MakerCard({ maker }: Props) { +export default function MakerCard({ maker, isMe }: Props) { const dispatch = useAppDispatch() @@ -35,27 +35,26 @@ export default function MakerCard({ maker }: Props) {

{maker.name}

{maker.jobTitle}

    - {maker.roles.map(role =>
  • {role.icon} {role.title}
  • )} + {maker.roles.map(role =>
  • {role.icon} {role.title}
  • )}
- + {isMe && }

🌈 Roles

-
    - {maker.roles.map(role =>
  • {role.icon}
  • )} +
      + {maker.roles.map(role =>
    • {role.icon} {role.title}
    • )}

🛠️ Skills

    - {maker.skills.map(skill =>
  • {skill.title}
  • )} + {maker.skills.map(skill =>
  • {skill.title}
  • )}
- - + {isMe && } ) } diff --git a/src/features/Tournaments/pages/MakersPage/MakersFilters/MakersFilters.tsx b/src/features/Tournaments/pages/MakersPage/MakersFilters/MakersFilters.tsx index fc43406..ff53b3b 100644 --- a/src/features/Tournaments/pages/MakersPage/MakersFilters/MakersFilters.tsx +++ b/src/features/Tournaments/pages/MakersPage/MakersFilters/MakersFilters.tsx @@ -39,7 +39,15 @@ export default function MakersFilters(props: Props) { value={props.roleValue} onChange={props.onRoleChange} options={options ?? []} - renderOption={option =>
+ renderOption={option =>
{option.data.icon} {option.data.title}
} diff --git a/src/features/Tournaments/pages/MakersPage/MakersPage.tsx b/src/features/Tournaments/pages/MakersPage/MakersPage.tsx index 24dccf3..3aa1a5b 100644 --- a/src/features/Tournaments/pages/MakersPage/MakersPage.tsx +++ b/src/features/Tournaments/pages/MakersPage/MakersPage.tsx @@ -1,56 +1,128 @@ -import React, { useState } from 'react' -import { GenericMakerRole, Tournament, TournamentEventTypeEnum, useGetMakersInTournamentQuery, User } from 'src/graphql' +import { NetworkStatus } from '@apollo/client'; +import { useDebouncedCallback, useDebouncedState } from '@react-hookz/web'; +import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react' +import { FaChevronLeft, FaChevronRight } from 'react-icons/fa'; +import IconButton from 'src/Components/IconButton/IconButton'; +import LoadingPage from 'src/Components/LoadingPage/LoadingPage'; +import { GenericMakerRole, GetMakersInTournamentQueryVariables, Tournament, useGetMakersInTournamentQuery, User } from 'src/graphql' +import ScrollToTop from 'src/utils/routing/scrollToTop'; import MakerCard from './MakerCard/MakerCard'; -import EventCard from './MakerCard/MakerCard'; +import MakerCardSkeleton from './MakerCard/MakerCard.Skeleton'; import MakersFilters from './MakersFilters/MakersFilters'; -import EventsFilters from './MakersFilters/MakersFilters'; interface Props { data: Pick } +const ITEMS_PER_PAGE = 15; + export default function MakersPage({ data: { id } }: Props) { + const [page, setPage] = useState(0) + const [searchFilter, setSearchFilter] = useState(""); + const [debouncedsearchFilter, setDebouncedSearchFilter] = useDebouncedState("", 500); + const [roleFilter, setRoleFilter] = useState(null); + + const loadingContainerCbRef = useCallback((e: HTMLDivElement) => { + if (e) + e.scrollIntoView({ + behavior: 'smooth', + block: "center" + }) + }, []) + + const [queryFilter, setQueryFilter] = useState({ + tournamentId: id, + roleId: roleFilter?.id ?? null, + search: debouncedsearchFilter, + skip: ITEMS_PER_PAGE * page, + take: ITEMS_PER_PAGE, + }); + + const query = useGetMakersInTournamentQuery({ - variables: { - tournamentId: id, - roleId: null, - search: null, - skip: null, - take: null, - }, - }) + variables: queryFilter, + notifyOnNetworkStatusChange: true, + }); - const [searchFilter, setSearchFilter] = useState("") - const [roleFilter, setRoleFilter] = useState(null) + useEffect(() => { + setPage(0); + setQueryFilter(f => ({ ...f, search: debouncedsearchFilter, roleId: roleFilter?.id ?? null, skip: 0 })) + }, [debouncedsearchFilter, roleFilter]); + + + + + + if (query.networkStatus === NetworkStatus.loading) return + + + const changeSearchFilter = (new_value: string) => { + setSearchFilter(new_value); + setDebouncedSearchFilter(new_value); + } + + + const nextPage = () => { + setPage(p => p + 1) + setQueryFilter(f => ({ ...f, skip: (f.skip ?? 0) + ITEMS_PER_PAGE })) + } + const prevPage = () => { + if (page === 0) return + setPage(p => p - 1) + setQueryFilter(f => ({ ...f, skip: (f.skip ?? 0) - ITEMS_PER_PAGE })) + } + + + const isFetchingMore = query.networkStatus === NetworkStatus.setVariables; + const itemsCount = query.data?.getMakersInTournament && query.data.getMakersInTournament.length; - if (query.loading) return <> return (
-
-
- - {/* { - events - .filter(event => { - if (!searchFilter) return true; - return event.title.search(new RegExp(searchFilter, 'i')) !== -1 || event.description.search(new RegExp(searchFilter, 'i')) !== -1 - }) - .filter(event => { - if (!eventFilter) return true; - return event.type === eventFilter; - }) - .map(event => ) - } */} +
+ +
+

Makers 👾

+ +
+ +
+
+ {isFetchingMore ? + <> +
+ +
+ + + + : + (itemsCount !== 0 ? + query.data?.getMakersInTournament.map(maker => ) : +
+

No makers found here...

+
) + } + + +
+ + + + + + +
+
) } diff --git a/src/features/Tournaments/pages/TournamentDetailsPage/data/events.ts b/src/features/Tournaments/pages/TournamentDetailsPage/data/events.ts index 58cdc6c..5156e37 100644 --- a/src/features/Tournaments/pages/TournamentDetailsPage/data/events.ts +++ b/src/features/Tournaments/pages/TournamentDetailsPage/data/events.ts @@ -68,7 +68,7 @@ export const events: Tournament['events'] = [ image: getCoverImage(), links: [], location: "Online", - type: TournamentEventTypeEnum.Workshop, + type: TournamentEventTypeEnum.OnlineMeetup, website: "https://event.name" }, ] \ No newline at end of file diff --git a/src/mocks/data/users.ts b/src/mocks/data/users.ts index 4f75248..5ac031c 100644 --- a/src/mocks/data/users.ts +++ b/src/mocks/data/users.ts @@ -141,7 +141,7 @@ const tournaments = [ }, ] as Tournament[]; -export const users: (User | MyProfile)[] = [{ +export const users: (User & MyProfile)[] = [{ id: 123, email: "mtg0987654321@gmail.com", avatar: "https://avatars.dicebear.com/api/bottts/Mtgmtg.svg", diff --git a/src/mocks/handlers.ts b/src/mocks/handlers.ts index 947345f..06630e1 100644 --- a/src/mocks/handlers.ts +++ b/src/mocks/handlers.ts @@ -1,6 +1,6 @@ import { graphql } from 'msw' -import { allCategories, getAllHackathons, getAllMakersRoles, getAllMakersSkills, getCategory, getFeed, getMyDrafts, getPostById, getProject, getTournamentById, getTrendingPosts, hottestProjects, me, newProjects, popularTags, profile, projectsByCategory, searchProjects } from './resolvers' +import { allCategories, getAllHackathons, getAllMakersRoles, getAllMakersSkills, getCategory, getFeed, getMakersInTournament, getMyDrafts, getPostById, getProject, getTournamentById, getTrendingPosts, hottestProjects, me, newProjects, popularTags, profile, projectsByCategory, searchProjects } from './resolvers' import { NavCategoriesQuery, ExploreProjectsQuery, @@ -35,6 +35,7 @@ import { MyProfileRolesSkillsQuery, GetAllRolesQuery, GetMakersInTournamentQuery, + GetMakersInTournamentQueryVariables, } from 'src/graphql' const delay = (ms = 1000) => new Promise((res) => setTimeout(res, ms + Math.random() * 1000)) @@ -285,13 +286,13 @@ export const handlers = [ ) }), - graphql.query('GetMakersInTournament', async (req, res, ctx) => { + graphql.query('GetMakersInTournament', async (req, res, ctx) => { await delay() return res( ctx.data({ me: { ...me() }, - getMakersInTournament: [] + getMakersInTournament: getMakersInTournament(req.variables) }) ) }), diff --git a/src/mocks/resolvers.ts b/src/mocks/resolvers.ts index 93660b8..b5ffa36 100644 --- a/src/mocks/resolvers.ts +++ b/src/mocks/resolvers.ts @@ -1,5 +1,5 @@ import { MOCK_DATA } from "./data"; -import { MyProfile, Query, QueryGetFeedArgs, QueryGetPostByIdArgs, User } from 'src/graphql' +import { GetMakersInTournamentQueryVariables, MyProfile, Query, QueryGetFeedArgs, QueryGetPostByIdArgs, User } from 'src/graphql' import { Chance } from "chance"; import { tags } from "./data/tags"; import { hackathons } from "./data/hackathon"; @@ -78,8 +78,6 @@ export function me() { } as MyProfile } - - export function profile() { return { ...MOCK_DATA['user'], __typename: 'User' } as User } @@ -97,4 +95,21 @@ export function getMyDrafts(): Query['getMyDrafts'] { export function getTournamentById(id: number) { return MOCK_DATA['tournaments'][0] -} \ No newline at end of file +} + +export function getMakersInTournament(vars: GetMakersInTournamentQueryVariables) { + + const offsetStart = vars.skip ?? 0; + const offsetEnd = offsetStart + (vars.take ?? 15) + + return MOCK_DATA.users.slice(1) + .filter(u => { + if (!vars.search) return true; + return [u.name, u.jobTitle].some(attr => attr?.search(new RegExp(vars.search!, 'i')) !== -1) + }) + .filter(u => { + if (!vars.roleId) return true; + return u.roles.some(r => r.id === vars.roleId) + }) + .slice(offsetStart, offsetEnd) as User[]; +} \ No newline at end of file diff --git a/src/utils/routing/routes.ts b/src/utils/routing/routes.ts index 29613d1..500aabc 100644 --- a/src/utils/routing/routes.ts +++ b/src/utils/routing/routes.ts @@ -31,6 +31,9 @@ type RouteOptions = id: string | number, username?: string, } + | { + type: "edit-profile", + } export function createRoute(options: RouteOptions) { @@ -57,6 +60,9 @@ export function createRoute(options: RouteOptions) { return `/profile/${options.id}` + (options.username ? `/${toSlug(options.username)}` : ""); + if (options.type === 'edit-profile') + return '/edit-profile' + return "" }