From 7f6c24f4bdf34dfc97475c9580dfde77f9d39031 Mon Sep 17 00:00:00 2001 From: mrtmeeseeks Date: Tue, 12 Nov 2024 18:10:15 +0200 Subject: [PATCH 01/10] added contributions and started implementation of commit contribution --- eslint.config.js | 3 +- package-lock.json | 10 +- package.json | 2 +- src/App.tsx | 8 + src/api/aut.api.ts | 13 + src/api/contributions.api.ts | 221 +++++++++++ .../discord-gathering.model.ts | 45 +++ .../contribution-types/join-discord.model.ts | 40 ++ .../contribution-types/open-task.model.ts | 44 +++ .../contribution-types/quiz.model.model.ts | 49 +++ .../contribution-types/retweet.model.ts | 38 ++ src/api/models/contribution.model.ts | 52 +++ src/api/models/task-type.ts | 9 + src/components/AutEditProfileDialog.tsx | 1 - .../AutID/AutHub/AutHubContributionsTable.tsx | 348 +++++++++--------- src/pages/Tasks/Shared/TaskDetails.tsx | 7 +- .../contributions/contributions.reducer.ts | 7 +- src/redux/reducers.ts | 4 +- src/redux/store.ts | 3 +- src/utils/format-contribution-type.tsx | 33 -- src/utils/hooks/GetContributions.tsx | 119 +++--- src/utils/hooks/useQueryTaskTypes.tsx | 74 ++++ 22 files changed, 856 insertions(+), 274 deletions(-) create mode 100644 src/api/contributions.api.ts create mode 100644 src/api/models/contribution-types/discord-gathering.model.ts create mode 100644 src/api/models/contribution-types/join-discord.model.ts create mode 100644 src/api/models/contribution-types/open-task.model.ts create mode 100644 src/api/models/contribution-types/quiz.model.model.ts create mode 100644 src/api/models/contribution-types/retweet.model.ts create mode 100644 src/api/models/contribution.model.ts create mode 100644 src/api/models/task-type.ts delete mode 100644 src/utils/format-contribution-type.tsx create mode 100644 src/utils/hooks/useQueryTaskTypes.tsx diff --git a/eslint.config.js b/eslint.config.js index 390b18c..e3ecdd7 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -28,7 +28,8 @@ export default tseslint.config( "@typescript-eslint/no-unused-vars": "off", "react-refresh/only-export-components": "off", "react-hooks/exhaustive-deps": "off", - "@typescript-eslint/no-unused-expressions": "off" + "@typescript-eslint/no-unused-expressions": "off", + "no-debugger":"off" } } ); diff --git a/package-lock.json b/package-lock.json index 3cf0a49..e05d105 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "@aut-labs/abi-types": "^0.0.86-dev", "@aut-labs/connector": "^0.0.203", "@aut-labs/d-aut": "^1.0.204-dev", - "@aut-labs/sdk": "^0.0.221-dev", + "@aut-labs/sdk": "^0.0.222-dev", "@emotion/react": "^11.11.3", "@emotion/styled": "^11.11.0", "@marker.io/browser": "^0.19.0", @@ -145,6 +145,7 @@ "version": "0.0.203", "resolved": "https://registry.npmjs.org/@aut-labs/connector/-/connector-0.0.203.tgz", "integrity": "sha512-bUXlRb1YviVb6jpnTLnZs3HaZhABItep+knkbCsrKAAZcPH0bcsnJsjCfLOH2PsZX+BcTafxUrT2FDmy92aeZw==", + "license": "MIT", "dependencies": { "@web3auth/base": "^8.0.0", "@web3auth/ethereum-provider": "^8.0.1", @@ -170,9 +171,10 @@ "integrity": "sha512-sDEu6yyvqu/KjqobI6nBoovrHWwhA4DoXPWObQLcGRs1Isuxg/d2HhP2/9k6Xz5zjFDo/w3MDI3XDvpVos20dg==" }, "node_modules/@aut-labs/sdk": { - "version": "0.0.221-dev", - "resolved": "https://registry.npmjs.org/@aut-labs/sdk/-/sdk-0.0.221-dev.tgz", - "integrity": "sha512-W6R0oneKaSvc9kYIicSoPvygP1c4UlWrWu884FtAPPrrRQpucEvo9NG2FzsKa/Ku+nKV6APf6YoG3Zjib1vLvQ==", + "version": "0.0.222-dev", + "resolved": "https://registry.npmjs.org/@aut-labs/sdk/-/sdk-0.0.222-dev.tgz", + "integrity": "sha512-0RMVx8JojxsWZZkfUaMPB6y/dKqwqoG8fbMzVQ57isgX+XCfRdqAQTh6mjM32O77VLi1N1Y71x7p33Zb89a15A==", + "license": "MIT", "dependencies": { "@aut-labs/abi-types": "^0.0.86-dev", "date-fns": "^2.29.3", diff --git a/package.json b/package.json index 641b512..ebe8891 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "@aut-labs/abi-types": "^0.0.86-dev", "@aut-labs/connector": "^0.0.203", "@aut-labs/d-aut": "^1.0.204-dev", - "@aut-labs/sdk": "^0.0.221-dev", + "@aut-labs/sdk": "^0.0.222-dev", "@emotion/react": "^11.11.3", "@emotion/styled": "^11.11.0", "@marker.io/browser": "^0.19.0", diff --git a/src/App.tsx b/src/App.tsx index 0728fe5..347b0f3 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -3,6 +3,7 @@ import { Route, Routes, Navigate } from "react-router-dom"; import { Box, useMediaQuery, useTheme } from "@mui/material"; import { useAppDispatch } from "@store/store.model"; import { updateWalletProviderState } from "@store/WalletProvider/WalletProvider"; +import useQueryTaskTypes from "@utils/hooks/useQueryTaskTypes"; import AutLoading from "@components/AutLoading"; import Web3DautConnect from "@components/DAutConnect"; import SWSnackbar from "./components/snackbar"; @@ -22,6 +23,13 @@ function App() { const theme = useTheme(); const mobile = useMediaQuery(theme.breakpoints.down("md")); + const { refetch } = useQueryTaskTypes({ + variables: { + skip: 0, + take: 1000 + } + }); + useEffect(() => { getAppConfig() .then(async (networks) => { diff --git a/src/api/aut.api.ts b/src/api/aut.api.ts index 686a05e..e7851a7 100644 --- a/src/api/aut.api.ts +++ b/src/api/aut.api.ts @@ -4,6 +4,7 @@ import { NetworkConfig } from "./models/network.config"; import { extractDomain } from "@utils/helpers"; import { useAutConnector, useWalletConnector } from "@aut-labs/connector"; import { useEffect, useState } from "react"; +import { AuthSig } from "@aut-labs/connector/lib/esm/aut-sig"; export const getAppConfig = (): Promise => { return axios @@ -11,6 +12,18 @@ export const getAppConfig = (): Promise => { .then((r) => r.data); }; +interface EncryptRequest { + autSig: AuthSig; + message: string; + hubAddress: string; +} + +export const encryptMessage = (body: EncryptRequest): Promise => { + return axios + .post(`${environment.apiUrl}/task/encrypt`, body) + .then((r) => r.data); +}; + export const useAuthenticatedApi = () => { const { state: { multiSigner, address } diff --git a/src/api/contributions.api.ts b/src/api/contributions.api.ts new file mode 100644 index 0000000..388f3bc --- /dev/null +++ b/src/api/contributions.api.ts @@ -0,0 +1,221 @@ +import { TaskContributionNFT } from "@aut-labs/sdk"; +import { BaseQueryApi, createApi } from "@reduxjs/toolkit/query/react"; +import { AuthSig } from "@aut-labs/connector/lib/esm/aut-sig"; +import { DiscordGatheringContribution } from "./models/contribution-types/discord-gathering.model"; +import { OpenTaskContribution } from "./models/contribution-types/open-task.model"; +import { QuizTaskContribution } from "./models/contribution-types/quiz.model.model"; +import { RetweetContribution } from "./models/contribution-types/retweet.model"; +import axios from "axios"; +import { environment } from "./environment"; + +interface CommitRequest { + autSig: AuthSig; + message: string; + hubAddress: string; + contributionId: string; +} + +export const _commitContribution = async ( + body: CommitRequest +): Promise => { + const r = await axios.post( + `${environment.apiUrl}/task/contribution/commit`, + body + ); + return r.data; +}; + +const commitContribution = async ( + autSig: AuthSig, + contribution: TaskContributionNFT, + message: string, + api: BaseQueryApi +) => { + try { + const state: any = api.getState() as any; + const hubAddress = state.aut.selectedHubAddress; + const response = _commitContribution({ + autSig: autSig, + message: message, + hubAddress: hubAddress, + contributionId: contribution.properties.id + }); + return { + data: response + }; + } catch (error) { + return { + error: error.message + }; + } +}; + +const commitOpenTaskContribution = async ( + { + contribution, + autSig + }: { contribution: OpenTaskContribution; autSig: AuthSig }, + api: BaseQueryApi +) => { + const secredMessage = "secred"; + return commitContribution(autSig, contribution, secredMessage, api); +}; + +const commitTwitterRetweetContribution = async ( + { + contribution, + autSig + }: { contribution: RetweetContribution; autSig: AuthSig }, + api: BaseQueryApi +) => { + const secredMessage = "secred"; + return commitContribution(autSig, contribution, secredMessage, api); +}; + +const commitDiscordGatheringContribution = async ( + { + contribution, + autSig + }: { contribution: DiscordGatheringContribution; autSig: AuthSig }, + api: BaseQueryApi +) => { + const secredMessage = "secred"; + return commitContribution(autSig, contribution, secredMessage, api); +}; + +const commitQuizContribution = async ( + { + contribution, + autSig + }: { contribution: QuizTaskContribution; autSig: AuthSig }, + api: BaseQueryApi +) => { + const secredMessage = "secred"; + return commitContribution(autSig, contribution, secredMessage, api); +}; + +const commitAnyContribution = async ( + { + contribution, + autSig + }: { contribution: TaskContributionNFT; autSig: AuthSig }, + api: BaseQueryApi +) => { + if (contribution instanceof OpenTaskContribution) { + return commitOpenTaskContribution({ contribution, autSig }, api); + } else if (contribution instanceof DiscordGatheringContribution) { + return commitDiscordGatheringContribution({ contribution, autSig }, api); + } else if (contribution instanceof RetweetContribution) { + return commitTwitterRetweetContribution({ contribution, autSig }, api); + } else if (contribution instanceof QuizTaskContribution) { + return commitQuizContribution({ contribution, autSig }, api); + } else { + throw new Error("Unknown contribution type"); + } +}; + +export const contributionsApi = createApi({ + reducerPath: "contributionsApi", + baseQuery: (args, api, extraOptions) => { + const { url, body } = args; + if (url === "commitOpenTaskContribution") { + return commitOpenTaskContribution(body, api); + } + if (url === "commitDiscordGatheringContribution") { + return commitDiscordGatheringContribution(body, api); + } + if (url === "commitTwitterRetweetContribution") { + return commitTwitterRetweetContribution(body, api); + } + if (url === "commitQuizContribution") { + return commitQuizContribution(body, api); + } + if (url === "commitAnyContribution") { + return commitAnyContribution(body, api); + } + return { + data: "Test" + }; + }, + tagTypes: ["Contributions"], + endpoints: (builder) => ({ + commitOpenTaskContribution: builder.mutation< + void, + { + autSig: AuthSig; + contribution: OpenTaskContribution; + } + >({ + query: (body) => { + return { + body, + url: "commitOpenTaskContribution" + }; + } + }), + commitDiscordGatheringContribution: builder.mutation< + void, + { + autSig: AuthSig; + contribution: DiscordGatheringContribution; + } + >({ + query: (body) => { + return { + body, + url: "commitDiscordGatheringContribution" + }; + } + }), + commitTwitterRetweetContribution: builder.mutation< + void, + { + autSig: AuthSig; + contribution: RetweetContribution; + } + >({ + query: (body) => { + return { + body, + url: "commitTwitterRetweetContribution" + }; + } + }), + commitQuizContribution: builder.mutation< + void, + { + autSig: AuthSig; + contribution: QuizTaskContribution; + } + >({ + query: (body) => { + return { + body, + url: "commitQuizContribution" + }; + } + }), + commitAnyContribution: builder.mutation< + void, + { + autSig: AuthSig; + contribution: TaskContributionNFT; + } + >({ + query: (body) => { + return { + body, + url: "commitAnyContribution" + }; + } + }) + }) +}); + +export const { + useCommitAnyContributionMutation, + useCommitTwitterRetweetContributionMutation, + useCommitOpenTaskContributionMutation, + useCommitDiscordGatheringContributionMutation, + useCommitQuizContributionMutation +} = contributionsApi; diff --git a/src/api/models/contribution-types/discord-gathering.model.ts b/src/api/models/contribution-types/discord-gathering.model.ts new file mode 100644 index 0000000..bdd8f74 --- /dev/null +++ b/src/api/models/contribution-types/discord-gathering.model.ts @@ -0,0 +1,45 @@ +import { + BaseNFTModel, + TaskContributionNFT, + TaskContributionProperties +} from "@aut-labs/sdk"; + +export class DiscordGatheringContributionProperties extends TaskContributionProperties { + channelId: string; + duration: number; + + constructor(data: DiscordGatheringContributionProperties) { + super(data); + this.channelId = data.channelId; + this.duration = data.duration; + } +} + +export class DiscordGatheringContribution< + T = DiscordGatheringContributionProperties +> extends TaskContributionNFT { + static getContributionNFT( + contribution: DiscordGatheringContribution + ): BaseNFTModel { + const taskContribution = new DiscordGatheringContribution(contribution); + return { + name: taskContribution.name, + description: taskContribution.description, + properties: { + duration: taskContribution.properties.duration, + channelId: taskContribution.properties.channelId + } + } as BaseNFTModel; + } + + constructor( + data: DiscordGatheringContribution = {} as DiscordGatheringContribution + ) { + super(data); + this.properties = new DiscordGatheringContributionProperties( + data.properties as DiscordGatheringContributionProperties + ) as T; + } + + contributionType? = "Discord Gatherings"; +} diff --git a/src/api/models/contribution-types/join-discord.model.ts b/src/api/models/contribution-types/join-discord.model.ts new file mode 100644 index 0000000..489d5c3 --- /dev/null +++ b/src/api/models/contribution-types/join-discord.model.ts @@ -0,0 +1,40 @@ +import { + BaseNFTModel, + TaskContributionNFT, + TaskContributionProperties +} from "@aut-labs/sdk"; + +export class JoinDiscordTaskContributionProperties extends TaskContributionProperties { + inviteUrl: string; + constructor(data: JoinDiscordTaskContributionProperties) { + super(data); + this.inviteUrl = data.inviteUrl; + } +} + +export class JoinDiscordContribution< + T = JoinDiscordTaskContributionProperties +> extends TaskContributionNFT { + static getContributionNFT( + contribution: JoinDiscordContribution + ): BaseNFTModel { + const taskContribution = new JoinDiscordContribution(contribution); + return { + name: taskContribution.name, + description: taskContribution.description, + properties: { + inviteUrl: taskContribution.properties.inviteUrl, + } + } as BaseNFTModel; + } + constructor( + data: JoinDiscordContribution = {} as JoinDiscordContribution + ) { + super(data); + this.properties = new JoinDiscordTaskContributionProperties( + data.properties as JoinDiscordTaskContributionProperties + ) as T; + } + + contributionType? = "Join Discord"; +} diff --git a/src/api/models/contribution-types/open-task.model.ts b/src/api/models/contribution-types/open-task.model.ts new file mode 100644 index 0000000..115ee90 --- /dev/null +++ b/src/api/models/contribution-types/open-task.model.ts @@ -0,0 +1,44 @@ +import { + BaseNFTModel, + TaskContributionNFT, + TaskContributionProperties + } from "@aut-labs/sdk"; + +export class OpenTaskContributionProperties extends TaskContributionProperties { + attachmentRequired: boolean; + textRequired: boolean; + attachmentType: string; + constructor(data: OpenTaskContributionProperties) { + super(data); + this.attachmentRequired = data.attachmentRequired; + this.textRequired = data.textRequired; + this.attachmentType = data.attachmentType; + } + } + + export class OpenTaskContribution< + T = OpenTaskContributionProperties + > extends TaskContributionNFT { + static getContributionNFT( + contribution: OpenTaskContribution + ): BaseNFTModel { + const taskContribution = new OpenTaskContribution(contribution); + return { + name: taskContribution.name, + description: taskContribution.description, + properties: { + attachmentRequired: taskContribution.properties.attachmentRequired, + textRequired: taskContribution.properties.textRequired, + attachmentType: taskContribution.properties.attachmentType + } + } as BaseNFTModel; + } + constructor(data: OpenTaskContribution = {} as OpenTaskContribution) { + super(data); + this.properties = new OpenTaskContributionProperties( + data.properties as OpenTaskContributionProperties + ) as T; + } + + contributionType? = "Open Task"; + } \ No newline at end of file diff --git a/src/api/models/contribution-types/quiz.model.model.ts b/src/api/models/contribution-types/quiz.model.model.ts new file mode 100644 index 0000000..6e58513 --- /dev/null +++ b/src/api/models/contribution-types/quiz.model.model.ts @@ -0,0 +1,49 @@ +import { + BaseNFTModel, + TaskContributionNFT, + TaskContributionProperties +} from "@aut-labs/sdk"; + +interface QuizQuestionsAndAnswers { + question: string; + questionType: string; + answers: { + value: string; + correct: boolean; + }[]; +} + +export class QuizTaskContributionProperties extends TaskContributionProperties { + questions: QuizQuestionsAndAnswers[]; + hash: string; + constructor(data: QuizTaskContributionProperties) { + super(data); + this.questions = data.questions; + this.hash = data.hash; + } +} + +export class QuizTaskContribution< + T = QuizTaskContributionProperties +> extends TaskContributionNFT { + static getContributionNFT( + contribution: QuizTaskContribution + ): BaseNFTModel { + const taskContribution = new QuizTaskContribution(contribution); + return { + name: taskContribution.name, + description: taskContribution.description, + properties: { + questions: taskContribution.properties.questions, + } + } as BaseNFTModel; + } + constructor(data: QuizTaskContribution = {} as QuizTaskContribution) { + super(data); + this.properties = new QuizTaskContributionProperties( + data.properties as QuizTaskContributionProperties + ) as T; + } + + contributionType? = "Quiz"; +} diff --git a/src/api/models/contribution-types/retweet.model.ts b/src/api/models/contribution-types/retweet.model.ts new file mode 100644 index 0000000..8e6d0f9 --- /dev/null +++ b/src/api/models/contribution-types/retweet.model.ts @@ -0,0 +1,38 @@ +import { + BaseNFTModel, + TaskContributionNFT, + TaskContributionProperties +} from "@aut-labs/sdk"; + +export class RetweetContributionProperties extends TaskContributionProperties { + tweetUrl: string; + constructor(data: RetweetContributionProperties) { + super(data); + this.tweetUrl = data.tweetUrl; + } +} + +export class RetweetContribution< + T = RetweetContributionProperties +> extends TaskContributionNFT { + static getContributionNFT( + contribution: RetweetContribution + ): BaseNFTModel { + const taskContribution = new RetweetContribution(contribution); + return { + name: taskContribution.name, + description: taskContribution.description, + properties: { + tweetUrl: taskContribution.properties.tweetUrl + } + } as BaseNFTModel; + } + constructor(data: RetweetContribution = {} as RetweetContribution) { + super(data); + this.properties = new RetweetContributionProperties( + data.properties as RetweetContributionProperties + ) as T; + } + + contributionType? = "Retweet"; +} diff --git a/src/api/models/contribution.model.ts b/src/api/models/contribution.model.ts new file mode 100644 index 0000000..81d2905 --- /dev/null +++ b/src/api/models/contribution.model.ts @@ -0,0 +1,52 @@ +import { BaseNFTModel, TaskContributionNFT } from "@aut-labs/sdk"; +import { OpenTaskContribution } from "./contribution-types/open-task.model"; +import { DiscordGatheringContribution } from "./contribution-types/discord-gathering.model"; +import { RetweetContribution } from "./contribution-types/retweet.model"; +import { JoinDiscordContribution } from "./contribution-types/join-discord.model"; +import { QuizTaskContribution } from "./contribution-types/quiz.model.model"; +import { TaskType } from "./task-type"; + +export const ContributionFactory = ( + metadata: BaseNFTModel, + contribution: any, + taskTypes: TaskType[] +) => { + const taskType = taskTypes.find( + (taskType) => taskType.taskId === contribution.taskId + ); + + if (!taskType) { + throw new Error("Task type not found"); + } + const taskName = taskType.metadata.properties.type; + const data = { + ...metadata, + properties: { + ...metadata.properties, + ...contribution + } + }; + switch (taskName) { + case "OpenTask": + return new OpenTaskContribution(data); + case "DiscordGatherings": + return new DiscordGatheringContribution(data); + case "TwitterRetweet": + return new RetweetContribution(data); + case "JoinDiscord": + return new JoinDiscordContribution(data); + case "Quiz": + return new QuizTaskContribution(data); + case "TwitterLike": + case "GitHubCommit": + case "GitHubOpenPR": + case "DiscordPolls": + case "TwitterFollow": + case "TwitterComment": + // throw new Error("Task type not implemented"); + return new TaskContributionNFT(data); + + default: + throw new Error("Task type not found"); + } +}; diff --git a/src/api/models/task-type.ts b/src/api/models/task-type.ts new file mode 100644 index 0000000..6db2423 --- /dev/null +++ b/src/api/models/task-type.ts @@ -0,0 +1,9 @@ +import { BaseNFTModel } from "@aut-labs/sdk"; + +export interface TaskType { + id: string; + metadataUri: string; + taskId: string; + creator: string; + metadata: BaseNFTModel; +} \ No newline at end of file diff --git a/src/components/AutEditProfileDialog.tsx b/src/components/AutEditProfileDialog.tsx index be844c7..9b6a649 100644 --- a/src/components/AutEditProfileDialog.tsx +++ b/src/components/AutEditProfileDialog.tsx @@ -214,7 +214,6 @@ function AutEditProfileDialog(props: EditDialogProps) { // return social; // }); // // eslint-disable-next-line no-debugger - // debugger; await dispatch( updateProfile({ ...autID, diff --git a/src/pages/AutID/AutHub/AutHubContributionsTable.tsx b/src/pages/AutID/AutHub/AutHubContributionsTable.tsx index bd7a985..a6087db 100644 --- a/src/pages/AutID/AutHub/AutHubContributionsTable.tsx +++ b/src/pages/AutID/AutHub/AutHubContributionsTable.tsx @@ -21,15 +21,11 @@ import { import { format } from "date-fns"; import { AutOsButton } from "@components/AutButton"; import { Link } from "react-router-dom"; -import { useDispatch, useSelector } from "react-redux"; -import { - AllContributions, - setSelectedContribution, - updateContributionState -} from "@store/contributions/contributions.reducer"; -import { formatContributionType } from "@utils/format-contribution-type"; +import { useDispatch } from "react-redux"; import { TaskStatus } from "@store/model"; import useQueryContributions from "@utils/hooks/GetContributions"; +import { useCommitAnyContributionMutation } from "@api/contributions.api"; +import { useWalletConnector } from "@aut-labs/connector"; const StyledTableCell = styled(TableCell)(({ theme }) => ({ [`&.${tableCellClasses.head}, &.${tableCellClasses.body}`]: { @@ -51,175 +47,163 @@ const StyledTableRow = styled(TableRow)(({ theme }) => ({ } })); -const generateRandomId = () => { - return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) { - const r = (Math.random() * 16) | 0, - v = c === "x" ? r : (r & 0x3) | 0x8; - return v.toString(16); - }); -}; +interface TableListItemProps { + row: any; + commitContribution: (row: any) => void; +} -const TableListItem = memo((data: any) => { - const dispatch = useDispatch(); - const { row } = data; - const theme = useTheme(); +const TableListItem = memo( + ({ row, commitContribution }: TableListItemProps) => { + const theme = useTheme(); - const handleContributionClick = (contribution) => { - dispatch(setSelectedContribution(contribution)); - }; + const startDate = useMemo(() => { + return format( + new Date(row?.properties?.startDate * 1000), + "dd.MM.yy" + ).toString(); + }, [row?.properties?.startDate]); - const contributionType = useMemo( - () => formatContributionType(row?.contributionType), - [row?.contributionType] - ); + const endDate = useMemo(() => { + return format( + new Date(row?.properties?.endDate * 1000), + "dd.MM.yy" + ).toString(); + }, [row?.properties?.endDate]); - const startDate = useMemo(() => { - return format( - new Date(row?.properties?.startDate * 1000), - "dd.MM.yy" - ).toString(); - }, [row?.properties?.startDate]); - - const endDate = useMemo(() => { - return format( - new Date(row?.properties?.endDate * 1000), - "dd.MM.yy" - ).toString(); - }, [row?.properties?.endDate]); - - return ( - - - - - {row?.name} - - - {row?.description} - - - - - + }} + > + + + + {row?.name} + + + {row?.description} + + + + + + + {row?.contributionType} + + + + - {contributionType} + {`${row?.properties?.points || 0} ${row?.properties?.points === 1 ? "pt" : "pts"}`} - - - - - {`${row?.properties?.points || 0} ${row?.properties?.points === 1 ? "pt" : "pts"}`} - - - - + + + + + {startDate} + + + + + - {startDate} + {endDate} - - - - - - {endDate} - - + - - - {row?.status === TaskStatus.Created ? ( - handleContributionClick(row)} - > - - Claim - - - ) : ( - - - Completed - - - )} - - - - ); -}); + + + {row?.status !== TaskStatus.Created ? ( + commitContribution(row)} + > + + Claim + + + ) : ( + + + Claimed + + + )} + + + + ); + } +); export const AutHubTasksTable = ({ header }) => { const dispatch = useDispatch(); - const contributions = useSelector(AllContributions); + const { state } = useWalletConnector(); const { data, @@ -231,22 +215,18 @@ export const AutHubTasksTable = ({ header }) => { take: 1000 } }); - useEffect(() => { - if (!contributions.length) { - const updatedContributions = data?.map((item) => ({ - ...item, - contributionType: (item.properties as any) - .tweetUrl - ? "retweet" - : "open", - status: TaskStatus.Created, - id: generateRandomId() - })); - dispatch( - updateContributionState({ contributions: updatedContributions }) - ); - } - }, [data]); + + const [ + commit, + { error, isError, isSuccess, isLoading: commitingContribution, reset } + ] = useCommitAnyContributionMutation(); + + const commitContribution = (row) => { + commit({ + autSig: state.authSig, + contribution: row + }); + }; const theme = useTheme(); return ( @@ -338,10 +318,14 @@ export const AutHubTasksTable = ({ header }) => { - {contributions?.length ? ( + {data?.length ? ( - {contributions?.map((row, index) => ( - + {data?.map((row, index) => ( + ))} ) : ( diff --git a/src/pages/Tasks/Shared/TaskDetails.tsx b/src/pages/Tasks/Shared/TaskDetails.tsx index b5dbfc7..7d6394a 100644 --- a/src/pages/Tasks/Shared/TaskDetails.tsx +++ b/src/pages/Tasks/Shared/TaskDetails.tsx @@ -9,17 +9,12 @@ import ArrowBackIosNewIcon from "@mui/icons-material/ArrowBackIosNew"; import { memo } from "react"; import { Link, useParams, useSearchParams } from "react-router-dom"; import { format } from "date-fns"; -import { getContributionTypeSubtitle } from "@utils/format-contribution-type"; const TaskDetails = ({ task }: any) => { const [searchParams] = useSearchParams(); const { hubAddress, autAddress } = useParams(); const isLoading = false; - const contributionType = getContributionTypeSubtitle( - task?.contributionType - ); - return ( <> {isLoading ? ( @@ -74,7 +69,7 @@ const TaskDetails = ({ task }: any) => { }} variant="body" > - {contributionType} + {task?.contributionType} {/* export const ContributionErrorMessage = (state) => state.contribution.errorMessage as string; +export const TaskTypes = (state) => state.contribution.taskTypes as TaskType[]; + export default contributionSlice.reducer; diff --git a/src/redux/reducers.ts b/src/redux/reducers.ts index 23617c2..7e5b6cb 100644 --- a/src/redux/reducers.ts +++ b/src/redux/reducers.ts @@ -5,6 +5,7 @@ import walletProvideReducer from "./WalletProvider/WalletProvider"; import pluginsReducer from "./plugins/plugins.reducer"; import interactionsReducer from "./interactions/interactions.reducer"; import contributionsReducer from "./contributions/contributions.reducer"; +import { contributionsApi } from "@api/contributions.api"; export const reducers = combineReducers({ ui: uiSliceReducer, @@ -12,7 +13,8 @@ export const reducers = combineReducers({ plugin: pluginsReducer, interaction: interactionsReducer, contribution: contributionsReducer, - walletProvider: walletProvideReducer + walletProvider: walletProvideReducer, + [contributionsApi.reducerPath]: contributionsApi.reducer, }); const rootReducer = (state, action) => { diff --git a/src/redux/store.ts b/src/redux/store.ts index 26db637..08318b9 100644 --- a/src/redux/store.ts +++ b/src/redux/store.ts @@ -2,12 +2,13 @@ import { configureStore } from "@reduxjs/toolkit"; import logger from "redux-logger"; import { reducers } from "./reducers"; +import { contributionsApi } from "@api/contributions.api"; export const store = configureStore({ middleware: (getDefaultMiddleware) => getDefaultMiddleware({ serializableCheck: false - }).concat(logger), + }).concat(logger, contributionsApi.middleware), reducer: reducers }); diff --git a/src/utils/format-contribution-type.tsx b/src/utils/format-contribution-type.tsx deleted file mode 100644 index f7dd1ad..0000000 --- a/src/utils/format-contribution-type.tsx +++ /dev/null @@ -1,33 +0,0 @@ -export const formatContributionType = (type: string) => { - switch (type) { - case "discord": - return "Discord"; - case "open": - return "Open Task"; - case "quiz": - return "Quiz"; - case "github": - return "GitHub"; - case "retweet": - return "Retweet"; - default: - return type; - } -}; - -export const getContributionTypeSubtitle = (type: string) => { - switch (type) { - case "discord": - return "Join Discord Task"; - case "open": - return "Open Task"; - case "quiz": - return "Quiz Task"; - case "github": - return "GitHub Task"; - case "retweet": - return "Retweet Task"; - default: - return type; - } -}; diff --git a/src/utils/hooks/GetContributions.tsx b/src/utils/hooks/GetContributions.tsx index 022ab6a..6d1c724 100644 --- a/src/utils/hooks/GetContributions.tsx +++ b/src/utils/hooks/GetContributions.tsx @@ -1,72 +1,105 @@ -/* eslint-disable no-debugger */ - import AutSDK, { BaseNFTModel, fetchMetadata, Hub, - TaskContribution, - TaskContributionNFT + TaskContributionNFT, + TaskFactoryContract } from "@aut-labs/sdk"; -import { QueryFunctionOptions, QueryResult } from "@apollo/client"; +import { + gql, + QueryFunctionOptions, + QueryResult, + useQuery +} from "@apollo/client"; import { useEffect, useState } from "react"; import { environment } from "@api/environment"; -import { AutOSHub } from "@api/models/hub.model"; import { useSelector } from "react-redux"; -import { Select } from "@mui/material"; -import { SelectedHub, SelectedHubAddress } from "@store/aut/aut.reducer"; -import { RootState } from "@react-three/fiber"; +import { SelectedHubAddress, SelectedHub } from "@store/aut/aut.reducer"; +import { TaskType } from "@api/models/task-type"; +import { TaskTypes } from "@store/contributions/contributions.reducer"; +import { ContributionFactory } from "@api/models/contribution.model"; -const fetchOnChainContributions = async ( - hubData: AutOSHub -): Promise => { - const sdk = await AutSDK.getInstance(); - const hubService: Hub = sdk.initService(Hub, hubData.properties.address); - const taskFactory = await hubService.getTaskFactory(); - const ids = (await taskFactory.functions.contributionIds()) as string[]; +const GET_HUB_CONTRIBUTIONS = gql` + query GetContributions($skip: Int, $first: Int, $where: Contribution_filter) { + contributions(skip: $skip, first: $first, where: $where) { + id + taskId + role + startDate + endDate + points + quantity + descriptionId + } + } +`; - const contributions = await Promise.all( - ids.map(async (id) => { - const _contribution = await taskFactory.functions.getContributionById(id); - const contribution = TaskContribution.mapFromTuple(_contribution as any); - const { uri } = await taskFactory.functions.getDescriptionById( - contribution.descriptionId - ); - const metadata = await fetchMetadata>( - uri, - environment.ipfsGatewayUrl - ); - return { - ...metadata, - properties: { - ...metadata.properties, - ...contribution - } - }; - }) - ); - return contributions; +const contributionsMetadata = ( + contributions: any[], + taskFactory: TaskFactoryContract, + taskTypes: TaskType[] +) => { + return contributions.map(async (contribution) => { + const { uri } = await taskFactory.functions.getDescriptionById( + contribution?.descriptionId + ); + let metadata = await fetchMetadata>( + uri, + environment.ipfsGatewayUrl + ); + metadata = metadata || ({ properties: {} } as BaseNFTModel); + return ContributionFactory(metadata, contribution, taskTypes); + }); }; const useQueryContributions = (props: QueryFunctionOptions = {}) => { - const [contributions, setContributions] = useState([]); - const [loadingMetadata, setLoadingMetadata] = useState(false); + const taskTypes = useSelector(TaskTypes); const selectedHubAddress = useSelector(SelectedHubAddress); const hubData = useSelector(SelectedHub(selectedHubAddress)); + const { data, loading, ...rest } = useQuery(GET_HUB_CONTRIBUTIONS, { + skip: !hubData?.properties?.address || !taskTypes.length, + fetchPolicy: "cache-and-network", + variables: { + ...props.variables, + where: { + hubAddress: hubData?.properties?.address, + ...(props.variables?.where || {}) + } + }, + ...props + }); + + const [contributions, setContributions] = useState([]); + const [loadingMetadata, setLoadingMetadata] = useState(true); + useEffect(() => { - if (hubData) { + if ( + hubData?.properties?.address && + data?.contributions?.length && + taskTypes.length + ) { const fetch = async () => { + const sdk = await AutSDK.getInstance(); + const hubService: Hub = sdk.initService( + Hub, + hubData.properties.address + ); + const taskFactory = await hubService.getTaskFactory(); setLoadingMetadata(true); - const contributions = await fetchOnChainContributions(hubData); + const contributions = await Promise.all( + contributionsMetadata(data?.contributions, taskFactory, taskTypes) + ); setLoadingMetadata(false); setContributions(contributions); }; fetch(); } - }, [hubData]); + }, [hubData?.properties?.address, data, taskTypes]); return { data: contributions || [], - loading: loadingMetadata + ...rest, + loading: loading || loadingMetadata } as QueryResult; }; diff --git a/src/utils/hooks/useQueryTaskTypes.tsx b/src/utils/hooks/useQueryTaskTypes.tsx new file mode 100644 index 0000000..7d3d867 --- /dev/null +++ b/src/utils/hooks/useQueryTaskTypes.tsx @@ -0,0 +1,74 @@ +import { BaseNFTModel, fetchMetadata } from "@aut-labs/sdk"; +import { + gql, + QueryFunctionOptions, + QueryResult, + useQuery +} from "@apollo/client"; +import { useEffect, useState } from "react"; +import { environment } from "@api/environment"; +import { useDispatch } from "react-redux"; +import { TaskType } from "@api/models/task-type"; +import { updateContributionState } from "@store/contributions/contributions.reducer"; + +const GET_TASK_TYPES = gql` + query GetTaskTypes($skip: Int, $first: Int, $where: HubAdmin_filter) { + tasks(skip: $skip, first: $first, where: $where) { + id + metadataUri + taskId + creator + } + } +`; + +const fetchTaskTypesMetadata = (taskTypes: TaskType[]) => { + return taskTypes.map(async ({ id, metadataUri, taskId, creator }) => { + let metadata = await fetchMetadata>( + metadataUri, + environment.ipfsGatewayUrl + ); + metadata = metadata || ({ properties: {} } as BaseNFTModel); + return { + id, + metadataUri, + taskId, + creator, + metadata + }; + }); +}; + +const useQueryTaskTypes = (props: QueryFunctionOptions = {}) => { + const dispatch = useDispatch(); + const { data, loading, ...rest } = useQuery(GET_TASK_TYPES, { + fetchPolicy: "cache-and-network", + ...props + }); + + const [taskTypes, setTaskTypes] = useState([]); + const [loadingMetadata, setLoadingMetadata] = useState(false); + + useEffect(() => { + if (data?.tasks?.length) { + const fetch = async () => { + setLoadingMetadata(true); + const taskTypes = await Promise.all([ + ...fetchTaskTypesMetadata(data?.tasks) + ]); + dispatch(updateContributionState({ taskTypes })); + setLoadingMetadata(false); + setTaskTypes(taskTypes); + }; + fetch(); + } + }, [data]); + + return { + data: taskTypes || [], + ...rest, + loading: loadingMetadata || loading + } as QueryResult; +}; + +export default useQueryTaskTypes; From 902edfe4044e78864b295f8db796ce556aca5408 Mon Sep 17 00:00:00 2001 From: mrtmeeseeks Date: Tue, 12 Nov 2024 23:50:28 +0200 Subject: [PATCH 02/10] added commit contribution for open task and quiz --- src/api/contributions.api.ts | 156 +----- .../contribution-types/quiz.model.model.ts | 2 +- src/index.tsx | 2 +- .../AutID/AutHub/AutHubContributionsTable.tsx | 94 ++-- .../Tasks/Contributions/Contributions.tsx | 79 ++- src/pages/Tasks/OpenTask/OpenTask.tsx | 520 ++++++++---------- src/pages/Tasks/QuizTask/QuizTask.tsx | 251 +++------ src/pages/Tasks/Shared/TaskDetails.tsx | 141 ++--- src/utils/hooks/GetContributions.tsx | 20 +- .../hooks/useQueryContributionCommits.tsx | 106 ++++ 10 files changed, 617 insertions(+), 754 deletions(-) create mode 100644 src/utils/hooks/useQueryContributionCommits.tsx diff --git a/src/api/contributions.api.ts b/src/api/contributions.api.ts index 388f3bc..a3aadb4 100644 --- a/src/api/contributions.api.ts +++ b/src/api/contributions.api.ts @@ -1,10 +1,6 @@ import { TaskContributionNFT } from "@aut-labs/sdk"; import { BaseQueryApi, createApi } from "@reduxjs/toolkit/query/react"; import { AuthSig } from "@aut-labs/connector/lib/esm/aut-sig"; -import { DiscordGatheringContribution } from "./models/contribution-types/discord-gathering.model"; -import { OpenTaskContribution } from "./models/contribution-types/open-task.model"; -import { QuizTaskContribution } from "./models/contribution-types/quiz.model.model"; -import { RetweetContribution } from "./models/contribution-types/retweet.model"; import axios from "axios"; import { environment } from "./environment"; @@ -29,11 +25,10 @@ const commitContribution = async ( autSig: AuthSig, contribution: TaskContributionNFT, message: string, + hubAddress: string, api: BaseQueryApi ) => { try { - const state: any = api.getState() as any; - const hubAddress = state.aut.selectedHubAddress; const response = _commitContribution({ autSig: autSig, message: message, @@ -50,86 +45,27 @@ const commitContribution = async ( } }; -const commitOpenTaskContribution = async ( - { - contribution, - autSig - }: { contribution: OpenTaskContribution; autSig: AuthSig }, - api: BaseQueryApi -) => { - const secredMessage = "secred"; - return commitContribution(autSig, contribution, secredMessage, api); -}; - -const commitTwitterRetweetContribution = async ( - { - contribution, - autSig - }: { contribution: RetweetContribution; autSig: AuthSig }, - api: BaseQueryApi -) => { - const secredMessage = "secred"; - return commitContribution(autSig, contribution, secredMessage, api); -}; - -const commitDiscordGatheringContribution = async ( - { - contribution, - autSig - }: { contribution: DiscordGatheringContribution; autSig: AuthSig }, - api: BaseQueryApi -) => { - const secredMessage = "secred"; - return commitContribution(autSig, contribution, secredMessage, api); -}; - -const commitQuizContribution = async ( - { - contribution, - autSig - }: { contribution: QuizTaskContribution; autSig: AuthSig }, - api: BaseQueryApi -) => { - const secredMessage = "secred"; - return commitContribution(autSig, contribution, secredMessage, api); -}; - const commitAnyContribution = async ( { contribution, - autSig - }: { contribution: TaskContributionNFT; autSig: AuthSig }, + autSig, + message, + hubAddress + }: { + contribution: TaskContributionNFT; + autSig: AuthSig; + message: string; + hubAddress: string; + }, api: BaseQueryApi ) => { - if (contribution instanceof OpenTaskContribution) { - return commitOpenTaskContribution({ contribution, autSig }, api); - } else if (contribution instanceof DiscordGatheringContribution) { - return commitDiscordGatheringContribution({ contribution, autSig }, api); - } else if (contribution instanceof RetweetContribution) { - return commitTwitterRetweetContribution({ contribution, autSig }, api); - } else if (contribution instanceof QuizTaskContribution) { - return commitQuizContribution({ contribution, autSig }, api); - } else { - throw new Error("Unknown contribution type"); - } + return commitContribution(autSig, contribution, message, hubAddress, api); }; export const contributionsApi = createApi({ reducerPath: "contributionsApi", - baseQuery: (args, api, extraOptions) => { + baseQuery: (args, api) => { const { url, body } = args; - if (url === "commitOpenTaskContribution") { - return commitOpenTaskContribution(body, api); - } - if (url === "commitDiscordGatheringContribution") { - return commitDiscordGatheringContribution(body, api); - } - if (url === "commitTwitterRetweetContribution") { - return commitTwitterRetweetContribution(body, api); - } - if (url === "commitQuizContribution") { - return commitQuizContribution(body, api); - } if (url === "commitAnyContribution") { return commitAnyContribution(body, api); } @@ -137,69 +73,15 @@ export const contributionsApi = createApi({ data: "Test" }; }, - tagTypes: ["Contributions"], + tagTypes: [], endpoints: (builder) => ({ - commitOpenTaskContribution: builder.mutation< - void, - { - autSig: AuthSig; - contribution: OpenTaskContribution; - } - >({ - query: (body) => { - return { - body, - url: "commitOpenTaskContribution" - }; - } - }), - commitDiscordGatheringContribution: builder.mutation< - void, - { - autSig: AuthSig; - contribution: DiscordGatheringContribution; - } - >({ - query: (body) => { - return { - body, - url: "commitDiscordGatheringContribution" - }; - } - }), - commitTwitterRetweetContribution: builder.mutation< - void, - { - autSig: AuthSig; - contribution: RetweetContribution; - } - >({ - query: (body) => { - return { - body, - url: "commitTwitterRetweetContribution" - }; - } - }), - commitQuizContribution: builder.mutation< - void, - { - autSig: AuthSig; - contribution: QuizTaskContribution; - } - >({ - query: (body) => { - return { - body, - url: "commitQuizContribution" - }; - } - }), commitAnyContribution: builder.mutation< void, { autSig: AuthSig; contribution: TaskContributionNFT; + message: string; + hubAddress: string; } >({ query: (body) => { @@ -212,10 +94,4 @@ export const contributionsApi = createApi({ }) }); -export const { - useCommitAnyContributionMutation, - useCommitTwitterRetweetContributionMutation, - useCommitOpenTaskContributionMutation, - useCommitDiscordGatheringContributionMutation, - useCommitQuizContributionMutation -} = contributionsApi; +export const { useCommitAnyContributionMutation } = contributionsApi; diff --git a/src/api/models/contribution-types/quiz.model.model.ts b/src/api/models/contribution-types/quiz.model.model.ts index 6e58513..13fde8f 100644 --- a/src/api/models/contribution-types/quiz.model.model.ts +++ b/src/api/models/contribution-types/quiz.model.model.ts @@ -4,7 +4,7 @@ import { TaskContributionProperties } from "@aut-labs/sdk"; -interface QuizQuestionsAndAnswers { +export interface QuizQuestionsAndAnswers { question: string; questionType: string; answers: { diff --git a/src/index.tsx b/src/index.tsx index 51ac383..10a35bd 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -45,7 +45,7 @@ root.render( diff --git a/src/pages/AutID/AutHub/AutHubContributionsTable.tsx b/src/pages/AutID/AutHub/AutHubContributionsTable.tsx index a6087db..ab94b2c 100644 --- a/src/pages/AutID/AutHub/AutHubContributionsTable.tsx +++ b/src/pages/AutID/AutHub/AutHubContributionsTable.tsx @@ -1,9 +1,8 @@ -import { memo, useEffect, useMemo } from "react"; +import { memo, useMemo } from "react"; import Box from "@mui/material/Box"; import ArrowIcon from "@assets/autos/move-right.svg?react"; import { - Link as BtnLink, Paper, Stack, SvgIcon, @@ -20,12 +19,14 @@ import { } from "@mui/material"; import { format } from "date-fns"; import { AutOsButton } from "@components/AutButton"; -import { Link } from "react-router-dom"; -import { useDispatch } from "react-redux"; -import { TaskStatus } from "@store/model"; import useQueryContributions from "@utils/hooks/GetContributions"; import { useCommitAnyContributionMutation } from "@api/contributions.api"; import { useWalletConnector } from "@aut-labs/connector"; +import useQueryContributionCommits, { + ContributionCommit +} from "@utils/hooks/useQueryContributionCommits"; +import { TaskContributionNFT } from "@aut-labs/sdk"; +import { Link } from "react-router-dom"; const StyledTableCell = styled(TableCell)(({ theme }) => ({ [`&.${tableCellClasses.head}, &.${tableCellClasses.body}`]: { @@ -48,27 +49,27 @@ const StyledTableRow = styled(TableRow)(({ theme }) => ({ })); interface TableListItemProps { - row: any; - commitContribution: (row: any) => void; + contribution: TaskContributionNFT & { contributionType?: string }; + commit: ContributionCommit; } const TableListItem = memo( - ({ row, commitContribution }: TableListItemProps) => { + ({ contribution, commit }: TableListItemProps) => { const theme = useTheme(); const startDate = useMemo(() => { return format( - new Date(row?.properties?.startDate * 1000), + new Date(contribution?.properties?.startDate * 1000), "dd.MM.yy" ).toString(); - }, [row?.properties?.startDate]); + }, [contribution?.properties?.startDate]); const endDate = useMemo(() => { return format( - new Date(row?.properties?.endDate * 1000), + new Date(contribution?.properties?.endDate * 1000), "dd.MM.yy" ).toString(); - }, [row?.properties?.endDate]); + }, [contribution?.properties?.endDate]); return ( - {row?.name} + {contribution?.name} - {row?.description} + {contribution?.description} @@ -116,13 +117,13 @@ const TableListItem = memo( }} > - {row?.contributionType} + {contribution?.contributionType} - {`${row?.properties?.points || 0} ${row?.properties?.points === 1 ? "pt" : "pts"}`} + {`${contribution?.properties?.points || 0} ${contribution?.properties?.points === 1 ? "pt" : "pts"}`} @@ -156,7 +157,7 @@ const TableListItem = memo( alignItems: "center" }} > - {row?.status !== TaskStatus.Created ? ( + {!commit ? ( commitContribution(row)} + relative="path" + to={`contribution/${contribution?.properties?.id}`} + component={Link} > Claim @@ -202,20 +202,39 @@ const TableListItem = memo( ); export const AutHubTasksTable = ({ header }) => { - const dispatch = useDispatch(); const { state } = useWalletConnector(); - const { - data, - loading: isLoading, - refetch - } = useQueryContributions({ + const { data, loading: isLoading } = useQueryContributions({ variables: { skip: 0, take: 1000 } }); + const { data: commits, loading: isLoadingCommits } = + useQueryContributionCommits({ + skip: !state?.address, + variables: { + skip: 0, + take: 1000, + where: { + who: state?.address?.toLowerCase() + } + } + }); + + const contributionWithCommits = useMemo(() => { + return (data || []).map((contribution) => { + const commit = (commits || []).find( + (commit) => commit?.contribution?.id === contribution.properties.id + ); + return { + contribution, + commit + }; + }); + }, [data, commits]); + const [ commit, { error, isError, isSuccess, isLoading: commitingContribution, reset } @@ -224,7 +243,8 @@ export const AutHubTasksTable = ({ header }) => { const commitContribution = (row) => { commit({ autSig: state.authSig, - contribution: row + contribution: row, + message: "secret" }); }; @@ -318,15 +338,17 @@ export const AutHubTasksTable = ({ header }) => { - {data?.length ? ( + {contributionWithCommits?.length ? ( - {data?.map((row, index) => ( - - ))} + {contributionWithCommits?.map( + ({ contribution, commit }, index) => ( + + ) + )} ) : ( { - let contribution = useSelector(SelectedContribution); - const contributions = useSelector(AllContributions); + const { state } = useWalletConnector(); const { id } = useParams<{ id: string }>(); + const { data, loading: isLoading } = useQueryContributions({ + variables: { + skip: 0, + take: 1000, + where: { + id + } + } + }); - if (!contribution) { - contribution = contributions.find((c) => c.id === id); - } - return ( - <> - {contribution?.contributionType === "open" && ( - - )} - {contribution?.contributionType === "discord" && ( - - )} - {contribution?.contributionType === "quiz" && ( - - )} - {contribution?.contributionType === "retweet" && ( - - )} - - ); + const { data: commits, loading: isLoadingCommits } = + useQueryContributionCommits({ + skip: !state?.address, + variables: { + skip: 0, + take: 1000, + where: { + who: state?.address?.toLowerCase(), + contribution_: { + id + } + } + } + }); + + const commit = useMemo(() => { + if (commits) { + return commits[0]; + } + return null; + }, [commits]); + + const contributionTemplate = useMemo(() => { + const contribution = data?.[0]; + if (!contribution) return null; + if (contribution instanceof OpenTaskContribution) { + return ; + } else if (contribution instanceof QuizTaskContribution) { + return ; + } else { + return "Contribution type not supported"; + } + }, [data, commit]); + + return <>{contributionTemplate}; }; export default Contributions; diff --git a/src/pages/Tasks/OpenTask/OpenTask.tsx b/src/pages/Tasks/OpenTask/OpenTask.tsx index 398f1c2..81c6e37 100644 --- a/src/pages/Tasks/OpenTask/OpenTask.tsx +++ b/src/pages/Tasks/OpenTask/OpenTask.tsx @@ -1,7 +1,3 @@ -/* eslint-disable no-useless-escape */ -/* eslint-disable max-len */ - -import AutLoading from "@components/AutLoading"; import { Box, Card, @@ -16,24 +12,22 @@ import { AutTextField } from "@theme/field-text-styles"; import { memo, useEffect, useMemo, useState } from "react"; import { Controller, useForm } from "react-hook-form"; import { useSearchParams, useParams, useNavigate } from "react-router-dom"; -import TaskDetails from "../Shared/TaskDetails"; -import SuccessDialog from "@components/Dialog/SuccessPopup"; -import { useAccount } from "wagmi"; import { FormHelperText } from "@components/Fields/AutFields"; import { ipfsCIDToHttpUrl } from "@utils/ipfs"; import { TaskFileUpload } from "@components/FileUpload"; import { AutOsButton } from "@components/AutButton"; import { TaskStatus } from "@store/model"; -import LoadingDialog from "@components/Dialog/LoadingPopup"; -import { updateContributionById } from "@store/contributions/contributions.reducer"; -import { useDispatch } from "react-redux"; import SubmitDialog from "@components/Dialog/SubmitDialog"; +import { OpenTaskContribution } from "@api/models/contribution-types/open-task.model"; +import { ContributionCommit } from "@utils/hooks/useQueryContributionCommits"; +import { useCommitAnyContributionMutation } from "@api/contributions.api"; +import { useWalletConnector } from "@aut-labs/connector"; +import ErrorDialog from "@components/Dialog/ErrorPopup"; +import TaskDetails from "../Shared/TaskDetails"; interface UserSubmitContentProps { - contribution: any; - userAddress: string; - isLoadingTasks: boolean; - submission?: any; + contribution: OpenTaskContribution; + commit: ContributionCommit; } const errorTypes = { @@ -42,87 +36,179 @@ const errorTypes = { const UserSubmitContent = ({ contribution, - userAddress, - isLoadingTasks + commit }: UserSubmitContentProps) => { - const [loading, setLoading] = useState(false); - const dispatch = useDispatch(); + const { state } = useWalletConnector(); const [searchParams] = useSearchParams(); const [initialized, setInitialized] = useState(false); const navigate = useNavigate(); - const [openSubmitSuccess, setOpenSubmitSuccess] = useState(false); - const { control, handleSubmit, formState, setValue } = useForm({ + const { control, handleSubmit, formState, setValue, getValues } = useForm({ mode: "onChange", defaultValues: { - openTask: null, - attachment: null + description: "", + attachment: "" } }); const { autAddress, hubAddress } = useParams(); + const contributionSubmitContent = useMemo(() => { + let userSubmit = null; + try { + userSubmit = JSON.parse(commit.data); + } catch (e) { + // pass + } + return userSubmit; + }, [commit]); + useEffect(() => { - if (!initialized && contribution) { - setValue("openTask", contribution.submission?.description); + if (!initialized && contributionSubmitContent) { + let userSubmit = { + description: "", + attachment: "" + }; + try { + userSubmit = JSON.parse(commit.data); + } catch (e) { + // pass + } + setValue("description", userSubmit.description); + setValue("attachment", userSubmit.attachment); setInitialized(true); } - }, [initialized, contribution]); + }, [initialized, contributionSubmitContent]); - // const [submitTask, { isSuccess, error, isError, isLoading, reset }] = - // useSubmitOpenTaskMutation(); + const [commitContribution, { error, isError, isSuccess, isLoading, reset }] = + useCommitAnyContributionMutation(); - // useEffect(() => { - // if (isSuccess) { - // setOpenSubmitSuccess(true); - // } - // }, [isSuccess]); - - const onSubmit = async (values) => { - setLoading(true); - await new Promise((resolve) => setTimeout(resolve, 3000)); - dispatch( - updateContributionById({ - id: contribution?.id, - data: { - ...contribution, - status: TaskStatus.Submitted - } - }) - ); - setLoading(false); - setOpenSubmitSuccess(true); - - // submitTask({ - // userAddress, - // file: values.attachment, - // task: { - // ...task, - // submission: { - // name: "Open task submission", - // description: values.openTask, - // properties: {} as any - // } - // }, - // onboardingQuestAddress: searchParams.get( - // RequiredQueryParams.OnboardingQuestAddress - // ), - // pluginAddress: plugin.pluginAddress, - // pluginDefinitionId: plugin.pluginDefinitionId - // }); + const onSubmit = () => { + const description = getValues("description"); + const attachment = getValues("attachment"); + commitContribution({ + autSig: state.authSig, + contribution, + message: JSON.stringify({ description, attachment }), + hubAddress + }); }; - // const attachmentType = useMemo(() => { - // // @ts-ignore - // return task.properties.attachmentType; - // }, [task]); + const textRequiredTemplate = useMemo(() => { + if (!contribution.properties.textRequired) return null; + return ( + { + return ( + + ); + }} + /> + ); + }, [contribution.properties.textRequired]); - // const textRequired = useMemo(() => { - // // @ts-ignore - // return task.properties.textRequired; - // }, [task]); + const attachmentTypeTemplate = useMemo(() => { + const attachmentType = contribution.properties.attachmentType; + if (!attachmentType) return null; - const textRequired = contribution?.properties?.textRequired; - const attachmentType = contribution?.properties?.attachmentType; + if (attachmentType === "url") { + return ( + <> + + URL + + { + return ( + + } + /> + ); + }} + /> + + ); + } else if (attachmentType === "image" || attachmentType === "text") { + return ( + <> + + {`Upload a file ${ + attachmentType === "image" + ? "(.png, .jpg, .jpeg)" + : "(.doc, .docx, .txt, .pdf)" + }`} + + { + return ( +
+ { + if (file) { + onChange(file); + } else { + onChange(null); + } + }} + /> +
+ ); + }} + /> + + ); + } + }, [contribution.properties.attachmentType]); return ( - {/* reset()} open={isError} message={error} /> - */} - {/* */} + reset()} + open={isError} + message={error || "An error occurred"} + /> { - if (!loading) { - setOpenSubmitSuccess(false); + if (!isLoading) { + reset(); navigate({ pathname: `/${autAddress}/hub/${hubAddress}`, search: searchParams.toString() @@ -165,8 +253,7 @@ const UserSubmitContent = ({ }} > - {contribution?.status === TaskStatus.Created || - contribution?.status === TaskStatus.Taken ? ( + {!commit ? ( {contribution?.description} - {textRequired && ( - { - return ( - - ); - }} - /> - )} - {attachmentType === "url" && ( - <> - - URL - - { - return ( - - } - /> - ); - }} - /> - - )} - {(attachmentType === "image" || attachmentType === "text") && ( - <> - - {`Upload a file ${ - attachmentType === "image" - ? "(.png, .jpg, .jpeg)" - : "(.doc, .docx, .txt, .pdf)" - }`} - - { - return ( -
- { - if (file) { - onChange(file); - } else { - onChange(null); - } - }} - /> -
- ); - }} - /> - - )} + {textRequiredTemplate} + {attachmentTypeTemplate}
) : ( @@ -329,11 +296,12 @@ const UserSubmitContent = ({ flexDirection: "column" }} > - {(contribution as any)?.status === TaskStatus.Finished && ( + {/* this will be implemented once give contribution is completed */} + {/* {contribution?.status === TaskStatus.Finished && ( - )} + )} */} - {contribution?.description} + {contributionSubmitContent?.description} Contribution Description - { - // @ts-ignore - task?.properties?.attachmentRequired && ( - - + + - - Open attachment - - - - Attachment File - - - ) - } + Open attachment + + + + Attachment File + +
+ )} )} @@ -393,8 +358,7 @@ const UserSubmitContent = ({ } }} > - {(contribution?.status === TaskStatus.Created || - contribution?.status === TaskStatus.Taken) && ( + {!commit && ( - {" "} - Confirm + Submit @@ -431,48 +391,13 @@ const UserSubmitContent = ({ ); }; -const OpenTask = ({ contribution }: any) => { - const [searchParams] = useSearchParams(); - const { address: userAddress } = useAccount(); - - const params = useParams(); - - // const { task, submission, isLoading } = useGetAllTasksPerQuestQuery( - // { - // userAddress, - // isAdmin: false, - // pluginAddress: searchParams.get( - // RequiredQueryParams.OnboardingQuestAddress - // ), - // questId: +searchParams.get(RequiredQueryParams.QuestId) - // }, - // { - // selectFromResult: ({ data, isLoading, isFetching }) => ({ - // isLoading: isLoading || isFetching, - // submission: (data?.submissions || []).find((t) => { - // const [pluginType] = location.pathname.split("/").splice(-2); - // return ( - // t.submitter === userAddress && - // t.taskId === +params?.taskId && - // PluginDefinitionType[pluginType] === - // taskTypes[t.taskType].pluginType - // ); - // }), - // task: (data?.tasks || []).find((t) => { - // const [pluginType] = location.pathname.split("/").splice(-2); - // return ( - // t.taskId === +params?.taskId && - // PluginDefinitionType[pluginType] === - // taskTypes[t.taskType].pluginType - // ); - // }) - // }) - // } - // ); - - const isLoading = false; - const submission = null; - +const OpenTask = ({ + contribution, + commit +}: { + contribution: OpenTaskContribution; + commit: ContributionCommit; +}) => { return ( { position: "relative" }} > - {contribution ? ( - <> - - - - ) : ( - - )} + + ); }; diff --git a/src/pages/Tasks/QuizTask/QuizTask.tsx b/src/pages/Tasks/QuizTask/QuizTask.tsx index 6e969f1..8116797 100644 --- a/src/pages/Tasks/QuizTask/QuizTask.tsx +++ b/src/pages/Tasks/QuizTask/QuizTask.tsx @@ -1,6 +1,5 @@ import AutLoading from "@components/AutLoading"; import ErrorDialog from "@components/Dialog/ErrorPopup"; -import LoadingDialog from "@components/Dialog/LoadingPopup"; import { Box, Card, @@ -12,18 +11,20 @@ import { styled, Typography } from "@mui/material"; -import { memo, useEffect, useState } from "react"; -import { Controller, useFieldArray, useForm, useWatch } from "react-hook-form"; -import { useDispatch, useSelector } from "react-redux"; +import { Fragment, memo, useEffect, useMemo, useState } from "react"; +import { Controller, useForm, useWatch } from "react-hook-form"; import { useNavigate, useParams, useSearchParams } from "react-router-dom"; -import SuccessDialog from "@components/Dialog/SuccessPopup"; -import { useAccount } from "wagmi"; import TaskDetails from "../Shared/TaskDetails"; -import { StepperButton } from "@components/StepperButton"; import { AutOsButton } from "@components/AutButton"; import { TaskStatus } from "@store/model"; -import { updateContributionById } from "@store/contributions/contributions.reducer"; import SubmitDialog from "@components/Dialog/SubmitDialog"; +import { + QuizQuestionsAndAnswers, + QuizTaskContribution +} from "@api/models/contribution-types/quiz.model.model"; +import { ContributionCommit } from "@utils/hooks/useQueryContributionCommits"; +import { useCommitAnyContributionMutation } from "@api/contributions.api"; +import { useWalletConnector } from "@aut-labs/connector"; export const taskStatuses: any = { [TaskStatus.Created]: { @@ -63,11 +64,12 @@ const GridRow = styled(Box)({ gridGap: "8px" }); -const Row = styled(Box)({ - display: "flex", - justifyContent: "flex-end", - width: "100%" -}); +const alphabetize = { + 0: "A", + 1: "B", + 2: "C", + 3: "D" +}; const Answers = memo(({ control, questionIndex, answers, taskStatus }: any) => { const values = useWatch({ @@ -75,18 +77,11 @@ const Answers = memo(({ control, questionIndex, answers, taskStatus }: any) => { control }); - const alphabetize = { - 0: "A", - 1: "B", - 2: "C", - 3: "D" - }; - return ( {answers.map((answer, index) => { return ( - <> + {answer?.value && ( { /> )} - - ); - })} - - ); -}); - -const AnswersAdminView = memo(({ questionIndex, answers }: any) => { - return ( - - {answers.map((answer, index) => { - return ( - - - - {answer?.value} - - + ); })} ); }); -const QuizTask = ({ contribution }: any) => { +const QuizTask = ({ + contribution, + commit +}: { + contribution: QuizTaskContribution; + commit: ContributionCommit; +}) => { + const navigate = useNavigate(); + const { state } = useWalletConnector(); const [searchParams] = useSearchParams(); - const [loading, setLoading] = useState(false); - const dispatch = useDispatch(); - // const isAdmin = useSelector(IsAdmin); - const isAdmin = false; - const { address: userAddress } = useAccount(); - const params = useParams(); const [initialized, setInitialized] = useState(false); - const navigate = useNavigate(); - const [openSubmitSuccess, setOpenSubmitSuccess] = useState(false); const { autAddress, hubAddress } = useParams(); - - // const { task, isLoading: isLoadingTasks } = useGetAllTasksPerQuestQuery( - // { - // userAddress, - // isAdmin, - // pluginAddress: searchParams.get( - // RequiredQueryParams.OnboardingQuestAddress - // ), - // questId: +searchParams.get(RequiredQueryParams.QuestId) - // }, - // { - // selectFromResult: ({ data, isLoading, isFetching }) => ({ - // isLoading: isLoading || isFetching, - // task: (data?.tasks || []).find((t) => { - // const [pluginType] = location.pathname.split("/").splice(-2); - // return ( - // t.taskId === +params?.taskId && - // PluginDefinitionType[pluginType] === - // taskTypes[t.taskType].pluginType - // ); - // }) - // }) - // } - // ); - const { control, handleSubmit, getValues, setValue, formState } = useForm({ mode: "onChange", defaultValues: { @@ -223,54 +157,52 @@ const QuizTask = ({ contribution }: any) => { } }); - const { fields, append, remove } = useFieldArray({ - control, - name: "questions" - }); + const questionsWithUserAnswers = useMemo(() => { + let answers: QuizQuestionsAndAnswers[] = []; + try { + answers = JSON.parse(commit.data); + } catch (e) { + // pass + } + if (answers.length === 0 || !commit) + return contribution.properties.questions; + return contribution.properties.questions.map((question) => { + const userAnswer = answers.find( + (answer) => answer.question === question.question + ); + return { + ...question, + answers: question.answers.map((answer) => { + const userAnswerValue = userAnswer.answers.find( + (a) => a.value === answer.value + ); + return { + ...answer, + correct: userAnswerValue?.correct + }; + }) + }; + }); + }, [contribution, commit]); useEffect(() => { - if (!initialized && contribution) { - setValue( - "questions", - (contribution as any)?.properties?.questions - ); + if (!initialized && questionsWithUserAnswers?.length) { + setValue("questions", questionsWithUserAnswers); setInitialized(true); } - }, [initialized, contribution]); - - // const [submitTask, { isSuccess, error, isError, isLoading, reset }] = - // useSubmitQuizTaskMutation(); + }, [initialized, questionsWithUserAnswers]); - // useEffect(() => { - // if (isSuccess) { - // setOpenSubmitSuccess(true); - // } - // }, [isSuccess]); + const [commitContribution, { error, isError, isSuccess, isLoading, reset }] = + useCommitAnyContributionMutation(); - const onSubmit = async () => { - setLoading(true); - await new Promise((resolve) => setTimeout(resolve, 3000)); - dispatch( - updateContributionById({ - id: contribution.id, - data: { - ...contribution, - status: TaskStatus.Submitted - } - }) - ); - setLoading(false); - setOpenSubmitSuccess(true); - // submitTask({ - // userAddress, - // task, - // questionsAndAnswers: values.questions, - // onboardingQuestAddress: searchParams.get( - // RequiredQueryParams.OnboardingQuestAddress - // ), - // pluginAddress: plugin.pluginAddress, - // pluginDefinitionId: plugin.pluginDefinitionId - // }); + const onSubmit = () => { + const answers = getValues("questions"); + commitContribution({ + autSig: state.authSig, + contribution, + message: JSON.stringify(answers), + hubAddress + }); }; return ( @@ -285,39 +217,26 @@ const QuizTask = ({ contribution }: any) => { position: "relative" }} > - {/* reset()} open={isError} message={error} /> - */} - {/* - { - setOpenSubmitSuccess(false); - navigate({ - pathname: "/quest", - search: searchParams.toString() - }); - }} - > */} - reset()} + open={isError} + message={error || "An error occurred"} + /> + { - if (!loading) { - setOpenSubmitSuccess(false); + if (!isLoading) { + reset(); navigate({ pathname: `/${autAddress}/hub/${hubAddress}`, search: searchParams.toString() @@ -327,7 +246,7 @@ const QuizTask = ({ contribution }: any) => { > {contribution ? ( <> - + { } }} > - {( - (contribution as any)?.metadata?.properties?.questions as any[] - )?.map((question, questionIndex) => ( + {questionsWithUserAnswers.map((question, questionIndex) => ( { control={control} answers={question?.answers} questionIndex={questionIndex} - taskStatus={contribution?.status} + // taskStatus={contribution?.status} > @@ -392,11 +309,7 @@ const QuizTask = ({ contribution }: any) => { sx={{ width: "100px" }} - disabled={ - !formState.isValid || - contribution?.status !== TaskStatus.Created - // || isLoadingTasks - } + disabled={!formState.isValid} onClick={handleSubmit(onSubmit)} > diff --git a/src/pages/Tasks/Shared/TaskDetails.tsx b/src/pages/Tasks/Shared/TaskDetails.tsx index 7d6394a..7fbf5b3 100644 --- a/src/pages/Tasks/Shared/TaskDetails.tsx +++ b/src/pages/Tasks/Shared/TaskDetails.tsx @@ -1,85 +1,90 @@ -import { - Box, - Button, - CircularProgress, - Stack, - Typography -} from "@mui/material"; +import { Box, Button, Stack, Typography } from "@mui/material"; import ArrowBackIosNewIcon from "@mui/icons-material/ArrowBackIosNew"; import { memo } from "react"; -import { Link, useParams, useSearchParams } from "react-router-dom"; -import { format } from "date-fns"; +import { Link, useParams } from "react-router-dom"; +import { TaskContributionNFT } from "@aut-labs/sdk"; +import OverflowTooltip from "@components/OverflowTooltip"; -const TaskDetails = ({ task }: any) => { - const [searchParams] = useSearchParams(); +const TaskDetails = ({ + contribution +}: { + contribution: TaskContributionNFT & { contributionType?: string }; +}) => { const { hubAddress, autAddress } = useParams(); - const isLoading = false; return ( <> - {isLoading ? ( - - ) : ( - - - - - {task?.name} - - - - + + + + {contribution?.name} + - {/* */} - - )} + variant="body" + > + {contribution?.contributionType} + + + {/* + + */} +
); }; diff --git a/src/utils/hooks/GetContributions.tsx b/src/utils/hooks/GetContributions.tsx index 6d1c724..b370259 100644 --- a/src/utils/hooks/GetContributions.tsx +++ b/src/utils/hooks/GetContributions.tsx @@ -11,13 +11,14 @@ import { QueryResult, useQuery } from "@apollo/client"; -import { useEffect, useState } from "react"; +import { useEffect, useMemo, useState } from "react"; import { environment } from "@api/environment"; import { useSelector } from "react-redux"; import { SelectedHubAddress, SelectedHub } from "@store/aut/aut.reducer"; import { TaskType } from "@api/models/task-type"; import { TaskTypes } from "@store/contributions/contributions.reducer"; import { ContributionFactory } from "@api/models/contribution.model"; +import { useParams } from "react-router-dom"; const GET_HUB_CONTRIBUTIONS = gql` query GetContributions($skip: Int, $first: Int, $where: Contribution_filter) { @@ -55,14 +56,19 @@ const contributionsMetadata = ( const useQueryContributions = (props: QueryFunctionOptions = {}) => { const taskTypes = useSelector(TaskTypes); const selectedHubAddress = useSelector(SelectedHubAddress); - const hubData = useSelector(SelectedHub(selectedHubAddress)); + const { hubAddress: _hubAddress } = useParams<{ hubAddress: string }>(); + + const hubAddress = useMemo(() => { + return selectedHubAddress || _hubAddress; + }, [_hubAddress, selectedHubAddress]); + const { data, loading, ...rest } = useQuery(GET_HUB_CONTRIBUTIONS, { - skip: !hubData?.properties?.address || !taskTypes.length, + skip: !hubAddress || !taskTypes.length, fetchPolicy: "cache-and-network", variables: { ...props.variables, where: { - hubAddress: hubData?.properties?.address, + hubAddress: hubAddress, ...(props.variables?.where || {}) } }, @@ -74,7 +80,7 @@ const useQueryContributions = (props: QueryFunctionOptions = {}) => { useEffect(() => { if ( - hubData?.properties?.address && + hubAddress && data?.contributions?.length && taskTypes.length ) { @@ -82,7 +88,7 @@ const useQueryContributions = (props: QueryFunctionOptions = {}) => { const sdk = await AutSDK.getInstance(); const hubService: Hub = sdk.initService( Hub, - hubData.properties.address + hubAddress ); const taskFactory = await hubService.getTaskFactory(); setLoadingMetadata(true); @@ -94,7 +100,7 @@ const useQueryContributions = (props: QueryFunctionOptions = {}) => { }; fetch(); } - }, [hubData?.properties?.address, data, taskTypes]); + }, [hubAddress, data, taskTypes]); return { data: contributions || [], diff --git a/src/utils/hooks/useQueryContributionCommits.tsx b/src/utils/hooks/useQueryContributionCommits.tsx new file mode 100644 index 0000000..707cb5a --- /dev/null +++ b/src/utils/hooks/useQueryContributionCommits.tsx @@ -0,0 +1,106 @@ +import { Hub, TaskContributionProperties } from "@aut-labs/sdk"; +import { + gql, + QueryFunctionOptions, + QueryResult, + useQuery +} from "@apollo/client"; +import { useEffect, useState } from "react"; +import { environment } from "@api/environment"; +import axios from "axios"; +import { useWalletConnector } from "@aut-labs/connector"; + +export interface ContributionCommit { + id: string; + hub: Hub; + data: any; + who: string; + contribution: Partial; + dataDecrypted?: boolean; +} + +export interface DecryptResponseData { + isSuccess: boolean; + data?: string; + error?: string; +} + +const GET_CONTRIBUTION_COMMITS = gql` + query GetContributionCommits( + $skip: Int + $first: Int + $where: ContributionCommit_filter + ) { + contributionCommits(skip: $skip, first: $first, where: $where) { + id + hub + data + who + contribution { + id + } + } + } +`; + +export const decodeHashesOfCommits = async ({ + hashes, + autSig +}): Promise => { + return axios + .post(`${environment.apiUrl}/task/contribution/viewByHashes`, { + hashes, + autSig + }) + .then((r) => r.data); +}; + +const useQueryContributionCommits = ( + props: QueryFunctionOptions = {} +) => { + const { state } = useWalletConnector(); + const { data, loading, ...rest } = useQuery(GET_CONTRIBUTION_COMMITS, { + fetchPolicy: "cache-and-network", + ...props + }); + + const [commits, setCommits] = useState([]); + + useEffect(() => { + if (data?.contributionCommits && !!state?.authSig) { + const hashes = data.contributionCommits.map( + (commit: ContributionCommit) => commit.data + ); + const fetch = async () => { + try { + const decodedCommits = await decodeHashesOfCommits({ + hashes, + autSig: state.authSig + }); + const commits = data.contributionCommits.map( + (commit: ContributionCommit, i: number) => { + const data = decodedCommits[i]; + return { + ...commit, + data: data?.data || commit.data, + dataDecrypted: data?.isSuccess + }; + } + ); + setCommits(commits); + } catch (e) { + setCommits(data?.contributionCommits); + } + }; + fetch(); + } + }, [data, state?.authSig]); + + return { + data: commits || [], + ...rest, + loading: loading + } as QueryResult; +}; + +export default useQueryContributionCommits; From e662d09589c92b895ec0cbd17a8dbcdbb88dc3f6 Mon Sep 17 00:00:00 2001 From: AntGe Date: Fri, 15 Nov 2024 17:21:41 +0200 Subject: [PATCH 03/10] final github flows --- src/components/OAuth/index.tsx | 2 +- .../AutID/AutHub/AutHubContributionsTable.tsx | 5 +- .../Tasks/Contributions/Contributions.tsx | 6 +- .../Tasks/GithubTask/GithubCommitTask.tsx | 274 ++++++++++++++++++ src/pages/Tasks/GithubTask/GithubPRTask.tsx | 267 +++++++++++++++++ src/utils/format-contribution-type.tsx | 4 + 6 files changed, 554 insertions(+), 4 deletions(-) create mode 100644 src/pages/Tasks/GithubTask/GithubCommitTask.tsx create mode 100644 src/pages/Tasks/GithubTask/GithubPRTask.tsx diff --git a/src/components/OAuth/index.tsx b/src/components/OAuth/index.tsx index 69349c8..3cff165 100644 --- a/src/components/OAuth/index.tsx +++ b/src/components/OAuth/index.tsx @@ -282,7 +282,7 @@ export const useOAuthSocials = () => { onFailure(error); } else { const response = await axios.post( - `${environment.apiUrl}/aut/config/oauth2AccessTokenGithub`, + `http://localhost:4005/api/aut/config/oauth2AccessTokenGithub`, { code: message.data.payload.code, callbackUrl diff --git a/src/pages/AutID/AutHub/AutHubContributionsTable.tsx b/src/pages/AutID/AutHub/AutHubContributionsTable.tsx index bd7a985..1b38885 100644 --- a/src/pages/AutID/AutHub/AutHubContributionsTable.tsx +++ b/src/pages/AutID/AutHub/AutHubContributionsTable.tsx @@ -235,9 +235,10 @@ export const AutHubTasksTable = ({ header }) => { if (!contributions.length) { const updatedContributions = data?.map((item) => ({ ...item, - contributionType: (item.properties as any) - .tweetUrl + contributionType: (item.properties as any).tweetUrl ? "retweet" + : (item.properties as any).repository && (item.properties as any).branch + ? "commit" : "open", status: TaskStatus.Created, id: generateRandomId() diff --git a/src/pages/Tasks/Contributions/Contributions.tsx b/src/pages/Tasks/Contributions/Contributions.tsx index 1b073ab..572d448 100644 --- a/src/pages/Tasks/Contributions/Contributions.tsx +++ b/src/pages/Tasks/Contributions/Contributions.tsx @@ -10,6 +10,7 @@ import QuizTask from "../QuizTask/QuizTask"; import { useParams } from "react-router-dom"; import useQueryContributions from "@utils/hooks/GetContributions"; import TwitterTask from "../TwitterTask/TwitterTask"; +import GithubCommitTask from "../GithubTask/GithubCommitTask"; const Contributions = () => { let contribution = useSelector(SelectedContribution); @@ -30,9 +31,12 @@ const Contributions = () => { {contribution?.contributionType === "quiz" && ( )} - {contribution?.contributionType === "retweet" && ( + {contribution?.contributionType === "retweet" && ( )} + {contribution?.contributionType === "commit" && ( + + )} ); }; diff --git a/src/pages/Tasks/GithubTask/GithubCommitTask.tsx b/src/pages/Tasks/GithubTask/GithubCommitTask.tsx new file mode 100644 index 0000000..fc68762 --- /dev/null +++ b/src/pages/Tasks/GithubTask/GithubCommitTask.tsx @@ -0,0 +1,274 @@ +import { memo, useState } from "react"; +import { + Box, + Card, + CardContent, + Container, + Link, + Stack, + Typography +} from "@mui/material"; +import { useSearchParams, useParams, useNavigate } from "react-router-dom"; +import { useDispatch } from "react-redux"; +import { TaskStatus } from "@store/model"; +import { updateContributionById } from "@store/contributions/contributions.reducer"; +import { AutOsButton } from "@components/AutButton"; +import TaskDetails from "../Shared/TaskDetails"; +import SubmitDialog from "@components/Dialog/SubmitDialog"; +import AutLoading from "@components/AutLoading"; +import { useOAuthSocials } from "@components/OAuth"; +import { useAccount } from "wagmi"; +import { useMutation } from "@tanstack/react-query"; +import axios from "axios"; +import { environment } from "@api/environment"; + +const GithubCommitContent = ({ contribution, userAddress }) => { + if (contribution) { + // eslint-disable-next-line no-debugger + debugger; + } + const [loading, setLoading] = useState(false); + const dispatch = useDispatch(); + const [searchParams] = useSearchParams(); + const navigate = useNavigate(); + const [openSubmitSuccess, setOpenSubmitSuccess] = useState(false); + const { autAddress, hubAddress } = useParams(); + const { getAuthGithub } = useOAuthSocials(); + + const { mutateAsync: verifyCommitTask } = useMutation({ + mutationFn: (verifyCommitRequest) => { + return axios + .post( + `http://localhost:4005/api/task/github/commit`, + verifyCommitRequest + ) + .then((res) => res.data); + } + }); + + const handleSubmit = async () => { + await getAuthGithub( + async (data) => { + const { access_token } = data; + setLoading(true); + try { + await verifyCommitTask( + { + accessToken: access_token, + contributionId: contribution?.id, + owner: contribution?.properties?.organisation, + branch: contribution?.properties?.branch, + repo: contribution?.properties?.repository + }, + { + onSuccess: (response) => { + dispatch( + updateContributionById({ + id: contribution?.id, + data: { + ...contribution, + status: TaskStatus.Submitted, + submission: { + properties: { + githubToken: access_token + } + } + } + }) + ); + + setOpenSubmitSuccess(true); + setLoading(false); + }, + onError: (res) => { + console.error("Failed to submit contribution:", res); + setLoading(false); + } + } + ); + } catch (error) { + setLoading(false); + // Handle error case + console.error("Failed to submit contribution:", error); + } + }, + () => { + setLoading(false); + // Handle auth failure + } + ); + }; + + return ( + + { + if (!loading) { + setOpenSubmitSuccess(false); + navigate({ + pathname: `/${autAddress}/hub/${hubAddress}`, + search: searchParams.toString() + }); + } + }} + /> + + {contribution?.status === TaskStatus.Created || + contribution?.status === TaskStatus.Taken ? ( + + + + {contribution?.description} + + + + + {contribution.properties?.tweetUrl} + + + + + Please authenticate with Github to verify your contribution + + + + + Claim + + + + + ) : ( + + + + + {contribution?.description} + + + Contribution Description + + + + + )} + + ); +}; + +const GithubCommitTask = ({ contribution }) => { + const { address: userAddress } = useAccount(); + + return ( + + {contribution ? ( + <> + + + + ) : ( + + )} + + ); +}; + +export default memo(GithubCommitTask); diff --git a/src/pages/Tasks/GithubTask/GithubPRTask.tsx b/src/pages/Tasks/GithubTask/GithubPRTask.tsx new file mode 100644 index 0000000..2c4d7f6 --- /dev/null +++ b/src/pages/Tasks/GithubTask/GithubPRTask.tsx @@ -0,0 +1,267 @@ +import { memo, useState } from "react"; +import { + Box, + Card, + CardContent, + Container, + Link, + Stack, + Typography +} from "@mui/material"; +import { useSearchParams, useParams, useNavigate } from "react-router-dom"; +import { useDispatch } from "react-redux"; +import { TaskStatus } from "@store/model"; +import { updateContributionById } from "@store/contributions/contributions.reducer"; +import { AutOsButton } from "@components/AutButton"; +import TaskDetails from "../Shared/TaskDetails"; +import SubmitDialog from "@components/Dialog/SubmitDialog"; +import AutLoading from "@components/AutLoading"; +import { useOAuthSocials } from "@components/OAuth"; +import { useAccount } from "wagmi"; +import { useMutation } from "@tanstack/react-query"; +import axios from "axios"; +import { environment } from "@api/environment"; + +const GithubPRContent = ({ contribution, userAddress }) => { + const [loading, setLoading] = useState(false); + const dispatch = useDispatch(); + const [searchParams] = useSearchParams(); + const navigate = useNavigate(); + const [openSubmitSuccess, setOpenSubmitSuccess] = useState(false); + const { autAddress, hubAddress } = useParams(); + const { getAuthGithub } = useOAuthSocials(); + + const { mutateAsync: verifyCommitTask } = useMutation({ + mutationFn: (verifyCommitRequest) => { + return axios + .post(`http://localhost:4005/api/task/github/pr`, verifyCommitRequest) + .then((res) => res.data); + } + }); + + const handleSubmit = async () => { + await getAuthGithub( + async (data) => { + const { access_token } = data; + setLoading(true); + try { + await verifyCommitTask( + { + accessToken: access_token, + contributionId: contribution?.id, + owner: contribution?.properties?.organisation, + branch: contribution?.properties?.branch, + repo: contribution?.properties?.repository + }, + { + onSuccess: (response) => { + dispatch( + updateContributionById({ + id: contribution?.id, + data: { + ...contribution, + status: TaskStatus.Submitted, + submission: { + properties: { + githubToken: access_token + } + } + } + }) + ); + + setOpenSubmitSuccess(true); + setLoading(false); + }, + onError: (res) => { + console.error("Failed to submit contribution:", res); + setLoading(false); + } + } + ); + } catch (error) { + setLoading(false); + // Handle error case + console.error("Failed to submit contribution:", error); + } + }, + () => { + setLoading(false); + // Handle auth failure + } + ); + }; + + return ( + + { + if (!loading) { + setOpenSubmitSuccess(false); + navigate({ + pathname: `/${autAddress}/hub/${hubAddress}`, + search: searchParams.toString() + }); + } + }} + /> + + {contribution?.status === TaskStatus.Created || + contribution?.status === TaskStatus.Taken ? ( + + + + {contribution?.description} + + + + + {contribution.properties?.tweetUrl} + + + + + Please authenticate with Github to verify your contribution + + + + + Claim + + + + + ) : ( + + + + + {contribution?.description} + + + Contribution Description + + + + + )} + + ); +}; + +const GithubPRTask = ({ contribution }) => { + const { address: userAddress } = useAccount(); + + return ( + + {contribution ? ( + <> + + + + ) : ( + + )} + + ); +}; + +export default memo(GithubPRTask); diff --git a/src/utils/format-contribution-type.tsx b/src/utils/format-contribution-type.tsx index f7dd1ad..86a3461 100644 --- a/src/utils/format-contribution-type.tsx +++ b/src/utils/format-contribution-type.tsx @@ -10,6 +10,8 @@ export const formatContributionType = (type: string) => { return "GitHub"; case "retweet": return "Retweet"; + case "commit": + return "Commit"; default: return type; } @@ -27,6 +29,8 @@ export const getContributionTypeSubtitle = (type: string) => { return "GitHub Task"; case "retweet": return "Retweet Task"; + case "commit": + return "Commit Task"; default: return type; } From 20a9c5b6f2de128baeaf79618fe6e781a62175ff Mon Sep 17 00:00:00 2001 From: eulaliee <52575560+eulaliee@users.noreply.github.com> Date: Fri, 15 Nov 2024 18:48:34 +0200 Subject: [PATCH 04/10] added task details, open task and quiz task submission view --- package-lock.json | 1 - src/assets/autos/move-right.svg | 4 +- .../AutID/AutHub/AutHubContributionsTable.tsx | 22 +- src/pages/Tasks/OpenTask/OpenTask.tsx | 9 +- src/pages/Tasks/QuizTask/QuizTask.tsx | 129 ++++---- src/pages/Tasks/Shared/TaskDetails.tsx | 293 ++++++++++++++++-- 6 files changed, 367 insertions(+), 91 deletions(-) diff --git a/package-lock.json b/package-lock.json index e05d105..3596077 100644 --- a/package-lock.json +++ b/package-lock.json @@ -174,7 +174,6 @@ "version": "0.0.222-dev", "resolved": "https://registry.npmjs.org/@aut-labs/sdk/-/sdk-0.0.222-dev.tgz", "integrity": "sha512-0RMVx8JojxsWZZkfUaMPB6y/dKqwqoG8fbMzVQ57isgX+XCfRdqAQTh6mjM32O77VLi1N1Y71x7p33Zb89a15A==", - "license": "MIT", "dependencies": { "@aut-labs/abi-types": "^0.0.86-dev", "date-fns": "^2.29.3", diff --git a/src/assets/autos/move-right.svg b/src/assets/autos/move-right.svg index 4a24358..53e77f6 100644 --- a/src/assets/autos/move-right.svg +++ b/src/assets/autos/move-right.svg @@ -1,6 +1,6 @@ - - + + diff --git a/src/pages/AutID/AutHub/AutHubContributionsTable.tsx b/src/pages/AutID/AutHub/AutHubContributionsTable.tsx index ab94b2c..6927048 100644 --- a/src/pages/AutID/AutHub/AutHubContributionsTable.tsx +++ b/src/pages/AutID/AutHub/AutHubContributionsTable.tsx @@ -187,10 +187,11 @@ const TableListItem = memo( }, width: "100px" }} - disabled + to={`contribution/${contribution?.properties?.id}`} + component={Link} > - - Claimed + + See Commit )} @@ -235,18 +236,19 @@ export const AutHubTasksTable = ({ header }) => { }); }, [data, commits]); + const [ commit, { error, isError, isSuccess, isLoading: commitingContribution, reset } ] = useCommitAnyContributionMutation(); - const commitContribution = (row) => { - commit({ - autSig: state.authSig, - contribution: row, - message: "secret" - }); - }; + // const commitContribution = (row) => { + // commit({ + // autSig: state.authSig, + // contribution: row, + // message: "secret" + // }); + // }; const theme = useTheme(); return ( diff --git a/src/pages/Tasks/OpenTask/OpenTask.tsx b/src/pages/Tasks/OpenTask/OpenTask.tsx index 81c6e37..c5ab7e8 100644 --- a/src/pages/Tasks/OpenTask/OpenTask.tsx +++ b/src/pages/Tasks/OpenTask/OpenTask.tsx @@ -62,6 +62,8 @@ const UserSubmitContent = ({ return userSubmit; }, [commit]); + console.log(contributionSubmitContent, 'contributionSubmitContent'); + useEffect(() => { if (!initialized && contributionSubmitContent) { let userSubmit = { @@ -284,8 +286,9 @@ const UserSubmitContent = ({ ) : ( @@ -330,7 +333,7 @@ const UserSubmitContent = ({ mt: 1, cursor: "pointer" }} - variant="body" + variant="subtitle2" target="_blank" href={ipfsCIDToHttpUrl( contributionSubmitContent?.attachment diff --git a/src/pages/Tasks/QuizTask/QuizTask.tsx b/src/pages/Tasks/QuizTask/QuizTask.tsx index 8116797..12735c8 100644 --- a/src/pages/Tasks/QuizTask/QuizTask.tsx +++ b/src/pages/Tasks/QuizTask/QuizTask.tsx @@ -71,7 +71,7 @@ const alphabetize = { 3: "D" }; -const Answers = memo(({ control, questionIndex, answers, taskStatus }: any) => { +const Answers = memo(({ control, questionIndex, answers, disabled }: any) => { const values = useWatch({ name: `questions[${questionIndex}].answers`, control @@ -98,36 +98,49 @@ const Answers = memo(({ control, questionIndex, answers, taskStatus }: any) => { {answer?.value} - v.correct) - }} - render={({ field: { name, value, onChange } }) => { - return ( - - ); - }} - /> + {disabled ? ( + + ) : ( + v.correct) + }} + render={({ field: { name, value, onChange } }) => { + return ( + + ); + }} + /> + )} )} @@ -247,6 +260,7 @@ const QuizTask = ({ {contribution ? ( <> + ))} - - - - Confirm - - - + + + Confirm + + + + )} ) : ( diff --git a/src/pages/Tasks/Shared/TaskDetails.tsx b/src/pages/Tasks/Shared/TaskDetails.tsx index 7fbf5b3..bae61fe 100644 --- a/src/pages/Tasks/Shared/TaskDetails.tsx +++ b/src/pages/Tasks/Shared/TaskDetails.tsx @@ -1,9 +1,66 @@ -import { Box, Button, Stack, Typography } from "@mui/material"; +import { + Box, + Button, + Chip, + Stack, + styled, + SvgIcon, + Tooltip, + Typography +} from "@mui/material"; import ArrowBackIosNewIcon from "@mui/icons-material/ArrowBackIosNew"; import { memo } from "react"; import { Link, useParams } from "react-router-dom"; import { TaskContributionNFT } from "@aut-labs/sdk"; -import OverflowTooltip from "@components/OverflowTooltip"; +import ArrowIcon from "@assets/autos/move-right.svg?react"; +import InfoIcon from "@assets/autos/info-icon.svg?react"; +import theme from "@theme/theme"; +import { + borderRadius, + display, + margin, + maxWidth, + textAlign, + width +} from "@mui/system"; +import { max } from "date-fns"; + +const TaskTopWrapper = styled(Box)(({ theme }) => ({ + display: "flex", + flexDirection: "column", + justifyContent: "center", + alignItems: "center", + padding: "16px", + borderBottom: "1px solid", + borderColor: "inherit", + [theme.breakpoints.down("md")]: { + flexDirection: "column", + justifyContent: "center", + alignItems: "flex-start", + gap: "20px" + } +})); +const TaskBottomWrapper = styled(Box)(({ theme }) => ({ + display: "grid", + gridTemplateColumns: "1fr 1fr 1fr", + borderColor: "inherit", + + [theme.breakpoints.down("md")]: { + display: "flex", + flexDirection: "column" + } +})); + +const PropertiesWrapper = styled(Box)(({ theme }) => ({ + display: "flex", + flexDirection: "column", + justifyContent: "center", + alignItems: "center", + padding: "8px", + [theme.breakpoints.down("md")]: { + padding: "4px 0" + } +})); const TaskDetails = ({ contribution @@ -11,6 +68,7 @@ const TaskDetails = ({ contribution: TaskContributionNFT & { contributionType?: string }; }) => { const { hubAddress, autAddress } = useParams(); + console.log(contribution); return ( <> @@ -30,10 +88,10 @@ const TaskDetails = ({ color="offWhite" sx={{ position: { - sm: "absolute" + md: "absolute" }, left: { - sm: "0" + md: "0" } }} to={`/${autAddress}/hub/${hubAddress}`} @@ -43,27 +101,220 @@ const TaskDetails = ({ Back - - {contribution?.name} - - - - {contribution?.contributionType} - + + + + {contribution?.name} + + + {contribution?.description} + + + + + + + + {new Date( + parseInt( + contribution?.properties?.startDate?.toString() || "" + ) * 1000 + ).toLocaleDateString()}{" "} + + + + {new Date( + parseInt( + contribution?.properties?.endDate?.toString() || "" + ) * 1000 + ).toLocaleDateString()}{" "} + + + + + + + {contribution?.properties.points}{" "} + {contribution.properties.points > 1 ? "points" : "point"} + + + + + + + + + + + + + {contribution?.properties.quantity}{" "} + {contribution.properties.quantity > 1 + ? "completions" + : "completion"} + + + + + + + + + {/* + + */} + + + + {/* Date: Thu, 21 Nov 2024 00:17:43 +0200 Subject: [PATCH 05/10] added rest of socials verification pages --- .../contribution-types/github-commit.model.ts | 1 + .../contribution-types/github-pr.model.ts | 1 + src/api/models/contribution.model.ts | 4 + src/components/OAuth/index.tsx | 2 +- .../AutID/AutHub/AutHubContributionsTable.tsx | 283 +++++++++--------- .../Tasks/Contributions/Contributions.tsx | 5 + .../Tasks/GithubTask/GithubCommitTask.tsx | 164 ++++------ src/pages/Tasks/GithubTask/GithubPRTask.tsx | 158 ++++------ src/pages/Tasks/TwitterTask/TwitterTask.tsx | 145 +++++---- src/utils/hooks/GetContributions.tsx | 5 +- 10 files changed, 353 insertions(+), 415 deletions(-) diff --git a/src/api/models/contribution-types/github-commit.model.ts b/src/api/models/contribution-types/github-commit.model.ts index 8119473..f9634d4 100644 --- a/src/api/models/contribution-types/github-commit.model.ts +++ b/src/api/models/contribution-types/github-commit.model.ts @@ -39,4 +39,5 @@ export class GithubCommitContribution< data.properties as GithubCommitContributionProperties ) as T; } + contributionType? = "Commit"; } diff --git a/src/api/models/contribution-types/github-pr.model.ts b/src/api/models/contribution-types/github-pr.model.ts index 20a5be3..111ca48 100644 --- a/src/api/models/contribution-types/github-pr.model.ts +++ b/src/api/models/contribution-types/github-pr.model.ts @@ -43,4 +43,5 @@ export class GithubPullRequestContribution< data.properties as GithubPullRequestContributionProperties ) as T; } + contributionType? = "Pull Request"; } diff --git a/src/api/models/contribution.model.ts b/src/api/models/contribution.model.ts index 81d2905..432abee 100644 --- a/src/api/models/contribution.model.ts +++ b/src/api/models/contribution.model.ts @@ -5,6 +5,8 @@ import { RetweetContribution } from "./contribution-types/retweet.model"; import { JoinDiscordContribution } from "./contribution-types/join-discord.model"; import { QuizTaskContribution } from "./contribution-types/quiz.model.model"; import { TaskType } from "./task-type"; +import { GithubCommitContribution } from "./contribution-types/github-commit.model"; +import { GithubPullRequestContribution } from "./contribution-types/github-pr.model"; export const ContributionFactory = ( metadata: BaseNFTModel, @@ -39,7 +41,9 @@ export const ContributionFactory = ( return new QuizTaskContribution(data); case "TwitterLike": case "GitHubCommit": + return new GithubCommitContribution(data); case "GitHubOpenPR": + return new GithubPullRequestContribution(data); case "DiscordPolls": case "TwitterFollow": case "TwitterComment": diff --git a/src/components/OAuth/index.tsx b/src/components/OAuth/index.tsx index 3cff165..69349c8 100644 --- a/src/components/OAuth/index.tsx +++ b/src/components/OAuth/index.tsx @@ -282,7 +282,7 @@ export const useOAuthSocials = () => { onFailure(error); } else { const response = await axios.post( - `http://localhost:4005/api/aut/config/oauth2AccessTokenGithub`, + `${environment.apiUrl}/aut/config/oauth2AccessTokenGithub`, { code: message.data.payload.code, callbackUrl diff --git a/src/pages/AutID/AutHub/AutHubContributionsTable.tsx b/src/pages/AutID/AutHub/AutHubContributionsTable.tsx index 6927048..6307184 100644 --- a/src/pages/AutID/AutHub/AutHubContributionsTable.tsx +++ b/src/pages/AutID/AutHub/AutHubContributionsTable.tsx @@ -27,6 +27,7 @@ import useQueryContributionCommits, { } from "@utils/hooks/useQueryContributionCommits"; import { TaskContributionNFT } from "@aut-labs/sdk"; import { Link } from "react-router-dom"; +import { GithubCommitContribution } from "@api/models/contribution-types/github-commit.model"; const StyledTableCell = styled(TableCell)(({ theme }) => ({ [`&.${tableCellClasses.head}, &.${tableCellClasses.body}`]: { @@ -53,154 +54,152 @@ interface TableListItemProps { commit: ContributionCommit; } -const TableListItem = memo( - ({ contribution, commit }: TableListItemProps) => { - const theme = useTheme(); +const TableListItem = memo(({ contribution, commit }: TableListItemProps) => { + const theme = useTheme(); - const startDate = useMemo(() => { - return format( - new Date(contribution?.properties?.startDate * 1000), - "dd.MM.yy" - ).toString(); - }, [contribution?.properties?.startDate]); + const startDate = useMemo(() => { + return format( + new Date(contribution?.properties?.startDate * 1000), + "dd.MM.yy" + ).toString(); + }, [contribution?.properties?.startDate]); - const endDate = useMemo(() => { - return format( - new Date(contribution?.properties?.endDate * 1000), - "dd.MM.yy" - ).toString(); - }, [contribution?.properties?.endDate]); + const endDate = useMemo(() => { + return format( + new Date(contribution?.properties?.endDate * 1000), + "dd.MM.yy" + ).toString(); + }, [contribution?.properties?.endDate]); - return ( - - - - - {contribution?.name} - - - {contribution?.description} - - - - - - - {contribution?.contributionType} - - - - + } + }} + > + + + + {contribution?.name} + + + {contribution?.description} + + + + + - {`${contribution?.properties?.points || 0} ${contribution?.properties?.points === 1 ? "pt" : "pts"}`} + {contribution?.contributionType} - - - - - {startDate} - - - - - + + + + + {`${contribution?.properties?.points || 0} ${contribution?.properties?.points === 1 ? "pt" : "pts"}`} + + + + - {endDate} + {startDate} - + + + + + + {endDate} + + - - - {!commit ? ( - - - Claim - - - ) : ( - - - See Commit - - - )} - - -
- ); - } -); + + + {!commit ? ( + + + Claim + + + ) : ( + + + See Commit + + + )} + + + + ); +}); export const AutHubTasksTable = ({ header }) => { const { state } = useWalletConnector(); @@ -236,7 +235,11 @@ export const AutHubTasksTable = ({ header }) => { }); }, [data, commits]); - + if (data?.length) { + data.map((contribution) => { + console.log(contribution as GithubCommitContribution); + }) + } const [ commit, { error, isError, isSuccess, isLoading: commitingContribution, reset } diff --git a/src/pages/Tasks/Contributions/Contributions.tsx b/src/pages/Tasks/Contributions/Contributions.tsx index 93d05d4..b300544 100644 --- a/src/pages/Tasks/Contributions/Contributions.tsx +++ b/src/pages/Tasks/Contributions/Contributions.tsx @@ -11,6 +11,8 @@ import { GithubCommitContribution } from "@api/models/contribution-types/github- import GithubCommitTask from "../GithubTask/GithubCommitTask"; import GithubPRTask from "../GithubTask/GithubPRTask"; import { GithubPullRequestContribution } from "@api/models/contribution-types/github-pr.model"; +import { RetweetContribution } from "@api/models/contribution-types/retweet.model"; +import TwitterTask from "../TwitterTask/TwitterTask"; const Contributions = () => { const { state } = useWalletConnector(); @@ -50,6 +52,7 @@ const Contributions = () => { const contributionTemplate = useMemo(() => { const contribution = data?.[0]; if (!contribution) return null; + debugger; if (contribution instanceof OpenTaskContribution) { return ; } else if (contribution instanceof QuizTaskContribution) { @@ -58,6 +61,8 @@ const Contributions = () => { return ; } else if (contribution instanceof GithubPullRequestContribution) { return ; + }else if (contribution instanceof RetweetContribution) { + return ; } else { return "Contribution type not supported"; } diff --git a/src/pages/Tasks/GithubTask/GithubCommitTask.tsx b/src/pages/Tasks/GithubTask/GithubCommitTask.tsx index 3bcb0ad..81afe66 100644 --- a/src/pages/Tasks/GithubTask/GithubCommitTask.tsx +++ b/src/pages/Tasks/GithubTask/GithubCommitTask.tsx @@ -1,28 +1,17 @@ import { memo, useState } from "react"; -import { - Box, - Card, - CardContent, - Container, - Link, - Stack, - Typography -} from "@mui/material"; +import { Card, CardContent, Container, Stack, Typography } from "@mui/material"; import { useSearchParams, useParams, useNavigate } from "react-router-dom"; -import { useDispatch } from "react-redux"; import { TaskStatus } from "@store/model"; -import { updateContributionById } from "@store/contributions/contributions.reducer"; import { AutOsButton } from "@components/AutButton"; import TaskDetails from "../Shared/TaskDetails"; import SubmitDialog from "@components/Dialog/SubmitDialog"; import AutLoading from "@components/AutLoading"; import { useOAuthSocials } from "@components/OAuth"; -import { useAccount } from "wagmi"; -import { useMutation } from "@tanstack/react-query"; -import axios from "axios"; -import { environment } from "@api/environment"; +import { useWalletConnector } from "@aut-labs/connector"; import { ContributionCommit } from "@utils/hooks/useQueryContributionCommits"; import { GithubCommitContribution } from "@api/models/contribution-types/github-commit.model"; +import { useCommitAnyContributionMutation } from "@api/contributions.api"; +import ErrorDialog from "@components/Dialog/ErrorPopup"; const GithubCommitContent = ({ contribution, @@ -31,73 +20,45 @@ const GithubCommitContent = ({ contribution: GithubCommitContribution; commit: ContributionCommit; }) => { - const [loading, setLoading] = useState(false); - const dispatch = useDispatch(); + const { state } = useWalletConnector(); const [searchParams] = useSearchParams(); const navigate = useNavigate(); - const [openSubmitSuccess, setOpenSubmitSuccess] = useState(false); const { autAddress, hubAddress } = useParams(); const { getAuthGithub } = useOAuthSocials(); - const { mutateAsync: verifyCommitTask } = useMutation({ - mutationFn: (verifyCommitRequest) => { - return axios - .post( - `http://localhost:4005/api/task/github/commit`, - verifyCommitRequest - ) - .then((res) => res.data); + const [commitContribution, { error, isError, isSuccess, isLoading, reset }] = + useCommitAnyContributionMutation(); + + const contributionSubmitContent = (() => { + let userSubmit = null; + try { + userSubmit = JSON.parse(commit?.data || "{}"); + } catch (e) { + // pass } - }); + return userSubmit; + })(); const handleSubmit = async () => { await getAuthGithub( async (data) => { const { access_token } = data; - setLoading(true); - try { - await verifyCommitTask( - { - accessToken: access_token, - contributionId: contribution?.id, - owner: contribution?.properties?.organisation, - branch: contribution?.properties?.branch, - repo: contribution?.properties?.repository - }, - { - onSuccess: (response) => { - dispatch( - updateContributionById({ - id: contribution?.id, - data: { - ...contribution, - status: TaskStatus.Submitted, - submission: { - properties: { - githubToken: access_token - } - } - } - }) - ); - setOpenSubmitSuccess(true); - setLoading(false); - }, - onError: (res) => { - console.error("Failed to submit contribution:", res); - setLoading(false); - } - } - ); - } catch (error) { - setLoading(false); - // Handle error case - console.error("Failed to submit contribution:", error); - } + const commitMessage = { + accessToken: access_token, + owner: contribution?.properties?.organisation, + branch: contribution?.properties?.branch, + repo: contribution?.properties?.repository + }; + + commitContribution({ + autSig: state.authSig, + contribution, + message: JSON.stringify(commitMessage), + hubAddress + }); }, () => { - setLoading(false); // Handle auth failure } ); @@ -118,21 +79,27 @@ const GithubCommitContent = ({ } }} > + reset()} + open={isError} + message={(error as { message: string })?.message || "An error occurred"} + /> + { - if (!loading) { - setOpenSubmitSuccess(false); + if (!isLoading) { + reset(); navigate({ pathname: `/${autAddress}/hub/${hubAddress}`, search: searchParams.toString() @@ -141,8 +108,7 @@ const GithubCommitContent = ({ }} /> - {contribution?.status === TaskStatus.Created || - contribution?.status === TaskStatus.Taken ? ( + {!commit ? ( - - - {contribution.properties?.tweetUrl} - - - - Claim + Submit @@ -234,8 +184,17 @@ const GithubCommitContent = ({ > {contribution?.description} + + Contribution submitted to repository:{" "} + {contributionSubmitContent?.repo} + - Contribution Description + Github Commit Contribution @@ -245,9 +204,13 @@ const GithubCommitContent = ({ ); }; -const GithubCommitTask = ({ contribution }) => { - const { address: userAddress } = useAccount(); - +const GithubCommitTask = ({ + contribution, + commit +}: { + contribution: GithubCommitContribution; + commit: ContributionCommit; +}) => { return ( { > {contribution ? ( <> - - + + ) : ( diff --git a/src/pages/Tasks/GithubTask/GithubPRTask.tsx b/src/pages/Tasks/GithubTask/GithubPRTask.tsx index 83d69d8..0dfc812 100644 --- a/src/pages/Tasks/GithubTask/GithubPRTask.tsx +++ b/src/pages/Tasks/GithubTask/GithubPRTask.tsx @@ -1,6 +1,5 @@ import { memo, useState } from "react"; import { - Box, Card, CardContent, Container, @@ -9,20 +8,17 @@ import { Typography } from "@mui/material"; import { useSearchParams, useParams, useNavigate } from "react-router-dom"; -import { useDispatch } from "react-redux"; import { TaskStatus } from "@store/model"; -import { updateContributionById } from "@store/contributions/contributions.reducer"; import { AutOsButton } from "@components/AutButton"; import TaskDetails from "../Shared/TaskDetails"; import SubmitDialog from "@components/Dialog/SubmitDialog"; import AutLoading from "@components/AutLoading"; import { useOAuthSocials } from "@components/OAuth"; -import { useAccount } from "wagmi"; -import { useMutation } from "@tanstack/react-query"; -import axios from "axios"; -import { environment } from "@api/environment"; -import { GithubPullRequestContribution } from "@api/models/contribution-types/github-pr.model"; +import { useWalletConnector } from "@aut-labs/connector"; import { ContributionCommit } from "@utils/hooks/useQueryContributionCommits"; +import { GithubPullRequestContribution } from "@api/models/contribution-types/github-pr.model"; +import { useCommitAnyContributionMutation } from "@api/contributions.api"; +import ErrorDialog from "@components/Dialog/ErrorPopup"; const GithubPRContent = ({ contribution, @@ -31,70 +27,49 @@ const GithubPRContent = ({ contribution: GithubPullRequestContribution; commit: ContributionCommit; }) => { - const [loading, setLoading] = useState(false); - const dispatch = useDispatch(); + const { state } = useWalletConnector(); const [searchParams] = useSearchParams(); const navigate = useNavigate(); - const [openSubmitSuccess, setOpenSubmitSuccess] = useState(false); const { autAddress, hubAddress } = useParams(); const { getAuthGithub } = useOAuthSocials(); - const { mutateAsync: verifyCommitTask } = useMutation({ - mutationFn: (verifyCommitRequest) => { - return axios - .post(`http://localhost:4005/api/task/github/pr`, verifyCommitRequest) - .then((res) => res.data); + const [commitContribution, { error, isError, isSuccess, isLoading, reset }] = + useCommitAnyContributionMutation(); + + if (error || isError) { + debugger; + } + + const contributionSubmitContent = (() => { + let userSubmit = null; + try { + userSubmit = JSON.parse(commit?.data || "{}"); + } catch (e) { + // pass } - }); + return userSubmit; + })(); const handleSubmit = async () => { await getAuthGithub( async (data) => { const { access_token } = data; - setLoading(true); - try { - await verifyCommitTask( - { - accessToken: access_token, - contributionId: contribution?.id, - owner: contribution?.properties?.organisation, - branch: contribution?.properties?.branch, - repo: contribution?.properties?.repository - }, - { - onSuccess: (response) => { - dispatch( - updateContributionById({ - id: contribution?.id, - data: { - ...contribution, - status: TaskStatus.Submitted, - submission: { - properties: { - githubToken: access_token - } - } - } - }) - ); - setOpenSubmitSuccess(true); - setLoading(false); - }, - onError: (res) => { - console.error("Failed to submit contribution:", res); - setLoading(false); - } - } - ); - } catch (error) { - setLoading(false); - // Handle error case - console.error("Failed to submit contribution:", error); - } + const commitMessage = { + accessToken: access_token, + owner: contribution?.properties?.organisation, + branch: contribution?.properties?.branch, + repo: contribution?.properties?.repository + }; + + commitContribution({ + autSig: state.authSig, + contribution, + message: JSON.stringify(commitMessage), + hubAddress + }); }, () => { - setLoading(false); // Handle auth failure } ); @@ -115,21 +90,27 @@ const GithubPRContent = ({ } }} > + reset()} + open={isError} + message={(error as { message: string })?.message || "An error occurred"} + /> + { - if (!loading) { - setOpenSubmitSuccess(false); + if (!isLoading) { + reset(); navigate({ pathname: `/${autAddress}/hub/${hubAddress}`, search: searchParams.toString() @@ -138,8 +119,7 @@ const GithubPRContent = ({ }} /> - {contribution?.status === TaskStatus.Created || - contribution?.status === TaskStatus.Taken ? ( + {!commit ? ( - - - {contribution.properties?.tweetUrl} - - - - Claim + Submit @@ -231,8 +195,17 @@ const GithubPRContent = ({ > {contribution?.description} + + Pull Request submitted to repository:{" "} + {contributionSubmitContent?.repo} + - Contribution Description + Github Pull Request Contribution @@ -242,9 +215,13 @@ const GithubPRContent = ({ ); }; -const GithubPRTask = ({ contribution , commit }) => { - const { address: userAddress } = useAccount(); - +const GithubPRTask = ({ + contribution, + commit +}: { + contribution: GithubPullRequestContribution; + commit: ContributionCommit; +}) => { return ( { > {contribution ? ( <> - - + + ) : ( diff --git a/src/pages/Tasks/TwitterTask/TwitterTask.tsx b/src/pages/Tasks/TwitterTask/TwitterTask.tsx index 2eef2df..90cd500 100644 --- a/src/pages/Tasks/TwitterTask/TwitterTask.tsx +++ b/src/pages/Tasks/TwitterTask/TwitterTask.tsx @@ -1,6 +1,5 @@ -import { memo, useState } from "react"; +import { memo } from "react"; import { - Box, Card, CardContent, Container, @@ -9,84 +8,62 @@ import { Typography } from "@mui/material"; import { useSearchParams, useParams, useNavigate } from "react-router-dom"; -import { useDispatch } from "react-redux"; import { TaskStatus } from "@store/model"; -import { updateContributionById } from "@store/contributions/contributions.reducer"; import { AutOsButton } from "@components/AutButton"; import TaskDetails from "../Shared/TaskDetails"; import SubmitDialog from "@components/Dialog/SubmitDialog"; import AutLoading from "@components/AutLoading"; import { useOAuthSocials } from "@components/OAuth"; -import { useAccount } from "wagmi"; -import { useMutation } from "@tanstack/react-query"; -import axios from "axios"; -import { environment } from "@api/environment"; +import { useWalletConnector } from "@aut-labs/connector"; +import { ContributionCommit } from "@utils/hooks/useQueryContributionCommits"; +import { useCommitAnyContributionMutation } from "@api/contributions.api"; +import ErrorDialog from "@components/Dialog/ErrorPopup"; +import { RetweetContribution } from "@api/models/contribution-types/retweet.model"; -const TwitterSubmitContent = ({ contribution, userAddress }) => { - const [loading, setLoading] = useState(false); - const dispatch = useDispatch(); +const TwitterSubmitContent = ({ + contribution, + commit +}: { + contribution: RetweetContribution; + commit: ContributionCommit; +}) => { + const { state } = useWalletConnector(); const [searchParams] = useSearchParams(); const navigate = useNavigate(); - const [openSubmitSuccess, setOpenSubmitSuccess] = useState(false); const { autAddress, hubAddress } = useParams(); const { getAuthX } = useOAuthSocials(); - const { mutateAsync: verifyTetweetTask } = useMutation({ - mutationFn: (verifyRetweetRequest) => { - return axios - .post( - `${environment.apiUrl}/task/twitter/retweet`, - verifyRetweetRequest - ) - .then((res) => res.data); + const [commitContribution, { error, isError, isSuccess, isLoading, reset }] = + useCommitAnyContributionMutation(); + + const contributionSubmitContent = (() => { + let userSubmit = null; + try { + userSubmit = JSON.parse(commit?.data || "{}"); + } catch (e) { + // pass } - }); + return userSubmit; + })(); const handleSubmit = async () => { await getAuthX( async (data) => { const { access_token } = data; - setLoading(true); - try { - await verifyTetweetTask( - { - accessToken: access_token, - contributionId: contribution?.id, - tweetUrl: contribution.properties?.tweetUrl - }, - { - onSuccess: (response) => { - dispatch( - updateContributionById({ - id: contribution?.id, - data: { - ...contribution, - status: TaskStatus.Submitted, - submission: { - properties: { - twitterToken: access_token - } - } - } - }) - ); - setOpenSubmitSuccess(true); - setLoading(false); - }, - onError: (res) => { - console.error("Failed to submit contribution:", res); - } - } - ); - } catch (error) { - setLoading(false); - // Handle error case - console.error("Failed to submit contribution:", error); - } + const tweetMessage = { + accessToken: access_token, + tweetUrl: contribution.properties?.tweetUrl + }; + + commitContribution({ + autSig: state.authSig, + contribution, + message: JSON.stringify(tweetMessage), + hubAddress + }); }, () => { - setLoading(false); // Handle auth failure } ); @@ -107,21 +84,27 @@ const TwitterSubmitContent = ({ contribution, userAddress }) => { } }} > + reset()} + open={isError} + message={(error as { message: string })?.message || "An error occurred"} + /> + { - if (!loading) { - setOpenSubmitSuccess(false); + if (!isLoading) { + reset(); navigate({ pathname: `/${autAddress}/hub/${hubAddress}`, search: searchParams.toString() @@ -130,8 +113,7 @@ const TwitterSubmitContent = ({ contribution, userAddress }) => { }} /> - {contribution?.status === TaskStatus.Created || - contribution?.status === TaskStatus.Taken ? ( + {!commit ? ( { }} > - Claim + Submit @@ -223,8 +205,16 @@ const TwitterSubmitContent = ({ contribution, userAddress }) => { > {contribution?.description} + + Tweet URL: {contributionSubmitContent?.tweetUrl} + - Contribution Description + Twitter Retweet Contribution @@ -234,9 +224,13 @@ const TwitterSubmitContent = ({ contribution, userAddress }) => { ); }; -const TwitterTask = ({ contribution }) => { - const { address: userAddress } = useAccount(); - +const TwitterTask = ({ + contribution, + commit +}: { + contribution: RetweetContribution; + commit: ContributionCommit; +}) => { return ( { > {contribution ? ( <> - - + + ) : ( diff --git a/src/utils/hooks/GetContributions.tsx b/src/utils/hooks/GetContributions.tsx index b370259..fbbbac7 100644 --- a/src/utils/hooks/GetContributions.tsx +++ b/src/utils/hooks/GetContributions.tsx @@ -61,9 +61,8 @@ const useQueryContributions = (props: QueryFunctionOptions = {}) => { const hubAddress = useMemo(() => { return selectedHubAddress || _hubAddress; }, [_hubAddress, selectedHubAddress]); - const { data, loading, ...rest } = useQuery(GET_HUB_CONTRIBUTIONS, { - skip: !hubAddress || !taskTypes.length, + skip: !hubAddress && !taskTypes.length, fetchPolicy: "cache-and-network", variables: { ...props.variables, @@ -72,7 +71,7 @@ const useQueryContributions = (props: QueryFunctionOptions = {}) => { ...(props.variables?.where || {}) } }, - ...props + // ...props }); const [contributions, setContributions] = useState([]); From cbedd4b6b09e869816679db1e24c96a6578b320e Mon Sep 17 00:00:00 2001 From: mrtmeeseeks Date: Tue, 26 Nov 2024 18:35:15 +0200 Subject: [PATCH 06/10] a fix for fetching contributions --- package-lock.json | 9 ++++--- package.json | 2 +- src/utils/hooks/GetContributions.tsx | 37 ++++++++++++---------------- 3 files changed, 22 insertions(+), 26 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3596077..520fa4d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "@aut-labs/abi-types": "^0.0.86-dev", "@aut-labs/connector": "^0.0.203", "@aut-labs/d-aut": "^1.0.204-dev", - "@aut-labs/sdk": "^0.0.222-dev", + "@aut-labs/sdk": "^0.0.223-dev", "@emotion/react": "^11.11.3", "@emotion/styled": "^11.11.0", "@marker.io/browser": "^0.19.0", @@ -171,9 +171,10 @@ "integrity": "sha512-sDEu6yyvqu/KjqobI6nBoovrHWwhA4DoXPWObQLcGRs1Isuxg/d2HhP2/9k6Xz5zjFDo/w3MDI3XDvpVos20dg==" }, "node_modules/@aut-labs/sdk": { - "version": "0.0.222-dev", - "resolved": "https://registry.npmjs.org/@aut-labs/sdk/-/sdk-0.0.222-dev.tgz", - "integrity": "sha512-0RMVx8JojxsWZZkfUaMPB6y/dKqwqoG8fbMzVQ57isgX+XCfRdqAQTh6mjM32O77VLi1N1Y71x7p33Zb89a15A==", + "version": "0.0.223-dev", + "resolved": "https://registry.npmjs.org/@aut-labs/sdk/-/sdk-0.0.223-dev.tgz", + "integrity": "sha512-Fsainkcjj0dJdlqriiLbJh6F/BjggRMqJJvzMjRZHJ94m5MLTHwrFpXlDwbmBVdq9OLeYZOFlua4/A9kWgNIeA==", + "license": "MIT", "dependencies": { "@aut-labs/abi-types": "^0.0.86-dev", "date-fns": "^2.29.3", diff --git a/package.json b/package.json index ebe8891..f14314a 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "@aut-labs/abi-types": "^0.0.86-dev", "@aut-labs/connector": "^0.0.203", "@aut-labs/d-aut": "^1.0.204-dev", - "@aut-labs/sdk": "^0.0.222-dev", + "@aut-labs/sdk": "^0.0.223-dev", "@emotion/react": "^11.11.3", "@emotion/styled": "^11.11.0", "@marker.io/browser": "^0.19.0", diff --git a/src/utils/hooks/GetContributions.tsx b/src/utils/hooks/GetContributions.tsx index b370259..9383c8e 100644 --- a/src/utils/hooks/GetContributions.tsx +++ b/src/utils/hooks/GetContributions.tsx @@ -40,17 +40,19 @@ const contributionsMetadata = ( taskFactory: TaskFactoryContract, taskTypes: TaskType[] ) => { - return contributions.map(async (contribution) => { - const { uri } = await taskFactory.functions.getDescriptionById( - contribution?.descriptionId - ); - let metadata = await fetchMetadata>( - uri, - environment.ipfsGatewayUrl - ); - metadata = metadata || ({ properties: {} } as BaseNFTModel); - return ContributionFactory(metadata, contribution, taskTypes); - }); + return contributions + .filter((contribution) => contribution?.descriptionId) + .map(async (contribution) => { + const { uri } = await taskFactory.functions.getDescriptionById( + contribution?.descriptionId + ); + let metadata = await fetchMetadata>( + uri, + environment.ipfsGatewayUrl + ); + metadata = metadata || ({ properties: {} } as BaseNFTModel); + return ContributionFactory(metadata, contribution, taskTypes); + }); }; const useQueryContributions = (props: QueryFunctionOptions = {}) => { @@ -72,24 +74,17 @@ const useQueryContributions = (props: QueryFunctionOptions = {}) => { ...(props.variables?.where || {}) } }, - ...props + // ...props }); const [contributions, setContributions] = useState([]); const [loadingMetadata, setLoadingMetadata] = useState(true); useEffect(() => { - if ( - hubAddress && - data?.contributions?.length && - taskTypes.length - ) { + if (hubAddress && data?.contributions?.length && taskTypes.length) { const fetch = async () => { const sdk = await AutSDK.getInstance(); - const hubService: Hub = sdk.initService( - Hub, - hubAddress - ); + const hubService: Hub = sdk.initService(Hub, hubAddress); const taskFactory = await hubService.getTaskFactory(); setLoadingMetadata(true); const contributions = await Promise.all( From 55a1de35f2875f1aa869cf911eacc46d2566ebd7 Mon Sep 17 00:00:00 2001 From: AntGe Date: Wed, 27 Nov 2024 23:43:29 +0200 Subject: [PATCH 07/10] join discord task page --- .../contribution-types/join-discord.model.ts | 18 +- .../Tasks/Contributions/Contributions.tsx | 6 +- src/pages/Tasks/DiscordTask/DiscordTask.tsx | 300 ------------------ .../Tasks/DiscordTask/JoinDiscordTask.tsx | 257 +++++++++++++++ 4 files changed, 273 insertions(+), 308 deletions(-) delete mode 100644 src/pages/Tasks/DiscordTask/DiscordTask.tsx create mode 100644 src/pages/Tasks/DiscordTask/JoinDiscordTask.tsx diff --git a/src/api/models/contribution-types/join-discord.model.ts b/src/api/models/contribution-types/join-discord.model.ts index 489d5c3..e8fab20 100644 --- a/src/api/models/contribution-types/join-discord.model.ts +++ b/src/api/models/contribution-types/join-discord.model.ts @@ -4,16 +4,18 @@ import { TaskContributionProperties } from "@aut-labs/sdk"; -export class JoinDiscordTaskContributionProperties extends TaskContributionProperties { +export class JoinDiscordContributionProperties extends TaskContributionProperties { + guildId: string; inviteUrl: string; - constructor(data: JoinDiscordTaskContributionProperties) { + constructor(data: JoinDiscordContributionProperties) { super(data); - this.inviteUrl = data.inviteUrl; + this.guildId = data.guildId; + this.inviteUrl = data.inviteUrl } } export class JoinDiscordContribution< - T = JoinDiscordTaskContributionProperties + T = JoinDiscordContributionProperties > extends TaskContributionNFT { static getContributionNFT( contribution: JoinDiscordContribution @@ -23,16 +25,18 @@ export class JoinDiscordContribution< name: taskContribution.name, description: taskContribution.description, properties: { - inviteUrl: taskContribution.properties.inviteUrl, + guildId: taskContribution.properties.guildId, + inviteUrl: taskContribution.properties.inviteUrl } } as BaseNFTModel; } + constructor( data: JoinDiscordContribution = {} as JoinDiscordContribution ) { super(data); - this.properties = new JoinDiscordTaskContributionProperties( - data.properties as JoinDiscordTaskContributionProperties + this.properties = new JoinDiscordContributionProperties( + data.properties as JoinDiscordContributionProperties ) as T; } diff --git a/src/pages/Tasks/Contributions/Contributions.tsx b/src/pages/Tasks/Contributions/Contributions.tsx index b300544..3581b08 100644 --- a/src/pages/Tasks/Contributions/Contributions.tsx +++ b/src/pages/Tasks/Contributions/Contributions.tsx @@ -13,6 +13,8 @@ import GithubPRTask from "../GithubTask/GithubPRTask"; import { GithubPullRequestContribution } from "@api/models/contribution-types/github-pr.model"; import { RetweetContribution } from "@api/models/contribution-types/retweet.model"; import TwitterTask from "../TwitterTask/TwitterTask"; +import { JoinDiscordContribution } from "@api/models/contribution-types/join-discord.model"; +import JoinDiscordTask from "../DiscordTask/JoinDiscordTask"; const Contributions = () => { const { state } = useWalletConnector(); @@ -61,8 +63,10 @@ const Contributions = () => { return ; } else if (contribution instanceof GithubPullRequestContribution) { return ; - }else if (contribution instanceof RetweetContribution) { + } else if (contribution instanceof RetweetContribution) { return ; + } else if (contribution instanceof JoinDiscordContribution) { + return ; } else { return "Contribution type not supported"; } diff --git a/src/pages/Tasks/DiscordTask/DiscordTask.tsx b/src/pages/Tasks/DiscordTask/DiscordTask.tsx deleted file mode 100644 index ff497c1..0000000 --- a/src/pages/Tasks/DiscordTask/DiscordTask.tsx +++ /dev/null @@ -1,300 +0,0 @@ -import AutLoading from "@components/AutLoading"; -import { Box, Container, Stack, Typography } from "@mui/material"; -import { memo, useEffect, useState } from "react"; -import { useDispatch, useSelector } from "react-redux"; -import { - useLocation, - useNavigate, - useParams, - useSearchParams -} from "react-router-dom"; -import TaskDetails from "../Shared/TaskDetails"; -import ErrorDialog from "@components/Dialog/ErrorPopup"; -import LoadingDialog from "@components/Dialog/LoadingPopup"; -import SuccessDialog from "@components/Dialog/SuccessPopup"; -import { StepperButton } from "@components/StepperButton"; -import { useAccount } from "wagmi"; -import { AutOsButton } from "@components/AutButton"; -import { TaskStatus } from "@store/model"; -import { useOAuth, useOAuthSocials } from "@components/OAuth"; -import { updateContributionById } from "@store/contributions/contributions.reducer"; -import SubmitDialog from "@components/Dialog/SubmitDialog"; - -const JoinDiscordTask = ({ contribution }: any) => { - const dispatch = useDispatch(); - const [searchParams] = useSearchParams(); - const [loading, setLoading] = useState(false); - const location = useLocation(); - const params = useParams(); - const { address: userAddress } = useAccount(); - // const isAdmin = useSelector(IsAdmin); - const isAdmin = false; - const { getAuthDiscord, authenticating } = useOAuthSocials(); - const [joinClicked, setJoinClicked] = useState(false); - const [openSubmitSuccess, setOpenSubmitSuccess] = useState(false); - const navigate = useNavigate(); - const { autAddress, hubAddress } = useParams(); - - // const { task, isLoading: isLoadingTasks } = useGetAllTasksPerQuestQuery( - // { - // userAddress, - // isAdmin, - // pluginAddress: searchParams.get( - // RequiredQueryParams.OnboardingQuestAddress - // ), - // questId: +searchParams.get(RequiredQueryParams.QuestId) - // }, - // { - // selectFromResult: ({ data, isLoading, isFetching }) => ({ - // isLoading: isLoading || isFetching, - // task: (data?.tasks || []).find((t) => { - // const [pluginType] = location.pathname.split("/").splice(-2); - // return ( - // t.taskId === +params?.taskId && - // PluginDefinitionType[pluginType] === - // taskTypes[t.taskType].pluginType - // ); - // }) - // }) - // } - // ); - - // const [ - // submitJoinDiscordTask, - // { isSuccess, error, isError, isLoading, reset } - // ] = useSubmitJoinDiscordTaskMutation(); - - const onSubmit = async () => { - setLoading(true); - await new Promise((resolve) => setTimeout(resolve, 3000)); - dispatch( - updateContributionById({ - id: contribution.id, - data: { - ...contribution, - status: TaskStatus.Submitted - } - }) - ); - setLoading(false); - setOpenSubmitSuccess(true); - // await getAuth( - // async (data) => { - // const { access_token } = data; - // submitJoinDiscordTask({ - // userAddress, - // task, - // bearerToken: access_token, - // onboardingPluginAddress: searchParams.get( - // RequiredQueryParams.OnboardingQuestAddress - // ) - // }); - // }, - // () => { - // setJoinClicked(false); - // } - // ); - }; - - // useEffect(() => { - // if (isSuccess) { - // setOpenSubmitSuccess(true); - // } - // }, [isSuccess]); - - return ( - - {/* reset()} open={isError} message={error} /> - */} - {/* - { - setOpenSubmitSuccess(false); - navigate({ - pathname: "/quest", - search: searchParams.toString() - }); - }} - > */} - - { - if (!loading) { - setOpenSubmitSuccess(false); - navigate({ - pathname: `/${autAddress}/hub/${hubAddress}`, - search: searchParams.toString() - }); - } - }} - > - - {contribution ? ( - <> - - - - {joinClicked && ( - onSubmit()} - > - - Confirm - - - )} - {!joinClicked && ( - { - setJoinClicked(true); - window.open( - contribution.metadata.properties["inviteUrl"], - "_blank" - ); - }} - > - - Join - - - )} - {/* */} - - {(contribution?.status === TaskStatus.Created || - contribution?.status === TaskStatus.Taken) && ( - - {" "} - - - Confirm - - - - )} - - - ) : ( - - )} - - ); -}; - -export default memo(JoinDiscordTask); diff --git a/src/pages/Tasks/DiscordTask/JoinDiscordTask.tsx b/src/pages/Tasks/DiscordTask/JoinDiscordTask.tsx new file mode 100644 index 0000000..216c435 --- /dev/null +++ b/src/pages/Tasks/DiscordTask/JoinDiscordTask.tsx @@ -0,0 +1,257 @@ +import { memo, useState } from "react"; +import { Card, CardContent, Container, Stack, Typography } from "@mui/material"; +import { useSearchParams, useParams, useNavigate } from "react-router-dom"; +import { TaskStatus } from "@store/model"; +import { AutOsButton } from "@components/AutButton"; +import TaskDetails from "../Shared/TaskDetails"; +import SubmitDialog from "@components/Dialog/SubmitDialog"; +import AutLoading from "@components/AutLoading"; +import { useOAuthSocials } from "@components/OAuth"; +import { useWalletConnector } from "@aut-labs/connector"; +import { ContributionCommit } from "@utils/hooks/useQueryContributionCommits"; +import { useCommitAnyContributionMutation } from "@api/contributions.api"; +import ErrorDialog from "@components/Dialog/ErrorPopup"; +import { JoinDiscordContribution } from "@api/models/contribution-types/join-discord.model"; + +const DiscordJoinContent = ({ + contribution, + commit +}: { + contribution: JoinDiscordContribution; + commit: ContributionCommit; +}) => { + const { state } = useWalletConnector(); + const [searchParams] = useSearchParams(); + const navigate = useNavigate(); + const { autAddress, hubAddress } = useParams(); + const { getAuthDiscord } = useOAuthSocials(); + + const [commitContribution, { error, isError, isSuccess, isLoading, reset }] = + useCommitAnyContributionMutation(); + + const contributionSubmitContent = (() => { + let userSubmit = null; + try { + userSubmit = JSON.parse(commit?.data || "{}"); + } catch (e) { + // pass + } + return userSubmit; + })(); + + const handleSubmit = async () => { + await getAuthDiscord( + async (data) => { + const { access_token } = data; + + const discordMessage = { + accessToken: access_token, + guildId: contribution?.properties?.guildId + }; + + commitContribution({ + autSig: state.authSig, + contribution, + message: JSON.stringify(discordMessage), + hubAddress + }); + }, + () => { + // Handle auth failure + } + ); + }; + + return ( + + reset()} + open={isError} + message={(error as { message: string })?.message || "An error occurred"} + /> + + { + if (!isLoading) { + reset(); + navigate({ + pathname: `/${autAddress}/hub/${hubAddress}`, + search: searchParams.toString() + }); + } + }} + /> + + {!commit ? ( + + + + {contribution?.description} + + + + Please join the Discord server and authenticate to verify your + contribution + + + + + window.open( + contribution?.properties?.inviteUrl, + "_blank" + ) + } + sx={{ + width: "160px" + }} + > + + Join Discord + + + + + + Submit + + + + + + ) : ( + + + + + {contribution?.description} + + + Successfully joined Discord server + + + Discord Join Contribution + + + + + )} + + ); +}; + +const JoinDiscordTask = ({ + contribution, + commit +}: { + contribution: JoinDiscordContribution; + commit: ContributionCommit; +}) => { + return ( + + {contribution ? ( + <> + + + + ) : ( + + )} + + ); +}; + +export default memo(JoinDiscordTask); From 07467266a62a689937079e6219c14b5de81fdcb0 Mon Sep 17 00:00:00 2001 From: eulaliee <52575560+eulaliee@users.noreply.github.com> Date: Fri, 29 Nov 2024 19:28:57 +0200 Subject: [PATCH 08/10] contribition commit views --- .../AutID/AutHub/AutHubContributionsTable.tsx | 2 +- .../Tasks/DiscordTask/JoinDiscordTask.tsx | 18 +++++--- .../Tasks/GithubTask/GithubCommitTask.tsx | 17 +++++--- src/pages/Tasks/GithubTask/GithubPRTask.tsx | 19 +++++--- src/pages/Tasks/OpenTask/OpenTask.tsx | 11 +++-- src/pages/Tasks/TwitterTask/TwitterTask.tsx | 43 +++++++++++++------ 6 files changed, 72 insertions(+), 38 deletions(-) diff --git a/src/pages/AutID/AutHub/AutHubContributionsTable.tsx b/src/pages/AutID/AutHub/AutHubContributionsTable.tsx index 6307184..8cbdbb2 100644 --- a/src/pages/AutID/AutHub/AutHubContributionsTable.tsx +++ b/src/pages/AutID/AutHub/AutHubContributionsTable.tsx @@ -332,7 +332,7 @@ export const AutHubTasksTable = ({ header }) => { End Date - + - + - {contribution?.description} + {contributionSubmitContent?.discordServer} + + Discord Server + + + - Successfully joined Discord server + {contributionSubmitContent?.authenticatedUser} - Discord Join Contribution + Authenticated User diff --git a/src/pages/Tasks/GithubTask/GithubCommitTask.tsx b/src/pages/Tasks/GithubTask/GithubCommitTask.tsx index 81afe66..6912730 100644 --- a/src/pages/Tasks/GithubTask/GithubCommitTask.tsx +++ b/src/pages/Tasks/GithubTask/GithubCommitTask.tsx @@ -162,8 +162,9 @@ const GithubCommitContent = ({ ) : ( - {contribution?.description} + {contributionSubmitContent?.repo} + + Repository + + + - Contribution submitted to repository:{" "} - {contributionSubmitContent?.repo} + {contributionSubmitContent?.authenticatedUser} - Github Commit Contribution + Authenticated User diff --git a/src/pages/Tasks/GithubTask/GithubPRTask.tsx b/src/pages/Tasks/GithubTask/GithubPRTask.tsx index 0dfc812..22a9de1 100644 --- a/src/pages/Tasks/GithubTask/GithubPRTask.tsx +++ b/src/pages/Tasks/GithubTask/GithubPRTask.tsx @@ -37,7 +37,7 @@ const GithubPRContent = ({ useCommitAnyContributionMutation(); if (error || isError) { - debugger; + // debugger; } const contributionSubmitContent = (() => { @@ -173,8 +173,9 @@ const GithubPRContent = ({ ) : ( - {contribution?.description} + {contributionSubmitContent?.repo} + + Repository + + + - Pull Request submitted to repository:{" "} - {contributionSubmitContent?.repo} + {contributionSubmitContent?.authenticatedUser} - Github Pull Request Contribution + Authenticated User diff --git a/src/pages/Tasks/OpenTask/OpenTask.tsx b/src/pages/Tasks/OpenTask/OpenTask.tsx index c5ab7e8..8b1770d 100644 --- a/src/pages/Tasks/OpenTask/OpenTask.tsx +++ b/src/pages/Tasks/OpenTask/OpenTask.tsx @@ -81,6 +81,8 @@ const UserSubmitContent = ({ } }, [initialized, contributionSubmitContent]); + console.log(contributionSubmitContent, 'contributionSubmitContent'); + const [commitContribution, { error, isError, isSuccess, isLoading, reset }] = useCommitAnyContributionMutation(); @@ -315,7 +317,7 @@ const UserSubmitContent = ({ {contributionSubmitContent?.description} - Contribution Description + Description @@ -335,9 +337,10 @@ const UserSubmitContent = ({ }} variant="subtitle2" target="_blank" - href={ipfsCIDToHttpUrl( - contributionSubmitContent?.attachment - )} + //TODO: To uncomment when attachment ipfs url is correctly added to the metadata + // href={ipfsCIDToHttpUrl( + // contributionSubmitContent?.attachment + // )} > Open attachment diff --git a/src/pages/Tasks/TwitterTask/TwitterTask.tsx b/src/pages/Tasks/TwitterTask/TwitterTask.tsx index 90cd500..05b89ba 100644 --- a/src/pages/Tasks/TwitterTask/TwitterTask.tsx +++ b/src/pages/Tasks/TwitterTask/TwitterTask.tsx @@ -46,6 +46,8 @@ const TwitterSubmitContent = ({ return userSubmit; })(); + console.log(contributionSubmitContent); + const handleSubmit = async () => { await getAuthX( async (data) => { @@ -131,14 +133,14 @@ const TwitterSubmitContent = ({ padding: "32px" }} > - {contribution?.description} - + */} @@ -158,11 +160,11 @@ const TwitterSubmitContent = ({ - Please authenticate with Twitter to verify your contribution + Please authenticate with Twitter to verify your contribution. - - {contribution?.description} + + {contribution.properties?.tweetUrl} + + + + Tweet Url + + - Tweet URL: {contributionSubmitContent?.tweetUrl} + {contributionSubmitContent?.authenticatedUser} - Twitter Retweet Contribution + Authenticated User From 374f69bee1136c726790ff5f817f022a7bb7f7f9 Mon Sep 17 00:00:00 2001 From: mrtmeeseeks Date: Mon, 2 Dec 2024 14:43:28 +0200 Subject: [PATCH 09/10] added query period metadata for members --- package-lock.json | 27 +++--- package.json | 6 +- .../AutID/AutHub/AutHubContributionsTable.tsx | 3 +- src/pages/AutID/AutHub/AutHubList.tsx | 4 + src/utils/hooks/GetContributions.tsx | 27 +++--- src/utils/hooks/useQueryHubPeriod.tsx | 86 +++++++++++++++++++ 6 files changed, 120 insertions(+), 33 deletions(-) create mode 100644 src/utils/hooks/useQueryHubPeriod.tsx diff --git a/package-lock.json b/package-lock.json index 520fa4d..2341009 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,10 +9,10 @@ "version": "0.1.0", "dependencies": { "@apollo/client": "^3.11.5", - "@aut-labs/abi-types": "^0.0.86-dev", - "@aut-labs/connector": "^0.0.203", + "@aut-labs/abi-types": "^0.0.87-dev", + "@aut-labs/connector": "^0.0.205", "@aut-labs/d-aut": "^1.0.204-dev", - "@aut-labs/sdk": "^0.0.223-dev", + "@aut-labs/sdk": "^0.0.228-dev", "@emotion/react": "^11.11.3", "@emotion/styled": "^11.11.0", "@marker.io/browser": "^0.19.0", @@ -137,14 +137,15 @@ } }, "node_modules/@aut-labs/abi-types": { - "version": "0.0.86-dev", - "resolved": "https://registry.npmjs.org/@aut-labs/abi-types/-/abi-types-0.0.86-dev.tgz", - "integrity": "sha512-I9VNsYN8smW516wPQeDWhJaw4OWiIc7WxRBIn2GkqKw4oYKaLbDRzTV2XXVrMlvVCo7V82V51SlV+fC0Hajq/w==" + "version": "0.0.87-dev", + "resolved": "https://registry.npmjs.org/@aut-labs/abi-types/-/abi-types-0.0.87-dev.tgz", + "integrity": "sha512-PDmfNSdzbQGcLiWuA7N4/ULLi3EFHvVyk3bAy55yHb24DLiq8wNWCmtngpWZK2u5/tjJ+X36pT7kGrtHS89Axg==", + "license": "ISC" }, "node_modules/@aut-labs/connector": { - "version": "0.0.203", - "resolved": "https://registry.npmjs.org/@aut-labs/connector/-/connector-0.0.203.tgz", - "integrity": "sha512-bUXlRb1YviVb6jpnTLnZs3HaZhABItep+knkbCsrKAAZcPH0bcsnJsjCfLOH2PsZX+BcTafxUrT2FDmy92aeZw==", + "version": "0.0.205", + "resolved": "https://registry.npmjs.org/@aut-labs/connector/-/connector-0.0.205.tgz", + "integrity": "sha512-TcbRTjHst2mM9SxZRRo0uKoY/dJ5xBuXpeDC8fc9R419nJxLm5cLLAleoNdXMrrSvSHjk7jJ27WEj3VpHGDqmA==", "license": "MIT", "dependencies": { "@web3auth/base": "^8.0.0", @@ -171,12 +172,12 @@ "integrity": "sha512-sDEu6yyvqu/KjqobI6nBoovrHWwhA4DoXPWObQLcGRs1Isuxg/d2HhP2/9k6Xz5zjFDo/w3MDI3XDvpVos20dg==" }, "node_modules/@aut-labs/sdk": { - "version": "0.0.223-dev", - "resolved": "https://registry.npmjs.org/@aut-labs/sdk/-/sdk-0.0.223-dev.tgz", - "integrity": "sha512-Fsainkcjj0dJdlqriiLbJh6F/BjggRMqJJvzMjRZHJ94m5MLTHwrFpXlDwbmBVdq9OLeYZOFlua4/A9kWgNIeA==", + "version": "0.0.228-dev", + "resolved": "https://registry.npmjs.org/@aut-labs/sdk/-/sdk-0.0.228-dev.tgz", + "integrity": "sha512-PpgmuX07NHyXO1fMtdLcRV8VUc3Ve2r2+jk9H+c5WuidSu6+pkJXj/y6cQhUhSbb3/pKO8YlKS39qB3+ScRiWA==", "license": "MIT", "dependencies": { - "@aut-labs/abi-types": "^0.0.86-dev", + "@aut-labs/abi-types": "^0.0.87-dev", "date-fns": "^2.29.3", "ethers": "^6.10.0" } diff --git a/package.json b/package.json index f14314a..cdf9471 100644 --- a/package.json +++ b/package.json @@ -29,10 +29,10 @@ }, "dependencies": { "@apollo/client": "^3.11.5", - "@aut-labs/abi-types": "^0.0.86-dev", - "@aut-labs/connector": "^0.0.203", + "@aut-labs/abi-types": "^0.0.87-dev", + "@aut-labs/connector": "^0.0.205", "@aut-labs/d-aut": "^1.0.204-dev", - "@aut-labs/sdk": "^0.0.223-dev", + "@aut-labs/sdk": "^0.0.228-dev", "@emotion/react": "^11.11.3", "@emotion/styled": "^11.11.0", "@marker.io/browser": "^0.19.0", diff --git a/src/pages/AutID/AutHub/AutHubContributionsTable.tsx b/src/pages/AutID/AutHub/AutHubContributionsTable.tsx index 8cbdbb2..7607ff4 100644 --- a/src/pages/AutID/AutHub/AutHubContributionsTable.tsx +++ b/src/pages/AutID/AutHub/AutHubContributionsTable.tsx @@ -28,6 +28,7 @@ import useQueryContributionCommits, { import { TaskContributionNFT } from "@aut-labs/sdk"; import { Link } from "react-router-dom"; import { GithubCommitContribution } from "@api/models/contribution-types/github-commit.model"; +import useQueryHubPeriod from "@utils/hooks/useQueryHubPeriod"; const StyledTableCell = styled(TableCell)(({ theme }) => ({ [`&.${tableCellClasses.head}, &.${tableCellClasses.body}`]: { @@ -238,7 +239,7 @@ export const AutHubTasksTable = ({ header }) => { if (data?.length) { data.map((contribution) => { console.log(contribution as GithubCommitContribution); - }) + }); } const [ commit, diff --git a/src/pages/AutID/AutHub/AutHubList.tsx b/src/pages/AutID/AutHub/AutHubList.tsx index 11b961e..294a803 100644 --- a/src/pages/AutID/AutHub/AutHubList.tsx +++ b/src/pages/AutID/AutHub/AutHubList.tsx @@ -26,6 +26,7 @@ import { useSelector } from "react-redux"; import { EditContentElements } from "@components/EditContentElements"; import { socialsWithIcons } from "@utils/social-icons"; import { SocialUrls } from "@aut-labs/sdk"; +import useQueryHubPeriod from "@utils/hooks/useQueryHubPeriod"; export const HubTopWrapper = styled(Box)(({ theme }) => ({ display: "flex", @@ -336,6 +337,9 @@ interface TableParamsParams { const AutHubList = ({ isLoading = false, hubs = [] }: TableParamsParams) => { const theme = useTheme(); + const { data: periodData } = useQueryHubPeriod(); + console.log(periodData, "periodData"); + return ( { - return contributions - .filter((contribution) => contribution?.descriptionId) - .map(async (contribution) => { - const { uri } = await taskFactory.functions.getDescriptionById( - contribution?.descriptionId - ); - let metadata = await fetchMetadata>( - uri, - environment.ipfsGatewayUrl - ); - metadata = metadata || ({ properties: {} } as BaseNFTModel); - return ContributionFactory(metadata, contribution, taskTypes); - }); + return contributions.map(async (contribution) => { + let metadata = await fetchMetadata>( + contribution.uri, + environment.ipfsGatewayUrl + ); + metadata = metadata || ({ properties: {} } as BaseNFTModel); + return ContributionFactory(metadata, contribution, taskTypes); + }); }; const useQueryContributions = (props: QueryFunctionOptions = {}) => { @@ -64,7 +59,7 @@ const useQueryContributions = (props: QueryFunctionOptions = {}) => { return selectedHubAddress || _hubAddress; }, [_hubAddress, selectedHubAddress]); const { data, loading, ...rest } = useQuery(GET_HUB_CONTRIBUTIONS, { - skip: !hubAddress && !taskTypes.length, + skip: !hubAddress && !taskTypes.length, fetchPolicy: "cache-and-network", variables: { ...props.variables, @@ -72,7 +67,7 @@ const useQueryContributions = (props: QueryFunctionOptions = {}) => { hubAddress: hubAddress, ...(props.variables?.where || {}) } - }, + } // ...props }); diff --git a/src/utils/hooks/useQueryHubPeriod.tsx b/src/utils/hooks/useQueryHubPeriod.tsx new file mode 100644 index 0000000..fb05339 --- /dev/null +++ b/src/utils/hooks/useQueryHubPeriod.tsx @@ -0,0 +1,86 @@ +import { useQuery } from "@tanstack/react-query"; +import { useSelector } from "react-redux"; +import AutSDK, { Hub } from "@aut-labs/sdk"; +import { SelectedAutID, SelectedHubAddress } from "@store/aut/aut.reducer"; +import { useParams } from "react-router-dom"; +import { useMemo } from "react"; +import { useWalletConnector } from "@aut-labs/connector"; +import { AutOSAutID } from "@api/models/aut.model"; + +export interface HubPeriodData { + hub: string; + who: string; + periodId: number; + startDate: Date; + endDate: Date; + pointsGiven: number; + score: number; + performance: number; + expectedPoints: number; +} + +const fetchHubPeriodData = async ( + hubAddress: string, + who: string, + autID: AutOSAutID +): Promise => { + const sdk = await AutSDK.getInstance(); + const hubService: Hub = sdk.initService(Hub, hubAddress); + const taskManager = await hubService.getTaskManager(); + const participationScore = await hubService.getParticipationScoreFactory(); + const periodId = await taskManager.functions.currentPeriodId(); + const selectedHub = autID.joinedHub(hubAddress); + + const [startDate, endDate, pointsGiven, participation, expectedPoints] = + await Promise.all([ + taskManager.functions.currentPeriodStart(), + taskManager.functions.currentPeriodEnd(), + taskManager.functions.getMemberPointsGiven(who, Number(periodId)), + participationScore.functions.memberParticipations(who, Number(periodId)), // {score: number; performance: number} + participationScore.functions.calcExpectedPoints( + +selectedHub.commitment, + Number(periodId) + ) + ]); + + return { + hub: hubAddress, + who, + periodId: Number(periodId), + startDate: new Date(Number(startDate) * 1000), + endDate: new Date(Number(endDate) * 1000), + pointsGiven: Number(pointsGiven), + score: Number(participation.score), + performance: Number(participation.performance), + expectedPoints: Number(expectedPoints) + }; +}; + +const useQueryHubPeriod = () => { + const selectedHubAddress = useSelector(SelectedHubAddress); + const autID = useSelector(SelectedAutID); + const { state } = useWalletConnector(); + const { hubAddress: _hubAddress } = useParams<{ hubAddress: string }>(); + + const hubAddress = useMemo(() => { + return selectedHubAddress || _hubAddress; + }, [_hubAddress, selectedHubAddress]); + + const { + data: periodData, + isLoading: loadingMetadata, + error + } = useQuery({ + queryKey: ["hubPeriodData", hubAddress], + queryFn: () => fetchHubPeriodData(hubAddress, state.address, autID), + enabled: !!hubAddress && !!state?.address + }); + + return { + data: periodData, + loading: loadingMetadata, + error + }; +}; + +export default useQueryHubPeriod; From 5656e3634199e0d4fbd9d94387f038aa0914fcd0 Mon Sep 17 00:00:00 2001 From: eulaliee <52575560+eulaliee@users.noreply.github.com> Date: Tue, 3 Dec 2024 01:15:27 +0200 Subject: [PATCH 10/10] period data implementation --- src/pages/AutID/AutHub/AutHubEdit.tsx | 33 +++++++++++-------- src/pages/AutID/AutHub/AutHubList.tsx | 15 +++++---- .../Tasks/DiscordTask/JoinDiscordTask.tsx | 6 ++-- .../Tasks/GithubTask/GithubCommitTask.tsx | 6 ++-- src/pages/Tasks/GithubTask/GithubPRTask.tsx | 6 ++-- src/pages/Tasks/OpenTask/OpenTask.tsx | 14 ++++---- src/pages/Tasks/TwitterTask/TwitterTask.tsx | 6 ++-- 7 files changed, 46 insertions(+), 40 deletions(-) diff --git a/src/pages/AutID/AutHub/AutHubEdit.tsx b/src/pages/AutID/AutHub/AutHubEdit.tsx index bd63569..1d01281 100644 --- a/src/pages/AutID/AutHub/AutHubEdit.tsx +++ b/src/pages/AutID/AutHub/AutHubEdit.tsx @@ -56,6 +56,7 @@ import { PropertiesWrapper } from "./AutHubList"; import { SocialUrls } from "@aut-labs/sdk"; +import useQueryHubPeriod from "@utils/hooks/useQueryHubPeriod"; const LeftWrapper = styled(Box)(({ theme }) => ({ display: "flex", @@ -136,6 +137,11 @@ const AutHubEdit = () => { const roleName = useSelector(RoleName(params.hubAddress)); const commitmentTemplate = useSelector(CommitmentTemplate(hubAddress)); + const { data: periodData } = useQueryHubPeriod(); + + const { pointsGiven, expectedPoints, endDate } = periodData || {}; + const initialScore = 100; + useEffect(() => { dispatch(updateAutState({ selectedHubAddress: params.hubAddress })); console.log( @@ -230,10 +236,6 @@ const AutHubEdit = () => { dispatch(setOpenCommitment(true)); }; - const nextPeriod = new Date("11/30/2024"); - const hubRep: number = 100; - const userRep: number = 100; - const socials = useMemo(() => { if (!selectedHub) return []; return socialsWithIcons(selectedHub?.properties?.socials); @@ -615,7 +617,7 @@ const AutHubEdit = () => { > Current Period Contribution - {userRep < hubRep ? ( + {pointsGiven < expectedPoints ? ( { period ends in @@ -684,7 +686,7 @@ const AutHubEdit = () => { lineHeight="48px" color="offWhite.main" > - {userRep} + {pointsGiven} { }} color="offWhite.dark" > - {hubRep} + {expectedPoints} - {userRep < hubRep && ( + {pointsGiven < expectedPoints && ( { } }} variant="determinate" - value={(userRep / hubRep) * 100} + value={ + (pointsGiven / (expectedPoints || 1)) * 100 + } /> { )} - {userRep === hubRep && ( + {pointsGiven === + expectedPoints && ( { )} - {userRep > hubRep && ( + {pointsGiven > expectedPoints && ( { color="offWhite.main" fontWeight="normal" > - 1.0 + {initialScore} { color="offWhite.main" fontWeight="normal" > - 100 + {pointsGiven} ({ const { IconContainer } = EditContentElements; const HubListItem = memo(({ row }: { row: AutOSHub }) => { + const { data: periodData } = useQueryHubPeriod(); + const initialScore = 100; const theme = useTheme(); const { address } = useAccount(); const autID = useSelector(SelectedAutID); @@ -274,7 +276,8 @@ const HubListItem = memo(({ row }: { row: AutOSHub }) => { } > - { xs: "inherit", md: "transparent" } - }}> + }} + > - 1.0 + {initialScore} { color="offWhite.main" fontWeight="normal" > - 100 + {periodData?.pointsGiven || 0} { const theme = useTheme(); - const { data: periodData } = useQueryHubPeriod(); - console.log(periodData, "periodData"); - return ( { + const contributionSubmissionContent = (() => { let userSubmit = null; try { userSubmit = JSON.parse(commit?.data || "{}"); @@ -203,7 +203,7 @@ const DiscordJoinContent = ({ textAlign="center" p="5px" > - {contributionSubmitContent?.discordServer} + {contributionSubmissionContent?.discordServer} Discord Server @@ -216,7 +216,7 @@ const DiscordJoinContent = ({ textAlign="center" p="5px" > - {contributionSubmitContent?.authenticatedUser} + {contributionSubmissionContent?.authenticatedUser} Authenticated User diff --git a/src/pages/Tasks/GithubTask/GithubCommitTask.tsx b/src/pages/Tasks/GithubTask/GithubCommitTask.tsx index 6912730..865a48e 100644 --- a/src/pages/Tasks/GithubTask/GithubCommitTask.tsx +++ b/src/pages/Tasks/GithubTask/GithubCommitTask.tsx @@ -29,7 +29,7 @@ const GithubCommitContent = ({ const [commitContribution, { error, isError, isSuccess, isLoading, reset }] = useCommitAnyContributionMutation(); - const contributionSubmitContent = (() => { + const contributionSubmissionContent = (() => { let userSubmit = null; try { userSubmit = JSON.parse(commit?.data || "{}"); @@ -183,7 +183,7 @@ const GithubCommitContent = ({ textAlign="center" p="5px" > - {contributionSubmitContent?.repo} + {contributionSubmissionContent?.repo} Repository @@ -196,7 +196,7 @@ const GithubCommitContent = ({ textAlign="center" p="5px" > - {contributionSubmitContent?.authenticatedUser} + {contributionSubmissionContent?.authenticatedUser} Authenticated User diff --git a/src/pages/Tasks/GithubTask/GithubPRTask.tsx b/src/pages/Tasks/GithubTask/GithubPRTask.tsx index 22a9de1..19111d3 100644 --- a/src/pages/Tasks/GithubTask/GithubPRTask.tsx +++ b/src/pages/Tasks/GithubTask/GithubPRTask.tsx @@ -40,7 +40,7 @@ const GithubPRContent = ({ // debugger; } - const contributionSubmitContent = (() => { + const contributionSubmissionContent = (() => { let userSubmit = null; try { userSubmit = JSON.parse(commit?.data || "{}"); @@ -194,7 +194,7 @@ const GithubPRContent = ({ textAlign="center" p="5px" > - {contributionSubmitContent?.repo} + {contributionSubmissionContent?.repo} Repository @@ -207,7 +207,7 @@ const GithubPRContent = ({ textAlign="center" p="5px" > - {contributionSubmitContent?.authenticatedUser} + {contributionSubmissionContent?.authenticatedUser} Authenticated User diff --git a/src/pages/Tasks/OpenTask/OpenTask.tsx b/src/pages/Tasks/OpenTask/OpenTask.tsx index 8b1770d..9ea75fd 100644 --- a/src/pages/Tasks/OpenTask/OpenTask.tsx +++ b/src/pages/Tasks/OpenTask/OpenTask.tsx @@ -52,7 +52,7 @@ const UserSubmitContent = ({ const { autAddress, hubAddress } = useParams(); - const contributionSubmitContent = useMemo(() => { + const contributionSubmissionContent = useMemo(() => { let userSubmit = null; try { userSubmit = JSON.parse(commit.data); @@ -62,10 +62,10 @@ const UserSubmitContent = ({ return userSubmit; }, [commit]); - console.log(contributionSubmitContent, 'contributionSubmitContent'); + console.log(contributionSubmissionContent, 'contributionSubmissionContent'); useEffect(() => { - if (!initialized && contributionSubmitContent) { + if (!initialized && contributionSubmissionContent) { let userSubmit = { description: "", attachment: "" @@ -79,9 +79,9 @@ const UserSubmitContent = ({ setValue("attachment", userSubmit.attachment); setInitialized(true); } - }, [initialized, contributionSubmitContent]); + }, [initialized, contributionSubmissionContent]); - console.log(contributionSubmitContent, 'contributionSubmitContent'); + console.log(contributionSubmissionContent, 'contributionSubmissionContent'); const [commitContribution, { error, isError, isSuccess, isLoading, reset }] = useCommitAnyContributionMutation(); @@ -314,7 +314,7 @@ const UserSubmitContent = ({ textAlign="center" p="5px" > - {contributionSubmitContent?.description} + {contributionSubmissionContent?.description} Description @@ -339,7 +339,7 @@ const UserSubmitContent = ({ target="_blank" //TODO: To uncomment when attachment ipfs url is correctly added to the metadata // href={ipfsCIDToHttpUrl( - // contributionSubmitContent?.attachment + // contributionSubmissionContent?.attachment // )} > Open attachment diff --git a/src/pages/Tasks/TwitterTask/TwitterTask.tsx b/src/pages/Tasks/TwitterTask/TwitterTask.tsx index 05b89ba..7c5c271 100644 --- a/src/pages/Tasks/TwitterTask/TwitterTask.tsx +++ b/src/pages/Tasks/TwitterTask/TwitterTask.tsx @@ -36,7 +36,7 @@ const TwitterSubmitContent = ({ const [commitContribution, { error, isError, isSuccess, isLoading, reset }] = useCommitAnyContributionMutation(); - const contributionSubmitContent = (() => { + const contributionSubmissionContent = (() => { let userSubmit = null; try { userSubmit = JSON.parse(commit?.data || "{}"); @@ -46,7 +46,7 @@ const TwitterSubmitContent = ({ return userSubmit; })(); - console.log(contributionSubmitContent); + console.log(contributionSubmissionContent); const handleSubmit = async () => { await getAuthX( @@ -226,7 +226,7 @@ const TwitterSubmitContent = ({ textAlign="center" p="5px" > - {contributionSubmitContent?.authenticatedUser} + {contributionSubmissionContent?.authenticatedUser} Authenticated User