refactor: split the makers page into sections & functionalities

This commit is contained in:
MTG2000
2022-09-06 11:29:23 +03:00
parent 939832a7ac
commit 345ef79cdd
13 changed files with 503 additions and 161 deletions

View File

@@ -246,7 +246,6 @@ export interface NexusGenObjects {
id: number; // Int!
judges: NexusGenRootTypes['TournamentJudge'][]; // [TournamentJudge!]!
location: string; // String!
makers_count: number; // Int!
prizes: NexusGenRootTypes['TournamentPrize'][]; // [TournamentPrize!]!
projects_count: number; // Int!
start_date: NexusGenScalars['Date']; // Date!
@@ -274,6 +273,11 @@ export interface NexusGenObjects {
jobTitle: string; // String!
name: string; // String!
}
TournamentMakersResponse: { // root type
hasNext?: boolean | null; // Boolean
hasPrev?: boolean | null; // Boolean
makers: NexusGenRootTypes['User'][]; // [User!]!
}
TournamentPrize: { // root type
amount: string; // String!
image: string; // String!
@@ -487,7 +491,7 @@ export interface NexusGenFieldTypes {
getDonationsStats: NexusGenRootTypes['DonationsStats']; // DonationsStats!
getFeed: NexusGenRootTypes['Post'][]; // [Post!]!
getLnurlDetailsForProject: NexusGenRootTypes['LnurlDetails']; // LnurlDetails!
getMakersInTournament: NexusGenRootTypes['User'][]; // [User!]!
getMakersInTournament: NexusGenRootTypes['TournamentMakersResponse']; // TournamentMakersResponse!
getMyDrafts: NexusGenRootTypes['Post'][]; // [Post!]!
getPostById: NexusGenRootTypes['Post']; // Post!
getProject: NexusGenRootTypes['Project']; // Project!
@@ -577,6 +581,11 @@ export interface NexusGenFieldTypes {
jobTitle: string; // String!
name: string; // String!
}
TournamentMakersResponse: { // field return type
hasNext: boolean | null; // Boolean
hasPrev: boolean | null; // Boolean
makers: NexusGenRootTypes['User'][]; // [User!]!
}
TournamentPrize: { // field return type
amount: string; // String!
image: string; // String!
@@ -813,7 +822,7 @@ export interface NexusGenFieldTypeNames {
getDonationsStats: 'DonationsStats'
getFeed: 'Post'
getLnurlDetailsForProject: 'LnurlDetails'
getMakersInTournament: 'User'
getMakersInTournament: 'TournamentMakersResponse'
getMyDrafts: 'Post'
getPostById: 'Post'
getProject: 'Project'
@@ -903,6 +912,11 @@ export interface NexusGenFieldTypeNames {
jobTitle: 'String'
name: 'String'
}
TournamentMakersResponse: { // field return type name
hasNext: 'Boolean'
hasPrev: 'Boolean'
makers: 'User'
}
TournamentPrize: { // field return type name
amount: 'String'
image: 'String'

View File

@@ -252,7 +252,7 @@ type Query {
getDonationsStats: DonationsStats!
getFeed(skip: Int = 0, sortBy: String, tag: Int = 0, take: Int = 10): [Post!]!
getLnurlDetailsForProject(project_id: Int!): LnurlDetails!
getMakersInTournament(roleId: Int, search: String, skip: Int = 0, take: Int = 10, tournamentId: Int!): [User!]!
getMakersInTournament(roleId: Int, search: String, skip: Int = 0, take: Int = 10, tournamentId: Int!): TournamentMakersResponse!
getMyDrafts(type: POST_TYPE!): [Post!]!
getPostById(id: Int!, type: POST_TYPE!): Post!
getProject(id: Int!): Project!
@@ -374,6 +374,12 @@ type TournamentJudge {
name: String!
}
type TournamentMakersResponse {
hasNext: Boolean
hasPrev: Boolean
makers: [User!]!
}
type TournamentPrize {
amount: String!
image: String!

View File

@@ -79,7 +79,11 @@ const Tournament = objectType({
t.nonNull.string('website');
t.nonNull.int('events_count');
t.nonNull.int('makers_count');
t.nonNull.int('makers_count', {
resolve(parent) {
return prisma.user.count();
}
});
t.nonNull.int('projects_count');
t.nonNull.list.nonNull.field('prizes', { type: TournamentPrize, });
@@ -89,6 +93,29 @@ const Tournament = objectType({
}
})
const TournamentMakersResponse = objectType({
name: 'TournamentMakersResponse',
definition(t) {
t.boolean('hasNext');
t.boolean('hasPrev');
t.nonNull.list.nonNull.field('makers', { type: "User" })
}
}
)
const TournamentProjectsResponse = objectType({
name: 'TournamentProjectsResponse',
definition(t) {
t.boolean('hasNext');
t.boolean('hasPrev');
t.nonNull.list.nonNull.field('projects', { type: "Project" })
}
}
)
const getTournamentById = extendType({
type: "Query",
definition(t) {
@@ -104,18 +131,20 @@ const getTournamentById = extendType({
}
})
const getMakersInTournament = extendType({
type: "Query",
definition(t) {
t.nonNull.list.nonNull.field('getMakersInTournament', {
type: "User",
t.nonNull.field('getMakersInTournament', {
type: TournamentMakersResponse,
args: {
tournamentId: nonNull(intArg()),
...paginationArgs({ take: 10 }),
search: stringArg(),
roleId: intArg(),
},
resolve(_, args) {
async resolve(_, args) {
let filters = [];
@@ -147,15 +176,84 @@ const getMakersInTournament = extendType({
})
return prisma.user.findMany({
const makers = await prisma.user.findMany({
...(filters.length > 0 && {
where: {
AND: filters
}
}),
skip: args.skip,
take: args.take,
take: args.take + 1,
});
return {
hasNext: makers.length === args.take + 1,
hasPrev: args.skip !== 0,
makers: makers.slice(0, args.take)
}
}
})
}
})
const getProjectsInTournament = extendType({
type: "Query",
definition(t) {
t.nonNull.field('getProjectsInTournament', {
type: TournamentProjectsResponse,
args: {
tournamentId: nonNull(intArg()),
...paginationArgs({ take: 10 }),
search: stringArg(),
roleId: intArg(),
},
async resolve(_, args) {
let filters = [];
if (args.search) filters.push({
OR: [
{
title: {
contains: args.search,
mode: 'insensitive'
}
},
{
description: {
contains: args.search,
mode: 'insensitive'
}
}
]
})
// if (args.roleId) filters.push({
// roles: {
// some: {
// roleId: args.roleId
// }
// }
// })
const makers = await prisma.project.findMany({
...(filters.length > 0 && {
where: {
AND: filters
}
}),
skip: args.skip,
take: args.take + 1,
});
return {
hasNext: makers.length === args.take + 1,
hasPrev: args.skip !== 0,
makers: makers.slice(0, args.take)
}
}
})
}

View File

@@ -13,10 +13,10 @@ import Avatar from 'src/features/Profiles/Components/Avatar/Avatar';
import Badge from 'src/Components/Badge/Badge';
import { createRoute, PAGES_ROUTES } from 'src/utils/routing';
type MakerType = GetMakersInTournamentQuery['getMakersInTournament'][number]
type MakerType = GetMakersInTournamentQuery['getMakersInTournament']['makers'][number]
interface Props {
maker: GetMakersInTournamentQuery['getMakersInTournament'][number],
maker: MakerType,
isMe?: boolean;
}

View File

@@ -1,126 +1,29 @@
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 { Tournament, useMeTournamentQuery, User } from 'src/graphql'
import MakerCard from './MakerCard/MakerCard';
import MakerCardSkeleton from './MakerCard/MakerCard.Skeleton';
import MakersFilters from './MakersFilters/MakersFilters';
import ParticipantsSection from './ParticipantsSection/ParticipantsSection';
interface Props {
data: Pick<Tournament,
| 'id'>
}
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<GenericMakerRole | null>(null);
const loadingContainerCbRef = useCallback((e: HTMLDivElement) => {
if (e)
e.scrollIntoView({
behavior: 'smooth',
block: "center"
})
}, [])
const [queryFilter, setQueryFilter] = useState<GetMakersInTournamentQueryVariables>({
tournamentId: id,
roleId: roleFilter?.id ?? null,
search: debouncedsearchFilter,
skip: ITEMS_PER_PAGE * page,
take: ITEMS_PER_PAGE,
});
const query = useGetMakersInTournamentQuery({
variables: queryFilter,
notifyOnNetworkStatusChange: true,
});
useEffect(() => {
setPage(0);
setQueryFilter(f => ({ ...f, search: debouncedsearchFilter, roleId: roleFilter?.id ?? null, skip: 0 }))
}, [debouncedsearchFilter, roleFilter]);
if (query.networkStatus === NetworkStatus.loading) return <LoadingPage />
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;
const query = useMeTournamentQuery();
return (
<div className='pb-42'>
<div className="flex flex-col gap-16 lg:gap-24">
{(query.data?.me ?? query.previousData?.me) && <MakerCard isMe maker={(query.data?.me ?? query.previousData?.me) as User} />}
<div className="flex flex-col gap-16">
<h3 className="text-body1 text-gray-900 font-bold mt-24">Makers 👾</h3>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-16 lg:gap-24">
<MakersFilters
searchValue={searchFilter}
onSearchChange={changeSearchFilter}
roleValue={roleFilter}
onRoleChange={setRoleFilter}
/>
</div>
</div>
{isFetchingMore ?
<>
<div ref={loadingContainerCbRef} >
<MakerCardSkeleton />
</div>
<MakerCardSkeleton />
<MakerCardSkeleton />
</>
{query.loading ?
<MakerCardSkeleton />
:
(itemsCount !== 0 ?
query.data?.getMakersInTournament.map(maker => <MakerCard key={maker.id} maker={maker} />) :
<div className="py-80 text-center text-body2">
<p className="text-gray-400">No makers found here...</p>
</div>)
query.data?.me ?
<MakerCard isMe maker={query.data.me as User} />
: null
}
<div className='flex justify-center gap-36 text-gray-400'>
<IconButton isDisabled={!itemsCount || page === 0} onClick={prevPage}>
<FaChevronLeft />
</IconButton>
<IconButton isDisabled={!itemsCount || itemsCount < ITEMS_PER_PAGE} onClick={nextPage} >
<FaChevronRight />
</IconButton>
</div>
<ParticipantsSection tournamentId={id} />
</div>
</div>

View File

@@ -0,0 +1,105 @@
import { useEffect, useRef, useState } from 'react'
import { FaChevronLeft, FaChevronRight } from 'react-icons/fa';
import IconButton from 'src/Components/IconButton/IconButton';
import { GetMakersInTournamentQueryVariables, useGetMakersInTournamentQuery } from 'src/graphql';
import MakerCard from '../MakerCard/MakerCard';
import MakerCardSkeleton from '../MakerCard/MakerCard.Skeleton';
interface Props {
tournamentId: number
searchFilter: string,
roleFilter: number | null
}
const ITEMS_PER_PAGE = 3;
export default function MakersList(props: Props) {
const [page, setPage] = useState(0);
const topContainerRef = useRef<HTMLDivElement>(null)
const [scrollToTop, setScrollToTop] = useState(false)
const [queryFilter, setQueryFilter] = useState<GetMakersInTournamentQueryVariables>({
tournamentId: props.tournamentId,
roleId: props.roleFilter ?? null,
search: props.searchFilter ?? null,
skip: ITEMS_PER_PAGE * page,
take: ITEMS_PER_PAGE,
});
const query = useGetMakersInTournamentQuery({
variables: queryFilter,
});
useEffect(() => {
setPage(0);
setQueryFilter(f => ({ ...f, search: props.searchFilter, roleId: props.roleFilter, skip: 0 }))
}, [props.roleFilter, props.searchFilter]);
useEffect(() => {
if (scrollToTop && topContainerRef.current) {
topContainerRef.current.scrollIntoView({
behavior: 'smooth',
block: "center"
})
setScrollToTop(false)
}
}, [scrollToTop])
const nextPage = () => {
setPage(p => p + 1)
setQueryFilter(f => ({ ...f, skip: (f.skip ?? 0) + ITEMS_PER_PAGE }))
setScrollToTop(true)
}
const prevPage = () => {
if (page === 0) return
setPage(p => p - 1)
setQueryFilter(f => ({ ...f, skip: (f.skip ?? 0) - ITEMS_PER_PAGE }))
setScrollToTop(true)
}
const itemsCount = query.data?.getMakersInTournament && query.data.getMakersInTournament.makers.length;
return (
<div >
<div ref={topContainerRef}></div>
<div className='flex flex-col gap-16 lg:gap-24'>
{
query.loading ?
<>
<div >
<MakerCardSkeleton />
</div>
<MakerCardSkeleton />
<MakerCardSkeleton />
</>
:
(itemsCount !== 0 ?
query.data?.getMakersInTournament.makers.map(maker => <MakerCard key={maker.id} maker={maker} />) :
<div className="py-80 text-center text-body2">
<p className="text-gray-400">No makers found here...</p>
</div>)
}
< div className='flex justify-center gap-36 text-gray-400' >
<IconButton isDisabled={!query.data?.getMakersInTournament.hasPrev} onClick={prevPage}>
<FaChevronLeft />
</IconButton>
<IconButton isDisabled={!query.data?.getMakersInTournament.hasNext} onClick={nextPage} >
<FaChevronRight />
</IconButton>
</div >
</div>
</div>
)
}

View File

@@ -0,0 +1,41 @@
import { useDebouncedState } from '@react-hookz/web';
import { useState } from 'react'
import { GenericMakerRole } from 'src/graphql'
import MakersFilters from '../MakersFilters/MakersFilters';
import MakersList from './MakersList';
interface Props {
tournamentId: number
}
export default function ParticipantsSection({ tournamentId }: Props) {
const [searchFilter, setSearchFilter] = useState("");
const [debouncedsearchFilter, setDebouncedSearchFilter] = useDebouncedState("", 500);
const [roleFilter, setRoleFilter] = useState<GenericMakerRole | null>(null);
const changeSearchFilter = (new_value: string) => {
setSearchFilter(new_value);
setDebouncedSearchFilter(new_value);
}
return (<>
<div className="flex flex-col gap-16">
<h3 className="text-body1 text-gray-900 font-bold mt-24">Makers 👾</h3>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-16 lg:gap-24">
<MakersFilters
searchValue={searchFilter}
onSearchChange={changeSearchFilter}
roleValue={roleFilter}
onRoleChange={setRoleFilter}
/>
</div>
</div>
<MakersList searchFilter={debouncedsearchFilter} roleFilter={roleFilter?.id ?? null} tournamentId={tournamentId} />
</>
)
}

View File

@@ -0,0 +1,40 @@
import Card from 'src/Components/Card/Card';
import Badge from 'src/Components/Badge/Badge';
import Skeleton from 'react-loading-skeleton';
export default function ProjectCardSkeleton() {
return (
<Card>
<div className="flex flex-wrap gap-24 items-start">
<div className="shrink-0 w-64 md:w-80 aspect-square">
<Skeleton borderRadius={16} width={"100%"} height={'100%'} />
</div>
<div className="flex flex-col gap-4 flex-1">
<p className="text-body2 text-gray-900 font-bold"><Skeleton width={"15ch"} /> </p>
<p className="text-body4 text-gray-600 font-medium"><Skeleton width={"8ch"} /> </p>
<p className="text-body5 text-gray-600 font-medium"><Skeleton width={"35ch"} /> </p>
<ul className="hidden md:flex flex-wrap gap-8 mt-4">
{Array(3).fill(0).map((_, idx) => <li key={idx}><Badge size='sm' className='!text-body5'> <span className="opacity-0">Loading role</span> </Badge> </li>)}
</ul>
</div>
</div>
<hr className="hidden md:block bg-gray-200 mt-24"></hr>
<div className="md:hidden mt-24">
<p className="text-body5 text-gray-900 font-medium"><Skeleton width={"7ch"} /></p>
<ul className="flex flex-wrap gap-8 mt-4">
{Array(3).fill(0).map((_, idx) => <li key={idx}><Badge size='sm' className='!text-body5'> <span className="opacity-0">Loading role</span> </Badge> </li>)}
</ul>
</div>
<div className="mt-24">
<p className="text-body5 text-gray-900 font-medium"><Skeleton width={"7ch"} /></p>
<ul className="flex flex-wrap gap-8 mt-12">
{Array(3).fill(0).map((_, idx) => <li key={idx}><Badge size='sm' className='!text-body5'> <span className="opacity-0">Loading role</span> </Badge> </li>)} </ul>
</div>
</Card>
)
}

View File

@@ -0,0 +1,62 @@
import Button from "src/Components/Button/Button"
import { GetMakersInTournamentQuery, } from "src/graphql";
import { useAppDispatch, } from "src/utils/hooks";
import Card from 'src/Components/Card/Card';
import Avatar from 'src/features/Profiles/Components/Avatar/Avatar';
import Badge from 'src/Components/Badge/Badge';
import { createRoute } from 'src/utils/routing';
type MakerType = GetMakersInTournamentQuery['getMakersInTournament']['makers'][number]
interface Props {
maker: MakerType,
isMe?: boolean;
}
export default function ProjectCard({ maker, isMe }: Props) {
return (
<Card>
<div className="flex flex-wrap gap-24 items-start">
<div className="shrink-0 w-64 md:w-80">
<Avatar src={maker.avatar} width={'100%'}></Avatar>
</div>
<div className="flex flex-col gap-4 flex-1 overflow-hidden">
<p className="text-body2 text-gray-900 font-bold overflow-hidden text-ellipsis">{maker.name}</p>
{maker.jobTitle ? <p className="text-body4 text-gray-600 font-medium">{maker.jobTitle}</p>
:
<p className="text-body4 text-gray-400 font-medium">No job title</p>}
{maker.roles.length ? <ul className="hidden md:flex flex-wrap gap-8 mt-4">
{maker.roles.map(role => <li><Badge size='sm' className='!text-body5'>{role.icon} {role.title}</Badge> </li>)}
</ul>
:
<p className="hidden md:block text-body4 text-gray-400">No roles added</p>
}
</div>
{isMe && <span className="ml-auto hidden md:inline-block"><Button color='white' href={createRoute({ type: 'edit-profile' })} size='sm' className='ml-auto'>Edit Profile</Button></span>}
</div>
<hr className="hidden md:block bg-gray-200 mt-24"></hr>
<div className="md:hidden mt-24">
<p className="text-body5 text-gray-900 font-medium mb-12">🌈 Roles</p>
{maker.roles.length ? <ul className="flex flex-wrap gap-8">
{maker.roles.map(role => <li><Badge size='sm' className='!text-body5'>{role.icon} {role.title}</Badge> </li>)}
</ul>
:
<p className="text-body4 text-gray-400">No roles added</p>
}
</div>
<div className="mt-24">
<p className="text-body5 text-gray-900 font-medium mb-12">🛠 Skills</p>
{maker.skills.length ? <ul className="flex flex-wrap gap-8">
{maker.skills.map(skill => <li><Badge size='sm' className='!text-body5'>{skill.title}</Badge> </li>)}
</ul>
:
<p className="text-body4 text-gray-400">No skills added</p>
}
</div>
{isMe && <Button fullWidth color='white' href={createRoute({ type: 'edit-profile' })} size='sm' className='mt-32 md:hidden'>Edit Profile</Button>} </Card>
)
}

View File

@@ -5,14 +5,6 @@ query GetMakersInTournament(
$search: String
$roleId: Int
) {
me {
id
name
avatar
jobTitle
...UserRolesSkills
}
getMakersInTournament(
tournamentId: $tournamentId
take: $take
@@ -20,19 +12,33 @@ query GetMakersInTournament(
search: $search
roleId: $roleId
) {
hasNext
hasPrev
makers {
id
name
avatar
jobTitle
roles {
id
icon
title
}
skills {
id
title
}
}
}
}
query MeTournament {
me {
id
name
avatar
jobTitle
roles {
id
icon
title
}
skills {
id
title
}
...UserRolesSkills
}
}

View File

@@ -330,7 +330,7 @@ export type Query = {
getDonationsStats: DonationsStats;
getFeed: Array<Post>;
getLnurlDetailsForProject: LnurlDetails;
getMakersInTournament: Array<User>;
getMakersInTournament: TournamentMakersResponse;
getMyDrafts: Array<Post>;
getPostById: Post;
getProject: Project;
@@ -555,6 +555,13 @@ export type TournamentJudge = {
name: Scalars['String'];
};
export type TournamentMakersResponse = {
__typename?: 'TournamentMakersResponse';
hasNext: Maybe<Scalars['Boolean']>;
hasPrev: Maybe<Scalars['Boolean']>;
makers: Array<User>;
};
export type TournamentPrize = {
__typename?: 'TournamentPrize';
amount: Scalars['String'];
@@ -809,7 +816,12 @@ export type GetMakersInTournamentQueryVariables = Exact<{
}>;
export type GetMakersInTournamentQuery = { __typename?: 'Query', me: { __typename?: 'MyProfile', id: number, name: string, avatar: string, jobTitle: string | null, skills: Array<{ __typename?: 'MakerSkill', id: number, title: string }>, roles: Array<{ __typename?: 'MakerRole', id: number, title: string, icon: string, level: RoleLevelEnum }> } | null, getMakersInTournament: Array<{ __typename?: 'User', id: number, name: string, avatar: string, jobTitle: string | null, roles: Array<{ __typename?: 'MakerRole', id: number, icon: string, title: string }>, skills: Array<{ __typename?: 'MakerSkill', id: number, title: string }> }> };
export type GetMakersInTournamentQuery = { __typename?: 'Query', getMakersInTournament: { __typename?: 'TournamentMakersResponse', hasNext: boolean | null, hasPrev: boolean | null, makers: Array<{ __typename?: 'User', id: number, name: string, avatar: string, jobTitle: string | null, roles: Array<{ __typename?: 'MakerRole', id: number, icon: string, title: string }>, skills: Array<{ __typename?: 'MakerSkill', id: number, title: string }> }> } };
export type MeTournamentQueryVariables = Exact<{ [key: string]: never; }>;
export type MeTournamentQuery = { __typename?: 'Query', me: { __typename?: 'MyProfile', id: number, name: string, avatar: string, jobTitle: string | null, skills: Array<{ __typename?: 'MakerSkill', id: number, title: string }>, roles: Array<{ __typename?: 'MakerRole', id: number, title: string, icon: string, level: RoleLevelEnum }> } | null };
export type GetAllRolesQueryVariables = Exact<{ [key: string]: never; }>;
@@ -2148,13 +2160,6 @@ export type ProjectDetailsLazyQueryHookResult = ReturnType<typeof useProjectDeta
export type ProjectDetailsQueryResult = Apollo.QueryResult<ProjectDetailsQuery, ProjectDetailsQueryVariables>;
export const GetMakersInTournamentDocument = gql`
query GetMakersInTournament($tournamentId: Int!, $take: Int, $skip: Int, $search: String, $roleId: Int) {
me {
id
name
avatar
jobTitle
...UserRolesSkills
}
getMakersInTournament(
tournamentId: $tournamentId
take: $take
@@ -2162,22 +2167,26 @@ export const GetMakersInTournamentDocument = gql`
search: $search
roleId: $roleId
) {
id
name
avatar
jobTitle
roles {
hasNext
hasPrev
makers {
id
icon
title
}
skills {
id
title
name
avatar
jobTitle
roles {
id
icon
title
}
skills {
id
title
}
}
}
}
${UserRolesSkillsFragmentDoc}`;
`;
/**
* __useGetMakersInTournamentQuery__
@@ -2210,6 +2219,44 @@ export function useGetMakersInTournamentLazyQuery(baseOptions?: Apollo.LazyQuery
export type GetMakersInTournamentQueryHookResult = ReturnType<typeof useGetMakersInTournamentQuery>;
export type GetMakersInTournamentLazyQueryHookResult = ReturnType<typeof useGetMakersInTournamentLazyQuery>;
export type GetMakersInTournamentQueryResult = Apollo.QueryResult<GetMakersInTournamentQuery, GetMakersInTournamentQueryVariables>;
export const MeTournamentDocument = gql`
query MeTournament {
me {
id
name
avatar
jobTitle
...UserRolesSkills
}
}
${UserRolesSkillsFragmentDoc}`;
/**
* __useMeTournamentQuery__
*
* To run a query within a React component, call `useMeTournamentQuery` and pass it any options that fit your needs.
* When your component renders, `useMeTournamentQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = useMeTournamentQuery({
* variables: {
* },
* });
*/
export function useMeTournamentQuery(baseOptions?: Apollo.QueryHookOptions<MeTournamentQuery, MeTournamentQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useQuery<MeTournamentQuery, MeTournamentQueryVariables>(MeTournamentDocument, options);
}
export function useMeTournamentLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<MeTournamentQuery, MeTournamentQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useLazyQuery<MeTournamentQuery, MeTournamentQueryVariables>(MeTournamentDocument, options);
}
export type MeTournamentQueryHookResult = ReturnType<typeof useMeTournamentQuery>;
export type MeTournamentLazyQueryHookResult = ReturnType<typeof useMeTournamentLazyQuery>;
export type MeTournamentQueryResult = Apollo.QueryResult<MeTournamentQuery, MeTournamentQueryVariables>;
export const GetAllRolesDocument = gql`
query GetAllRoles {
getAllMakersRoles {

View File

@@ -36,6 +36,7 @@ import {
GetAllRolesQuery,
GetMakersInTournamentQuery,
GetMakersInTournamentQueryVariables,
MeTournamentQuery,
} from 'src/graphql'
const delay = (ms = 1000) => new Promise((res) => setTimeout(res, ms + Math.random() * 1000))
@@ -286,12 +287,21 @@ export const handlers = [
)
}),
graphql.query<MeTournamentQuery>('MeTournament', async (req, res, ctx) => {
await delay()
return res(
ctx.data({
me: { ...me() }
})
)
}),
graphql.query<GetMakersInTournamentQuery, GetMakersInTournamentQueryVariables>('GetMakersInTournament', async (req, res, ctx) => {
await delay()
return res(
ctx.data({
me: { ...me() },
getMakersInTournament: getMakersInTournament(req.variables)
})
)

View File

@@ -99,10 +99,13 @@ export function getTournamentById(id: number) {
export function getMakersInTournament(vars: GetMakersInTournamentQueryVariables) {
const offsetStart = vars.skip ?? 0;
const offsetEnd = offsetStart + (vars.take ?? 15)
const take = vars.take ?? 15;
const skip = vars.skip ?? 0;
return MOCK_DATA.users.slice(1)
const offsetStart = skip;
const offsetEnd = offsetStart + take;
const allMakers = 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)
@@ -111,5 +114,12 @@ export function getMakersInTournament(vars: GetMakersInTournamentQueryVariables)
if (!vars.roleId) return true;
return u.roles.some(r => r.id === vars.roleId)
})
.slice(offsetStart, offsetEnd) as User[];
.slice(offsetStart, offsetEnd + 1) as User[]
;
return {
hasNext: allMakers.length === take + 1,
hasPrev: skip !== 0,
makers: allMakers.slice(0, take)
};
}