From a0f09aaa33033632ae9b7f6077ca03d158bbd26a Mon Sep 17 00:00:00 2001 From: MTG2000 Date: Thu, 8 Sep 2022 14:53:08 +0300 Subject: [PATCH] feat: wired the registeration journey with the api, success modal, reactive data --- api/functions/graphql/nexus-typegen.ts | 32 ++++ api/functions/graphql/schema.graphql | 14 ++ api/functions/graphql/types/tournament.js | 24 ++- api/functions/graphql/types/users.js | 20 +- src/Components/InfoCard/InfoCard.tsx | 4 +- src/Components/Modals/Modal/Modal.tsx | 8 +- .../ModalsContainer/ModalsContainer.tsx | 3 +- .../Auth/pages/LoginPage/LoginPage.tsx | 2 +- .../LinkedAccountsCard/LinkedAccountsCard.tsx | 2 +- .../UpdateSkillsCard/UpdateSkillsCard.tsx | 2 +- .../TournamentsCard/TournamentsCard.tsx | 38 +++- .../ConnectToMakerModal.tsx | 6 - .../pages/MakersPage/MakersPage.tsx | 6 +- .../pages/MakersPage/tournamentMakers.graphql | 10 - .../pages/OverviewPage/OverviewPage.tsx | 5 +- .../RegisterCard/RegisterCard.tsx | 41 +++- .../ConfirmAccount/ConfirmAccount.tsx | 68 +++++++ .../ConfirmAccount/index.ts | 3 + .../LoginModal/LoginModal.tsx | 173 +++++++++++++++++ .../RegisterationModals/LoginModal/index.ts | 3 + .../RegistrationDetails.tsx | 181 ++++++++++++++++++ .../RegistrationDetails/index.ts | 3 + .../registerInTournament.graphql | 9 + .../RegistrationSuccess.tsx | 72 +++++++ .../RegistrationSuccess/index.ts | 3 + .../RegisterationModals/index.tsx | 11 ++ .../Navigation/Navigation.tsx | 2 +- .../TournamentDetailsPage.tsx | 34 ++-- .../meTournament.graphql | 12 ++ .../tournamentDetails.graphql | 11 ++ src/graphql/index.tsx | 180 ++++++++++++----- src/mocks/data/users.ts | 4 + src/mocks/handlers.ts | 3 +- src/redux/features/modals.slice.ts | 5 + src/styles/tw.scss | 2 +- 35 files changed, 878 insertions(+), 118 deletions(-) create mode 100644 src/features/Tournaments/pages/OverviewPage/RegisterationModals/ConfirmAccount/ConfirmAccount.tsx create mode 100644 src/features/Tournaments/pages/OverviewPage/RegisterationModals/ConfirmAccount/index.ts create mode 100644 src/features/Tournaments/pages/OverviewPage/RegisterationModals/LoginModal/LoginModal.tsx create mode 100644 src/features/Tournaments/pages/OverviewPage/RegisterationModals/LoginModal/index.ts create mode 100644 src/features/Tournaments/pages/OverviewPage/RegisterationModals/RegistrationDetails/RegistrationDetails.tsx create mode 100644 src/features/Tournaments/pages/OverviewPage/RegisterationModals/RegistrationDetails/index.ts create mode 100644 src/features/Tournaments/pages/OverviewPage/RegisterationModals/RegistrationDetails/registerInTournament.graphql create mode 100644 src/features/Tournaments/pages/OverviewPage/RegisterationModals/RegistrationSuccess/RegistrationSuccess.tsx create mode 100644 src/features/Tournaments/pages/OverviewPage/RegisterationModals/RegistrationSuccess/index.ts create mode 100644 src/features/Tournaments/pages/OverviewPage/RegisterationModals/index.tsx create mode 100644 src/features/Tournaments/pages/TournamentDetailsPage/meTournament.graphql diff --git a/api/functions/graphql/nexus-typegen.ts b/api/functions/graphql/nexus-typegen.ts index ad69a48..28338b2 100644 --- a/api/functions/graphql/nexus-typegen.ts +++ b/api/functions/graphql/nexus-typegen.ts @@ -52,6 +52,10 @@ export interface NexusGenInputs { roles: NexusGenInputs['MakerRoleInput'][]; // [MakerRoleInput!]! skills: NexusGenInputs['MakerSkillInput'][]; // [MakerSkillInput!]! } + RegisterInTournamentInput: { // input type + email: string; // String! + hacking_status: NexusGenEnums['TournamentMakerHackingStatusEnum']; // TournamentMakerHackingStatusEnum! + } StoryInputType: { // input type body: string; // String! cover_image?: string | null; // String @@ -70,6 +74,7 @@ export interface NexusGenEnums { POST_TYPE: "Bounty" | "Question" | "Story" RoleLevelEnum: 3 | 0 | 1 | 2 | 4 TournamentEventTypeEnum: 2 | 3 | 0 | 1 + TournamentMakerHackingStatusEnum: 1 | 0 VOTE_ITEM_TYPE: "Bounty" | "PostComment" | "Project" | "Question" | "Story" | "User" } @@ -428,6 +433,7 @@ export interface NexusGenFieldTypes { createStory: NexusGenRootTypes['Story'] | null; // Story deleteStory: NexusGenRootTypes['Story'] | null; // Story donate: NexusGenRootTypes['Donation']; // Donation! + registerInTournament: NexusGenRootTypes['User'] | null; // User updateProfileDetails: NexusGenRootTypes['MyProfile'] | null; // MyProfile updateProfileRoles: NexusGenRootTypes['MyProfile'] | null; // MyProfile updateUserPreferences: NexusGenRootTypes['MyProfile']; // MyProfile! @@ -439,6 +445,7 @@ export interface NexusGenFieldTypes { email: string | null; // String github: string | null; // String id: number; // Int! + in_tournament: boolean; // Boolean! jobTitle: string | null; // String join_date: NexusGenScalars['Date']; // Date! lightning_address: string | null; // String @@ -604,6 +611,7 @@ export interface NexusGenFieldTypes { email: string | null; // String github: string | null; // String id: number; // Int! + in_tournament: boolean; // Boolean! jobTitle: string | null; // String join_date: NexusGenScalars['Date']; // Date! lightning_address: string | null; // String @@ -639,6 +647,7 @@ export interface NexusGenFieldTypes { email: string | null; // String github: string | null; // String id: number; // Int! + in_tournament: boolean; // Boolean! jobTitle: string | null; // String join_date: NexusGenScalars['Date']; // Date! lightning_address: string | null; // String @@ -767,6 +776,7 @@ export interface NexusGenFieldTypeNames { createStory: 'Story' deleteStory: 'Story' donate: 'Donation' + registerInTournament: 'User' updateProfileDetails: 'MyProfile' updateProfileRoles: 'MyProfile' updateUserPreferences: 'MyProfile' @@ -778,6 +788,7 @@ export interface NexusGenFieldTypeNames { email: 'String' github: 'String' id: 'Int' + in_tournament: 'Boolean' jobTitle: 'String' join_date: 'Date' lightning_address: 'String' @@ -943,6 +954,7 @@ export interface NexusGenFieldTypeNames { email: 'String' github: 'String' id: 'Int' + in_tournament: 'Boolean' jobTitle: 'String' join_date: 'Date' lightning_address: 'String' @@ -978,6 +990,7 @@ export interface NexusGenFieldTypeNames { email: 'String' github: 'String' id: 'Int' + in_tournament: 'Boolean' jobTitle: 'String' join_date: 'Date' lightning_address: 'String' @@ -1024,6 +1037,10 @@ export interface NexusGenArgTypes { donate: { // args amount_in_sat: number; // Int! } + registerInTournament: { // args + data?: NexusGenInputs['RegisterInTournamentInput'] | null; // RegisterInTournamentInput + tournament_id: number; // Int! + } updateProfileDetails: { // args data?: NexusGenInputs['ProfileDetailsInput'] | null; // ProfileDetailsInput } @@ -1039,6 +1056,11 @@ export interface NexusGenArgTypes { item_type: NexusGenEnums['VOTE_ITEM_TYPE']; // VOTE_ITEM_TYPE! } } + MyProfile: { + in_tournament: { // args + id: number; // Int! + } + } Query: { allProjects: { // args skip?: number | null; // Int @@ -1112,6 +1134,16 @@ export interface NexusGenArgTypes { id: number; // Int! } } + User: { + in_tournament: { // args + id: number; // Int! + } + } + BaseUser: { + in_tournament: { // args + id: number; // Int! + } + } } export interface NexusGenAbstractTypeMembers { diff --git a/api/functions/graphql/schema.graphql b/api/functions/graphql/schema.graphql index ccce643..56b9e0a 100644 --- a/api/functions/graphql/schema.graphql +++ b/api/functions/graphql/schema.graphql @@ -24,6 +24,7 @@ interface BaseUser { email: String github: String id: Int! + in_tournament(id: Int!): Boolean! jobTitle: String join_date: Date! lightning_address: String @@ -148,6 +149,7 @@ type Mutation { createStory(data: StoryInputType): Story deleteStory(id: Int!): Story donate(amount_in_sat: Int!): Donation! + registerInTournament(data: RegisterInTournamentInput, tournament_id: Int!): User updateProfileDetails(data: ProfileDetailsInput): MyProfile updateProfileRoles(data: ProfileRolesInput): MyProfile updateUserPreferences(userKeys: [UserKeyInputType!]): MyProfile! @@ -160,6 +162,7 @@ type MyProfile implements BaseUser { email: String github: String id: Int! + in_tournament(id: Int!): Boolean! jobTitle: String join_date: Date! lightning_address: String @@ -285,6 +288,11 @@ type Question implements PostBase { votes_count: Int! } +input RegisterInTournamentInput { + email: String! + hacking_status: TournamentMakerHackingStatusEnum! +} + enum RoleLevelEnum { Advanced Beginner @@ -377,6 +385,11 @@ type TournamentJudge { name: String! } +enum TournamentMakerHackingStatusEnum { + OpenToConnect + Solo +} + type TournamentMakersResponse { hasNext: Boolean hasPrev: Boolean @@ -401,6 +414,7 @@ type User implements BaseUser { email: String github: String id: Int! + in_tournament(id: Int!): Boolean! jobTitle: String join_date: Date! lightning_address: String diff --git a/api/functions/graphql/types/tournament.js b/api/functions/graphql/types/tournament.js index cfb8d8c..2eb4572 100644 --- a/api/functions/graphql/types/tournament.js +++ b/api/functions/graphql/types/tournament.js @@ -345,9 +345,12 @@ const registerInTournament = extendType({ type: 'Mutation', definition(t) { t.field('registerInTournament', { - type: 'boolean', - args: { data: RegisterInTournamentInput }, - async resolve(_root, { email, hacking_status }, ctx) { + type: 'User', + args: { + data: RegisterInTournamentInput, + tournament_id: nonNull(intArg()) + }, + async resolve(_root, { tournament_id, data: { email, hacking_status } }, ctx) { const user = await getUserByPubKey(ctx.userPubKey); // Do some validation @@ -359,12 +362,17 @@ const registerInTournament = extendType({ // .... // .... - prisma.tournamentParticipant.create({ - data:{ - + return (await prisma.tournamentParticipant.create({ + data: { + tournament_id, + user_id: user.id, + email, + hacking_status + }, + include: { + user: true } - }) - + })).user; } }) }, diff --git a/api/functions/graphql/types/users.js b/api/functions/graphql/types/users.js index 3864637..f7c3d13 100644 --- a/api/functions/graphql/types/users.js +++ b/api/functions/graphql/types/users.js @@ -54,8 +54,15 @@ const BaseUser = interfaceType({ }) t.nonNull.list.nonNull.field('tournaments', { type: Tournament, - resolve: (parent) => { - return [] + resolve: async (parent) => { + return prisma.tournamentParticipant.findMany({ + where: { + user_id: parent.id + }, + include: { + tournament: true + } + }).then(d => d.map(item => item.tournament)) } }) t.nonNull.list.nonNull.field('similar_makers', { @@ -82,6 +89,15 @@ const BaseUser = interfaceType({ } }); + t.nonNull.boolean('in_tournament', { + args: { + id: nonNull(intArg()) + }, + resolve(parent, args) { + return prisma.tournamentParticipant.findFirst({ where: { tournament_id: args.id, user_id: parent.id } }).then(res => !!res) + } + }) + }, resolveType() { diff --git a/src/Components/InfoCard/InfoCard.tsx b/src/Components/InfoCard/InfoCard.tsx index 6e41f47..c14e977 100644 --- a/src/Components/InfoCard/InfoCard.tsx +++ b/src/Components/InfoCard/InfoCard.tsx @@ -1,12 +1,12 @@ import React, { PropsWithChildren } from 'react' interface Props { - + className?: string } export default function InfoCard(props: PropsWithChildren) { return ( -
+

{props.children}

diff --git a/src/Components/Modals/Modal/Modal.tsx b/src/Components/Modals/Modal/Modal.tsx index 66fe3d3..dc5a5e8 100644 --- a/src/Components/Modals/Modal/Modal.tsx +++ b/src/Components/Modals/Modal/Modal.tsx @@ -17,7 +17,11 @@ ReactModal.setAppElement('#root'); export default function Modal({ onClose, children, ...props }: Props) { - const dispatch = useAppDispatch() + const dispatch = useAppDispatch(); + + const onAfterClose = () => { + dispatch(removeClosedModal(props.id)) + } return dispatch(removeClosedModal(props.id))} + onAfterClose={onAfterClose} contentElement={(_props, children) =>
{openModals.map((modal, idx) => { const Child = ALL_MODALS[modal.Modal]; - return ( { return data; } -const useLnurlQuery = () => { +export const useLnurlQuery = () => { const [loading, setLoading] = useState(true) const [error, setError] = useState(null); const [data, setData] = useState<{ lnurl: string, session_token: string }>({ lnurl: '', session_token: '' }) diff --git a/src/features/Profiles/pages/EditProfilePage/PreferencesTab/LinkedAccountsCard/LinkedAccountsCard.tsx b/src/features/Profiles/pages/EditProfilePage/PreferencesTab/LinkedAccountsCard/LinkedAccountsCard.tsx index 34da685..04d94aa 100644 --- a/src/features/Profiles/pages/EditProfilePage/PreferencesTab/LinkedAccountsCard/LinkedAccountsCard.tsx +++ b/src/features/Profiles/pages/EditProfilePage/PreferencesTab/LinkedAccountsCard/LinkedAccountsCard.tsx @@ -64,7 +64,7 @@ export default function LinkedAccountsCard({ value, onChange }: Props) { } - + 💡 Note: if you link a wallet that was used to create another account previously, you won't be able to login to that account until you remove it from here. diff --git a/src/features/Profiles/pages/EditProfilePage/RolesSkillsTab/UpdateSkillsCard/UpdateSkillsCard.tsx b/src/features/Profiles/pages/EditProfilePage/RolesSkillsTab/UpdateSkillsCard/UpdateSkillsCard.tsx index 07c1a01..0f98065 100644 --- a/src/features/Profiles/pages/EditProfilePage/RolesSkillsTab/UpdateSkillsCard/UpdateSkillsCard.tsx +++ b/src/features/Profiles/pages/EditProfilePage/RolesSkillsTab/UpdateSkillsCard/UpdateSkillsCard.tsx @@ -46,7 +46,7 @@ export default function UpdateSkillsCard(props: Props) { )} } - + ℹ️ Can't find a specific skill? You can suggest it to be added here diff --git a/src/features/Profiles/pages/ProfilePage/TournamentsCard/TournamentsCard.tsx b/src/features/Profiles/pages/ProfilePage/TournamentsCard/TournamentsCard.tsx index 1bf1cfc..13f7287 100644 --- a/src/features/Profiles/pages/ProfilePage/TournamentsCard/TournamentsCard.tsx +++ b/src/features/Profiles/pages/ProfilePage/TournamentsCard/TournamentsCard.tsx @@ -1,5 +1,6 @@ import Card from 'src/Components/Card/Card' import { User } from 'src/graphql'; +import { Link } from 'react-router-dom' @@ -26,15 +27,22 @@ export default function TournamentsCard({ tournaments, isOwner }: Props) {
    { tournaments.map((tournament) => { - - const isLive = ((new Date() < new Date(tournament.end_date)) && (new Date() > new Date(tournament.start_date))); - - return
  • - -
    -

    {tournament.title}

    -

    • {isLive ? "Live" : "Completed"}

    -
    + const status = getDateStatus(tournament.start_date, tournament.end_date) + return
  • + + +
    +

    {tournament.title}

    +

    • {status === 'live' && "Running"} + {status === 'upcoming' && "Upcoming"} + {status === 'finished' && "Completed"}

    +
    +
  • })}
@@ -42,3 +50,15 @@ export default function TournamentsCard({ tournaments, isOwner }: Props) { ) } + + +function getDateStatus(start: string, end: string) { + + const start_date = new Date(start); + const now_date = new Date(); + const end_date = new Date(end); + + if (now_date < start_date) return 'upcoming' + if (now_date >= start_date && now_date <= end_date) return 'live' + return 'finished' +} \ No newline at end of file diff --git a/src/features/Tournaments/pages/MakersPage/ConnectToMakerModal/ConnectToMakerModal.tsx b/src/features/Tournaments/pages/MakersPage/ConnectToMakerModal/ConnectToMakerModal.tsx index 0af3a40..dce9916 100644 --- a/src/features/Tournaments/pages/MakersPage/ConnectToMakerModal/ConnectToMakerModal.tsx +++ b/src/features/Tournaments/pages/MakersPage/ConnectToMakerModal/ConnectToMakerModal.tsx @@ -15,12 +15,6 @@ export default function LinkingAccountModal({ onClose, direction, maker, ...prop const links = [ - { - hasValue: maker.email, - text: maker.email, - icon: FiMail, - url: maker.email && `mailto:${maker.email}` - }, { hasValue: maker.twitter, text: maker.twitter, diff --git a/src/features/Tournaments/pages/MakersPage/MakersPage.tsx b/src/features/Tournaments/pages/MakersPage/MakersPage.tsx index 69b8fad..4732a8c 100644 --- a/src/features/Tournaments/pages/MakersPage/MakersPage.tsx +++ b/src/features/Tournaments/pages/MakersPage/MakersPage.tsx @@ -11,7 +11,9 @@ interface Props { export default function MakersPage({ data: { id } }: Props) { - const query = useMeTournamentQuery(); + const query = useMeTournamentQuery({ + variables: { inTournamentId: id } + }); return (
@@ -19,7 +21,7 @@ export default function MakersPage({ data: { id } }: Props) { {query.loading ? : - query.data?.me ? + query.data?.me?.in_tournament ? : null } diff --git a/src/features/Tournaments/pages/MakersPage/tournamentMakers.graphql b/src/features/Tournaments/pages/MakersPage/tournamentMakers.graphql index f1ebe98..949f80d 100644 --- a/src/features/Tournaments/pages/MakersPage/tournamentMakers.graphql +++ b/src/features/Tournaments/pages/MakersPage/tournamentMakers.graphql @@ -1,13 +1,3 @@ -query MeTournament { - me { - id - name - avatar - jobTitle - ...UserRolesSkills - } -} - query GetAllRoles { getAllMakersRoles { id diff --git a/src/features/Tournaments/pages/OverviewPage/OverviewPage.tsx b/src/features/Tournaments/pages/OverviewPage/OverviewPage.tsx index 8b3d1eb..3893659 100644 --- a/src/features/Tournaments/pages/OverviewPage/OverviewPage.tsx +++ b/src/features/Tournaments/pages/OverviewPage/OverviewPage.tsx @@ -17,9 +17,10 @@ interface Props { | 'faqs' > avatars: string[] + isRegistered: boolean; } -export default function OverviewPage({ data, avatars }: Props) { +export default function OverviewPage({ data, avatars, isRegistered }: Props) { return (
@@ -30,7 +31,7 @@ export default function OverviewPage({ data, avatars }: Props) { >
- +
diff --git a/src/features/Tournaments/pages/OverviewPage/RegisterCard/RegisterCard.tsx b/src/features/Tournaments/pages/OverviewPage/RegisterCard/RegisterCard.tsx index 18c7554..70cf9d6 100644 --- a/src/features/Tournaments/pages/OverviewPage/RegisterCard/RegisterCard.tsx +++ b/src/features/Tournaments/pages/OverviewPage/RegisterCard/RegisterCard.tsx @@ -1,30 +1,57 @@ import React from 'react' import { FaUsers } from 'react-icons/fa' +import { useParams } from 'react-router-dom' import Button from 'src/Components/Button/Button' import Card from 'src/Components/Card/Card' import Avatar from 'src/features/Profiles/Components/Avatar/Avatar' +import { openModal } from 'src/redux/features/modals.slice' import { useCountdown } from 'src/utils/hooks' +import { useAppDispatch, useAppSelector } from "src/utils/hooks"; interface Props { start_date: string; makers_count: number avatars: string[] + isRegistered: boolean; } -export default function RegisterCard({ makers_count, start_date, avatars }: Props) { +export default function RegisterCard({ makers_count, start_date, avatars, isRegistered }: Props) { const counter = useCountdown(start_date) + const { id: tournamentId } = useParams() + + + const isLoggedIn = useAppSelector(state => !!state.user.me) + const dispatch = useAppDispatch() + + const onRegister = () => { + if (!tournamentId) return; + + if (isLoggedIn) + dispatch(openModal({ + Modal: "RegisterTournamet_ConfrimAccount", + props: { + tournamentId: Number(tournamentId) + } + })) + else + dispatch(openModal({ + Modal: "RegisterTournamet_Login", + props: { + tournamentId: Number(tournamentId) + } + })) + } + return (
-

-

- {avatars.map((img, idx) =>
)} - + {makers_count} makers -
+

+ {avatars.map((img, idx) =>

)} + + {makers_count} makers

- +
{counter.isExpired ? diff --git a/src/features/Tournaments/pages/OverviewPage/RegisterationModals/ConfirmAccount/ConfirmAccount.tsx b/src/features/Tournaments/pages/OverviewPage/RegisterationModals/ConfirmAccount/ConfirmAccount.tsx new file mode 100644 index 0000000..9ea7762 --- /dev/null +++ b/src/features/Tournaments/pages/OverviewPage/RegisterationModals/ConfirmAccount/ConfirmAccount.tsx @@ -0,0 +1,68 @@ +import { motion } from 'framer-motion' +import { ModalCard, modalCardVariants } from 'src/Components/Modals/ModalsContainer/ModalsContainer' +import { IoClose } from 'react-icons/io5'; +import Avatar from 'src/features/Profiles/Components/Avatar/Avatar'; +import { useAppDispatch, useAppSelector } from "src/utils/hooks"; +import Button from 'src/Components/Button/Button'; +import { Direction, replaceModal } from 'src/redux/features/modals.slice'; + + +interface Props extends ModalCard { + tournamentId: number +} + +export default function ConfirmAccount({ onClose, direction, tournamentId, ...props }: Props) { + + const me = useAppSelector(state => state.user.me) + const dispatch = useAppDispatch(); + + if (!me) + return null; + + const onCancel = () => onClose?.(); + const onContinue = () => { + dispatch(replaceModal({ + Modal: "RegisterTournamet_RegistrationDetails", + direction: Direction.NEXT, + props: { + tournamentId + } + })) + } + + + return ( + +
+ +

Register for tournament

+
+
+
+ +
+

{me.name}

+

{me.jobTitle}

+
+ + +

You are currently signed in using this profile. Would you like to continue with your ⚔️ Tournament registration?

+ +
+ + +
+
+
+ ) +} + + + diff --git a/src/features/Tournaments/pages/OverviewPage/RegisterationModals/ConfirmAccount/index.ts b/src/features/Tournaments/pages/OverviewPage/RegisterationModals/ConfirmAccount/index.ts new file mode 100644 index 0000000..2caf10e --- /dev/null +++ b/src/features/Tournaments/pages/OverviewPage/RegisterationModals/ConfirmAccount/index.ts @@ -0,0 +1,3 @@ +import { lazyModal } from 'src/utils/helperFunctions'; + +export const { LazyComponent: ConfirmAccount } = lazyModal(() => import('./ConfirmAccount')) \ No newline at end of file diff --git a/src/features/Tournaments/pages/OverviewPage/RegisterationModals/LoginModal/LoginModal.tsx b/src/features/Tournaments/pages/OverviewPage/RegisterationModals/LoginModal/LoginModal.tsx new file mode 100644 index 0000000..de6f63b --- /dev/null +++ b/src/features/Tournaments/pages/OverviewPage/RegisterationModals/LoginModal/LoginModal.tsx @@ -0,0 +1,173 @@ +import { motion } from 'framer-motion' +import { ModalCard, modalCardVariants } from 'src/Components/Modals/ModalsContainer/ModalsContainer' +import { FiCopy } from "react-icons/fi"; +import { IoClose, IoRocketOutline } from 'react-icons/io5'; +import { useMeTournamentQuery } from 'src/graphql'; +import Button from 'src/Components/Button/Button'; +import { QRCodeSVG } from 'qrcode.react'; +import { Grid } from 'react-loader-spinner'; +import { useCallback, useEffect, useState } from 'react'; +import { CONSTS } from 'src/utils'; +import useCopyToClipboard from 'src/utils/hooks/useCopyToClipboard'; +import { useLnurlQuery } from 'src/features/Auth/pages/LoginPage/LoginPage'; +import { useAppDispatch } from 'src/utils/hooks'; +import { Direction, replaceModal } from 'src/redux/features/modals.slice'; + + +interface Props extends ModalCard { + tournamentId: number +} + +export default function LinkingAccountModal({ onClose, direction, tournamentId, ...props }: Props) { + + const [copied, setCopied] = useState(false); + + const { loadingLnurl, data: { lnurl, session_token }, error } = useLnurlQuery(); + const clipboard = useCopyToClipboard() + + const dispatch = useAppDispatch(); + + + useEffect(() => { + setCopied(false); + }, [lnurl]) + + const meQuery = useMeTournamentQuery({ + variables: { + inTournamentId: tournamentId + }, + onCompleted: (data) => { + if (data.me) { + const already_registerd = data.me.in_tournament; + if (already_registerd) + onClose?.(); + else dispatch(replaceModal({ + Modal: "RegisterTournamet_RegistrationDetails", + direction: Direction.NEXT, + props: { tournamentId } + })) + + } + + } + }); + + const copyToClipboard = () => { + setCopied(true); + clipboard(lnurl); + } + + const refetch = meQuery.refetch; + const startPolling = useCallback( + () => { + const interval = setInterval(() => { + fetch(CONSTS.apiEndpoint + '/is-logged-in', { + credentials: 'include', + headers: { + session_token + } + }).then(data => data.json()) + .then(data => { + if (data.logged_in) { + clearInterval(interval) + refetch(); + } + }) + }, 2000); + + return interval; + } + , [refetch, session_token], + ) + + + + useEffect(() => { + let interval: NodeJS.Timer; + if (lnurl) + interval = startPolling(); + + return () => { + clearInterval(interval) + } + }, [lnurl, startPolling]) + + + + let content = <> + + if (error) + content =
+

Something wrong happened...

+ Please try again +
+ + else if (loadingLnurl) + content =
+ +

Fetching Lnurl-Auth link

+
+ + + else + content =
+ + + +

+ To register for this tournament, you need a maker profile. Luckily, this is very easy! +
+
+ To sign in or create an account, just scan this QR, or click to connect using any lightning wallet like Alby or Breez. +

+
+ Click to connect + + What is a lightning wallet? +
+ +
; + + + return ( + +
+ +

Connect ⚡️ your maker profile

+
+
+
+ {content} +
+
+ ) +} + + + diff --git a/src/features/Tournaments/pages/OverviewPage/RegisterationModals/LoginModal/index.ts b/src/features/Tournaments/pages/OverviewPage/RegisterationModals/LoginModal/index.ts new file mode 100644 index 0000000..903f38a --- /dev/null +++ b/src/features/Tournaments/pages/OverviewPage/RegisterationModals/LoginModal/index.ts @@ -0,0 +1,3 @@ +import { lazyModal } from 'src/utils/helperFunctions'; + +export const { LazyComponent: LoginModal } = lazyModal(() => import('./LoginModal')) \ No newline at end of file diff --git a/src/features/Tournaments/pages/OverviewPage/RegisterationModals/RegistrationDetails/RegistrationDetails.tsx b/src/features/Tournaments/pages/OverviewPage/RegisterationModals/RegistrationDetails/RegistrationDetails.tsx new file mode 100644 index 0000000..2026ee7 --- /dev/null +++ b/src/features/Tournaments/pages/OverviewPage/RegisterationModals/RegistrationDetails/RegistrationDetails.tsx @@ -0,0 +1,181 @@ +import { motion } from 'framer-motion' +import { ModalCard, modalCardVariants } from 'src/Components/Modals/ModalsContainer/ModalsContainer' +import { IoClose } from 'react-icons/io5'; +import { useAppDispatch, useAppSelector } from "src/utils/hooks"; +import Button from 'src/Components/Button/Button'; +import { Direction, replaceModal } from 'src/redux/features/modals.slice'; +import BasicSelectInput from 'src/Components/Inputs/Selects/BasicSelectInput/BasicSelectInput'; +import { GetTournamentByIdDocument, TournamentMakerHackingStatusEnum, useRegisterInTournamentMutation } from 'src/graphql'; +import InfoCard from 'src/Components/InfoCard/InfoCard'; +import * as yup from "yup"; +import { yupResolver } from '@hookform/resolvers/yup'; +import { Controller, SubmitHandler, useForm } from 'react-hook-form'; +import { NotificationsService } from "src/services/notifications.service"; + + +interface Props extends ModalCard { + tournamentId: number +} + +const hackingStatusOptions = [ + { + label: "Hacking han solo 👻", + value: TournamentMakerHackingStatusEnum.Solo + }, { + label: "Open to connect 👋", + value: TournamentMakerHackingStatusEnum.OpenToConnect + }, +] + +interface IFormInputs { + email: string; + agreement: boolean; + hacking_status: typeof hackingStatusOptions[number]; +} + + +const schema: yup.SchemaOf = yup.object({ + email: yup.string().required().email(), + hacking_status: yup.object().shape({ + label: yup.string().required(), + value: yup.string().required() + }).required(), + agreement: yup.boolean().required().isTrue("You won't be able to follow the updates/events of the tournament if you don't allow this"), +}).required(); + +export default function RegistrationDetails({ onClose, direction, ...props }: Props) { + + + const me = useAppSelector(state => state.user.me) + const dispatch = useAppDispatch(); + + const [mutate, mutationStatus] = useRegisterInTournamentMutation() + + + const { handleSubmit, control, register, formState: { errors }, } = useForm({ + mode: "onChange", + resolver: yupResolver(schema), + defaultValues: { + email: "", + hacking_status: hackingStatusOptions[0] + } + + }); + + + if (!me) + return null; + + + const onCancel = () => onClose?.(); + + const onSubmit: SubmitHandler = data => { + mutate({ + variables: { + data: { + email: data.email, + hacking_status: data.hacking_status.value, + }, + tournamentId: Number(props.tournamentId) + }, + onCompleted: (data) => { + if (data.registerInTournament?.in_tournament) { + dispatch(replaceModal({ + Modal: "RegisterTournamet_RegistrationSuccess", + direction: Direction.NEXT + })) + + } + }, + refetchQueries: [{ + query: GetTournamentByIdDocument, + variables: { + id: props.tournamentId + } + }] + }) + .catch(() => { + NotificationsService.error("A network error happned...") + mutationStatus.reset() + }) + } + + + return ( + +
+ +

Register for tournament

+
+
+
+

Please provide us with some additional details below.

+ +
+ + } + /> + + + 👋 Details: other makers will be able to see your hacker card and send you Team Up requests. + +
+
+ +
+ +
+ + {errors.email &&

+ {errors.email.message} +

} +
+ + +
+ {errors.agreement &&

+ {errors.agreement.message} +

} +
+ +
+ + +
+
+
+ ) +} + + + diff --git a/src/features/Tournaments/pages/OverviewPage/RegisterationModals/RegistrationDetails/index.ts b/src/features/Tournaments/pages/OverviewPage/RegisterationModals/RegistrationDetails/index.ts new file mode 100644 index 0000000..cd7c9af --- /dev/null +++ b/src/features/Tournaments/pages/OverviewPage/RegisterationModals/RegistrationDetails/index.ts @@ -0,0 +1,3 @@ +import { lazyModal } from 'src/utils/helperFunctions'; + +export const { LazyComponent: RegistrationDetails } = lazyModal(() => import('./RegistrationDetails')) \ No newline at end of file diff --git a/src/features/Tournaments/pages/OverviewPage/RegisterationModals/RegistrationDetails/registerInTournament.graphql b/src/features/Tournaments/pages/OverviewPage/RegisterationModals/RegistrationDetails/registerInTournament.graphql new file mode 100644 index 0000000..02a3642 --- /dev/null +++ b/src/features/Tournaments/pages/OverviewPage/RegisterationModals/RegistrationDetails/registerInTournament.graphql @@ -0,0 +1,9 @@ +mutation RegisterInTournament( + $tournamentId: Int! + $data: RegisterInTournamentInput +) { + registerInTournament(tournament_id: $tournamentId, data: $data) { + id + in_tournament(id: $tournamentId) + } +} diff --git a/src/features/Tournaments/pages/OverviewPage/RegisterationModals/RegistrationSuccess/RegistrationSuccess.tsx b/src/features/Tournaments/pages/OverviewPage/RegisterationModals/RegistrationSuccess/RegistrationSuccess.tsx new file mode 100644 index 0000000..e45f8cd --- /dev/null +++ b/src/features/Tournaments/pages/OverviewPage/RegisterationModals/RegistrationSuccess/RegistrationSuccess.tsx @@ -0,0 +1,72 @@ +import { motion } from 'framer-motion' +import { ModalCard, modalCardVariants } from 'src/Components/Modals/ModalsContainer/ModalsContainer' +import { IoClose } from 'react-icons/io5'; +import Avatar from 'src/features/Profiles/Components/Avatar/Avatar'; +import { useAppSelector } from "src/utils/hooks"; +import Button from 'src/Components/Button/Button'; +import Confetti from "react-confetti"; +import { Portal } from 'src/Components/Portal/Portal'; + + +interface Props extends ModalCard { + +} + +export default function RegistrationSuccess({ onClose, direction, ...props }: Props) { + + const me = useAppSelector(state => state.user.me) + + if (!me) + throw new Error("User not defined"); + + + return ( + +
+ +

Registration succeeded!! ✅

+
+
+
+ +
+

{me.name}

+

{me.jobTitle}

+
+ +

Nice work! You’ve successfully registered for the tournament. You can get started with some of the options below!

+ + +
+
👾
+
+

Complete your maker profile

+

Add details to your maker profile so you stand out.

+
+
+
+
🤝️️️
+
+

Find makers to team up with

+

Recruit or find makers to team up with.

+
+
+ +
+ + +
+
+
+ ) +} + + + diff --git a/src/features/Tournaments/pages/OverviewPage/RegisterationModals/RegistrationSuccess/index.ts b/src/features/Tournaments/pages/OverviewPage/RegisterationModals/RegistrationSuccess/index.ts new file mode 100644 index 0000000..ae9cdab --- /dev/null +++ b/src/features/Tournaments/pages/OverviewPage/RegisterationModals/RegistrationSuccess/index.ts @@ -0,0 +1,3 @@ +import { lazyModal } from 'src/utils/helperFunctions'; + +export const { LazyComponent: RegistrationSuccess } = lazyModal(() => import('./RegistrationSuccess')) \ No newline at end of file diff --git a/src/features/Tournaments/pages/OverviewPage/RegisterationModals/index.tsx b/src/features/Tournaments/pages/OverviewPage/RegisterationModals/index.tsx new file mode 100644 index 0000000..6d7e22e --- /dev/null +++ b/src/features/Tournaments/pages/OverviewPage/RegisterationModals/index.tsx @@ -0,0 +1,11 @@ +import { LoginModal } from './LoginModal' +import { ConfirmAccount } from './ConfirmAccount' +import { RegistrationDetails } from './RegistrationDetails' +import { RegistrationSuccess } from './RegistrationSuccess' + +export const RegistrationModals = { + LoginModal, + RegistrationDetails, + ConfirmAccount, + RegistrationSuccess, +} diff --git a/src/features/Tournaments/pages/TournamentDetailsPage/Navigation/Navigation.tsx b/src/features/Tournaments/pages/TournamentDetailsPage/Navigation/Navigation.tsx index c24ad1f..b6e4f49 100644 --- a/src/features/Tournaments/pages/TournamentDetailsPage/Navigation/Navigation.tsx +++ b/src/features/Tournaments/pages/TournamentDetailsPage/Navigation/Navigation.tsx @@ -41,7 +41,7 @@ export default function Navigation({ data }: Props) { path: "resources", isDisabled: true, }, - ], [data.events_count]) + ], [data.events_count, data.makers_count, data.projects_count]) return (
diff --git a/src/features/Tournaments/pages/TournamentDetailsPage/TournamentDetailsPage.tsx b/src/features/Tournaments/pages/TournamentDetailsPage/TournamentDetailsPage.tsx index b101814..9778532 100644 --- a/src/features/Tournaments/pages/TournamentDetailsPage/TournamentDetailsPage.tsx +++ b/src/features/Tournaments/pages/TournamentDetailsPage/TournamentDetailsPage.tsx @@ -1,30 +1,34 @@ import Header from './Header/Header' -import { Navigate, Route, Routes } from 'react-router-dom' +import { Navigate, Route, Routes, useParams } from 'react-router-dom' import OverviewPage from '../OverviewPage/OverviewPage' import { Helmet } from 'react-helmet' import Navigation from './Navigation/Navigation' import EventsPage from '../EventsPage/EventsPage' import MakersPage from '../MakersPage/MakersPage' import ProjectsPage from '../ProjectsPage/ProjectsPage' -import { useGetTournamentByIdQuery } from 'src/graphql' +import { useGetTournamentByIdQuery, GetTournamentByIdQuery } from 'src/graphql' import LoadingPage from 'src/Components/LoadingPage/LoadingPage' import NotFoundPage from 'src/features/Shared/pages/NotFoundPage/NotFoundPage' +export type MeTournament = GetTournamentByIdQuery['me'] + export default function TournamentDetailsPage() { - const query = useGetTournamentByIdQuery({ - variables: { - id: 12, - }, + const { id } = useParams() + const tournaemntQuery = useGetTournamentByIdQuery({ + variables: { + id: Number(id)!, + }, + skip: !id }) - if (query.loading) + if (tournaemntQuery.loading) return - if (!query.data?.getTournamentById) + if (!tournaemntQuery.data?.getTournamentById) return return ( @@ -32,18 +36,18 @@ export default function TournamentDetailsPage() { "--maxPageWidth": "910px" } as any}> - {query.data.getTournamentById.title} Tournament + {tournaemntQuery.data.getTournamentById.title} Tournament -
- +
+
} /> - m.avatar)} />} /> - } /> - } /> - } /> + m.avatar)} isRegistered={!!tournaemntQuery.data.me?.in_tournament} />} /> + } /> + } /> + } />
diff --git a/src/features/Tournaments/pages/TournamentDetailsPage/meTournament.graphql b/src/features/Tournaments/pages/TournamentDetailsPage/meTournament.graphql new file mode 100644 index 0000000..c7615c3 --- /dev/null +++ b/src/features/Tournaments/pages/TournamentDetailsPage/meTournament.graphql @@ -0,0 +1,12 @@ +query MeTournament($inTournamentId: Int!) { + me { + id + name + avatar + jobTitle + + in_tournament(id: $inTournamentId) + + ...UserRolesSkills + } +} diff --git a/src/features/Tournaments/pages/TournamentDetailsPage/tournamentDetails.graphql b/src/features/Tournaments/pages/TournamentDetailsPage/tournamentDetails.graphql index 62e5f24..b1c4b29 100644 --- a/src/features/Tournaments/pages/TournamentDetailsPage/tournamentDetails.graphql +++ b/src/features/Tournaments/pages/TournamentDetailsPage/tournamentDetails.graphql @@ -48,4 +48,15 @@ query GetTournamentById($id: Int!) { avatar } } + + me { + id + name + avatar + jobTitle + + in_tournament(id: $id) + + ...UserRolesSkills + } } diff --git a/src/graphql/index.tsx b/src/graphql/index.tsx index ebe86f4..f848154 100644 --- a/src/graphql/index.tsx +++ b/src/graphql/index.tsx @@ -41,6 +41,7 @@ export type BaseUser = { email: Maybe; github: Maybe; id: Scalars['Int']; + in_tournament: Scalars['Boolean']; jobTitle: Maybe; join_date: Scalars['Date']; lightning_address: Maybe; @@ -57,6 +58,11 @@ export type BaseUser = { website: Maybe; }; + +export type BaseUserIn_TournamentArgs = { + id: Scalars['Int']; +}; + export type Bounty = PostBase & { __typename?: 'Bounty'; applicants_count: Scalars['Int']; @@ -173,6 +179,7 @@ export type Mutation = { createStory: Maybe; deleteStory: Maybe; donate: Donation; + registerInTournament: Maybe; updateProfileDetails: Maybe; updateProfileRoles: Maybe; updateUserPreferences: MyProfile; @@ -207,6 +214,12 @@ export type MutationDonateArgs = { }; +export type MutationRegisterInTournamentArgs = { + data: InputMaybe; + tournament_id: Scalars['Int']; +}; + + export type MutationUpdateProfileDetailsArgs = { data: InputMaybe; }; @@ -235,6 +248,7 @@ export type MyProfile = BaseUser & { email: Maybe; github: Maybe; id: Scalars['Int']; + in_tournament: Scalars['Boolean']; jobTitle: Maybe; join_date: Scalars['Date']; lightning_address: Maybe; @@ -254,6 +268,11 @@ export type MyProfile = BaseUser & { website: Maybe; }; + +export type MyProfileIn_TournamentArgs = { + id: Scalars['Int']; +}; + export enum Post_Type { Bounty = 'Bounty', Question = 'Question', @@ -469,6 +488,11 @@ export type Question = PostBase & { votes_count: Scalars['Int']; }; +export type RegisterInTournamentInput = { + email: Scalars['String']; + hacking_status: TournamentMakerHackingStatusEnum; +}; + export enum RoleLevelEnum { Advanced = 'Advanced', Beginner = 'Beginner', @@ -567,6 +591,11 @@ export type TournamentJudge = { name: Scalars['String']; }; +export enum TournamentMakerHackingStatusEnum { + OpenToConnect = 'OpenToConnect', + Solo = 'Solo' +} + export type TournamentMakersResponse = { __typename?: 'TournamentMakersResponse'; hasNext: Maybe; @@ -595,6 +624,7 @@ export type User = BaseUser & { email: Maybe; github: Maybe; id: Scalars['Int']; + in_tournament: Scalars['Boolean']; jobTitle: Maybe; join_date: Scalars['Date']; lightning_address: Maybe; @@ -611,6 +641,11 @@ export type User = BaseUser & { website: Maybe; }; + +export type UserIn_TournamentArgs = { + id: Scalars['Int']; +}; + export type UserKeyInputType = { key: Scalars['String']; name: Scalars['String']; @@ -826,11 +861,6 @@ export type ProjectDetailsQueryVariables = Exact<{ export type ProjectDetailsQuery = { __typename?: 'Query', getProject: { __typename?: 'Project', id: number, title: string, description: string, cover_image: string, thumbnail_image: string, screenshots: Array, website: string, lightning_address: string | null, lnurl_callback_url: string | null, votes_count: number, category: { __typename?: 'Category', id: number, title: string }, awards: Array<{ __typename?: 'Award', title: string, image: string, url: string, id: number }>, tags: Array<{ __typename?: 'Tag', 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; }>; @@ -858,12 +888,27 @@ export type GetProjectsInTournamentQueryVariables = Exact<{ export type GetProjectsInTournamentQuery = { __typename?: 'Query', getProjectsInTournament: { __typename?: 'TournamentProjectsResponse', hasNext: boolean | null, hasPrev: boolean | null, projects: Array<{ __typename?: 'Project', id: number, title: string, description: string, thumbnail_image: string, category: { __typename?: 'Category', id: number, title: string, icon: string | null }, recruit_roles: Array<{ __typename?: 'MakerRole', id: number, title: string, icon: string, level: RoleLevelEnum }> }> } }; +export type RegisterInTournamentMutationVariables = Exact<{ + tournamentId: Scalars['Int']; + data: InputMaybe; +}>; + + +export type RegisterInTournamentMutation = { __typename?: 'Mutation', registerInTournament: { __typename?: 'User', id: number, in_tournament: boolean } | null }; + +export type MeTournamentQueryVariables = Exact<{ + inTournamentId: Scalars['Int']; +}>; + + +export type MeTournamentQuery = { __typename?: 'Query', me: { __typename?: 'MyProfile', id: number, name: string, avatar: string, jobTitle: string | null, in_tournament: boolean, skills: Array<{ __typename?: 'MakerSkill', id: number, title: string }>, roles: Array<{ __typename?: 'MakerRole', id: number, title: string, icon: string, level: RoleLevelEnum }> } | null }; + export type GetTournamentByIdQueryVariables = Exact<{ id: Scalars['Int']; }>; -export type GetTournamentByIdQuery = { __typename?: 'Query', getTournamentById: { __typename?: 'Tournament', id: number, title: string, description: string, thumbnail_image: string, cover_image: string, start_date: any, end_date: any, location: string, website: string, events_count: number, makers_count: number, projects_count: number, prizes: Array<{ __typename?: 'TournamentPrize', title: string, amount: string, image: string }>, judges: Array<{ __typename?: 'TournamentJudge', name: string, company: string, avatar: string }>, events: Array<{ __typename?: 'TournamentEvent', id: number, title: string, image: string, description: string, starts_at: any, ends_at: any, location: string, website: string, type: TournamentEventTypeEnum, links: Array }>, faqs: Array<{ __typename?: 'TournamentFAQ', question: string, answer: string }> }, getMakersInTournament: { __typename?: 'TournamentMakersResponse', makers: Array<{ __typename?: 'User', id: number, avatar: string }> } }; +export type GetTournamentByIdQuery = { __typename?: 'Query', getTournamentById: { __typename?: 'Tournament', id: number, title: string, description: string, thumbnail_image: string, cover_image: string, start_date: any, end_date: any, location: string, website: string, events_count: number, makers_count: number, projects_count: number, prizes: Array<{ __typename?: 'TournamentPrize', title: string, amount: string, image: string }>, judges: Array<{ __typename?: 'TournamentJudge', name: string, company: string, avatar: string }>, events: Array<{ __typename?: 'TournamentEvent', id: number, title: string, image: string, description: string, starts_at: any, ends_at: any, location: string, website: string, type: TournamentEventTypeEnum, links: Array }>, faqs: Array<{ __typename?: 'TournamentFAQ', question: string, answer: string }> }, getMakersInTournament: { __typename?: 'TournamentMakersResponse', makers: Array<{ __typename?: 'User', id: number, avatar: string }> }, me: { __typename?: 'MyProfile', id: number, name: string, avatar: string, jobTitle: string | null, in_tournament: boolean, skills: Array<{ __typename?: 'MakerSkill', id: number, title: string }>, roles: Array<{ __typename?: 'MakerRole', id: number, title: string, icon: string, level: RoleLevelEnum }> } | null }; export type VoteMutationVariables = Exact<{ itemType: Vote_Item_Type; @@ -2188,44 +2233,6 @@ export function useProjectDetailsLazyQuery(baseOptions?: Apollo.LazyQueryHookOpt export type ProjectDetailsQueryHookResult = ReturnType; export type ProjectDetailsLazyQueryHookResult = ReturnType; export type ProjectDetailsQueryResult = Apollo.QueryResult; -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) { - const options = {...defaultOptions, ...baseOptions} - return Apollo.useQuery(MeTournamentDocument, options); - } -export function useMeTournamentLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { - const options = {...defaultOptions, ...baseOptions} - return Apollo.useLazyQuery(MeTournamentDocument, options); - } -export type MeTournamentQueryHookResult = ReturnType; -export type MeTournamentLazyQueryHookResult = ReturnType; -export type MeTournamentQueryResult = Apollo.QueryResult; export const GetAllRolesDocument = gql` query GetAllRoles { getAllMakersRoles { @@ -2390,6 +2397,81 @@ export function useGetProjectsInTournamentLazyQuery(baseOptions?: Apollo.LazyQue export type GetProjectsInTournamentQueryHookResult = ReturnType; export type GetProjectsInTournamentLazyQueryHookResult = ReturnType; export type GetProjectsInTournamentQueryResult = Apollo.QueryResult; +export const RegisterInTournamentDocument = gql` + mutation RegisterInTournament($tournamentId: Int!, $data: RegisterInTournamentInput) { + registerInTournament(tournament_id: $tournamentId, data: $data) { + id + in_tournament(id: $tournamentId) + } +} + `; +export type RegisterInTournamentMutationFn = Apollo.MutationFunction; + +/** + * __useRegisterInTournamentMutation__ + * + * To run a mutation, you first call `useRegisterInTournamentMutation` within a React component and pass it any options that fit your needs. + * When your component renders, `useRegisterInTournamentMutation` returns a tuple that includes: + * - A mutate function that you can call at any time to execute the mutation + * - An object with fields that represent the current status of the mutation's execution + * + * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2; + * + * @example + * const [registerInTournamentMutation, { data, loading, error }] = useRegisterInTournamentMutation({ + * variables: { + * tournamentId: // value for 'tournamentId' + * data: // value for 'data' + * }, + * }); + */ +export function useRegisterInTournamentMutation(baseOptions?: Apollo.MutationHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useMutation(RegisterInTournamentDocument, options); + } +export type RegisterInTournamentMutationHookResult = ReturnType; +export type RegisterInTournamentMutationResult = Apollo.MutationResult; +export type RegisterInTournamentMutationOptions = Apollo.BaseMutationOptions; +export const MeTournamentDocument = gql` + query MeTournament($inTournamentId: Int!) { + me { + id + name + avatar + jobTitle + in_tournament(id: $inTournamentId) + ...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: { + * inTournamentId: // value for 'inTournamentId' + * }, + * }); + */ +export function useMeTournamentQuery(baseOptions: Apollo.QueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useQuery(MeTournamentDocument, options); + } +export function useMeTournamentLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useLazyQuery(MeTournamentDocument, options); + } +export type MeTournamentQueryHookResult = ReturnType; +export type MeTournamentLazyQueryHookResult = ReturnType; +export type MeTournamentQueryResult = Apollo.QueryResult; export const GetTournamentByIdDocument = gql` query GetTournamentById($id: Int!) { getTournamentById(id: $id) { @@ -2438,8 +2520,16 @@ export const GetTournamentByIdDocument = gql` avatar } } + me { + id + name + avatar + jobTitle + in_tournament(id: $id) + ...UserRolesSkills + } } - `; + ${UserRolesSkillsFragmentDoc}`; /** * __useGetTournamentByIdQuery__ diff --git a/src/mocks/data/users.ts b/src/mocks/data/users.ts index 5ac031c..4ca7d8b 100644 --- a/src/mocks/data/users.ts +++ b/src/mocks/data/users.ts @@ -157,6 +157,7 @@ export const users: (User & MyProfile)[] = [{ twitter: "mtg", website: "https://mtg-dev.tech", stories: posts.stories, + in_tournament: true, nostr_prv_key: "123123124asdfsadfsa8d7fsadfasdf", nostr_pub_key: "123124123123dfsadfsa8d7f11sadfasdf", walletsKeys: [ @@ -191,6 +192,7 @@ export const users: (User & MyProfile)[] = [{ twitter: "john-doe", website: "https://mtg-dev.tech", stories: posts.stories, + in_tournament: true, nostr_prv_key: "123123124asdfsadfsa8d7fsadfasdf", nostr_pub_key: "123124123123dfsadfsa8d7f11sadfasdf", @@ -226,6 +228,7 @@ export const users: (User & MyProfile)[] = [{ twitter: "john-doe", website: "https://mtg-dev.tech", stories: posts.stories, + in_tournament: true, nostr_prv_key: "123123124asdfsadfsa8d7fsadfasdf", nostr_pub_key: "123124123123dfsadfsa8d7f11sadfasdf", walletsKeys: [ @@ -260,6 +263,7 @@ export const users: (User & MyProfile)[] = [{ twitter: "john-doe", website: "https://mtg-dev.tech", stories: posts.stories, + in_tournament: true, nostr_prv_key: "123123124asdfsadfsa8d7fsadfasdf", nostr_pub_key: "123124123123dfsadfsa8d7f11sadfasdf", walletsKeys: [ diff --git a/src/mocks/handlers.ts b/src/mocks/handlers.ts index 147c620..b6a8bc4 100644 --- a/src/mocks/handlers.ts +++ b/src/mocks/handlers.ts @@ -283,7 +283,8 @@ export const handlers = [ return res( ctx.data({ getTournamentById: getTournamentById(12), - getMakersInTournament: getMakersInTournament({ roleId: null, search: null, skip: null, take: 4, tournamentId: 12 }) + getMakersInTournament: getMakersInTournament({ roleId: null, search: null, skip: null, take: 4, tournamentId: 12 }), + me: { ...me() } }) ) }), diff --git a/src/redux/features/modals.slice.ts b/src/redux/features/modals.slice.ts index 98b413f..eb49b57 100644 --- a/src/redux/features/modals.slice.ts +++ b/src/redux/features/modals.slice.ts @@ -15,6 +15,7 @@ import { ComponentProps } from "react"; import { generateId } from "src/utils/helperFunctions"; import { NoWeblnModal } from "src/Components/Modals/NoWeblnModal"; import { ConnectToMakerModal } from "src/features/Tournaments/pages/MakersPage/ConnectToMakerModal"; +import { RegistrationModals } from "src/features/Tournaments/pages/OverviewPage/RegisterationModals"; @@ -44,6 +45,10 @@ export const ALL_MODALS = { // Tournaments EventModal, ConnectToMakerModal, + RegisterTournamet_Login: RegistrationModals.LoginModal, + RegisterTournamet_ConfrimAccount: RegistrationModals.ConfirmAccount, + RegisterTournamet_RegistrationDetails: RegistrationModals.RegistrationDetails, + RegisterTournamet_RegistrationSuccess: RegistrationModals.RegistrationSuccess, // Misc ConfirmModal, diff --git a/src/styles/tw.scss b/src/styles/tw.scss index a2bb859..18b2141 100644 --- a/src/styles/tw.scss +++ b/src/styles/tw.scss @@ -44,6 +44,6 @@ } .modal-card { - @apply rounded-[40px] bg-gray-50 overflow-hidden w-full shadow-2xl z-10; + @apply rounded-[40px] bg-white overflow-hidden w-full shadow-2xl z-10; } }